[flang] Checks for constraints C731 through C740
In most cases, I just added the contraint names to the code and tests.
I implemented the following checks:
- C736 A child type with a coarray ultimate component must have a parent with
a coarray ultimate component.
- C737 A child type with and EVENT_TYPE or LOCK_TYPE component must have a
parent either which is EVENT_TYPE or LOCK_TYPE or a type with an EVENT_TYPE
or LOCK_TYPE component.
- C740 Sequence types must contain at least on component
- C740 Data components of sequence types must either be of an intrinsic type
or a sequenced derived type.
After implementing these checks, some tests had new errors unrelated to their
original purpose, so I fixed them.
Original-commit: flang-compiler/f18@098f01bc474798ae03bd4dc7de6c929deec6f244
Reviewed-on: https://github.com/flang-compiler/f18/pull/1097
diff --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h
index b55cf50..38b884e 100644
--- a/flang/include/flang/Semantics/scope.h
+++ b/flang/include/flang/Semantics/scope.h
@@ -91,6 +91,7 @@
const Symbol *GetSymbol() const;
const Scope *GetDerivedTypeParent() const;
+ const Scope &GetDerivedTypeBase() const;
std::optional<SourceName> GetName() const;
bool Contains(const Scope &) const;
/// Make a scope nested in this one
diff --git a/flang/include/flang/Semantics/type.h b/flang/include/flang/Semantics/type.h
index 00f38e2..cc20318 100644
--- a/flang/include/flang/Semantics/type.h
+++ b/flang/include/flang/Semantics/type.h
@@ -336,6 +336,7 @@
}
bool IsAssumedType() const { return category_ == TypeStar; }
bool IsNumeric(TypeCategory) const;
+ bool IsSequenceType() const;
const NumericTypeSpec &numericTypeSpec() const;
const LogicalTypeSpec &logicalTypeSpec() const;
const CharacterTypeSpec &characterTypeSpec() const {
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 15dd782..da02b4f 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -679,13 +679,14 @@
void CheckHelper::CheckDerivedType(
const Symbol &symbol, const DerivedTypeDetails &details) {
- if (!symbol.scope()) {
+ const Scope *scope{symbol.scope()};
+ if (!scope) {
CHECK(details.isForwardReferenced());
return;
}
- CHECK(symbol.scope()->symbol() == &symbol);
- CHECK(symbol.scope()->IsDerivedType());
- if (symbol.attrs().test(Attr::ABSTRACT) &&
+ CHECK(scope->symbol() == &symbol);
+ CHECK(scope->IsDerivedType());
+ if (symbol.attrs().test(Attr::ABSTRACT) && // C734
(symbol.attrs().test(Attr::BIND_C) || details.sequence())) {
messages_.Say("An ABSTRACT derived type must be extensible"_err_en_US);
}
@@ -699,7 +700,7 @@
ScopeComponentIterator components{*parentDerived};
for (const Symbol &component : components) {
if (component.attrs().test(Attr::DEFERRED)) {
- if (symbol.scope()->FindComponent(component.name()) == &component) {
+ if (scope->FindComponent(component.name()) == &component) {
SayWithDeclaration(component,
"Non-ABSTRACT extension of ABSTRACT derived type '%s' lacks a binding for DEFERRED procedure '%s'"_err_en_US,
parentDerived->typeSymbol().name(), component.name());
@@ -707,6 +708,26 @@
}
}
}
+ DerivedTypeSpec derived{symbol.name(), symbol};
+ derived.set_scope(*scope);
+ if (FindCoarrayUltimateComponent(derived) && // C736
+ !(parentDerived && FindCoarrayUltimateComponent(*parentDerived))) {
+ messages_.Say(
+ "Type '%s' has a coarray ultimate component so the type at the base "
+ "of its type extension chain ('%s') must be a type that has a "
+ "coarray ultimate component"_err_en_US,
+ symbol.name(), scope->GetDerivedTypeBase().GetSymbol()->name());
+ }
+ if (FindEventOrLockPotentialComponent(derived) && // C737
+ !(FindEventOrLockPotentialComponent(*parentDerived) ||
+ IsEventTypeOrLockType(parentDerived))) {
+ messages_.Say(
+ "Type '%s' has an EVENT_TYPE or LOCK_TYPE component, so the type "
+ "at the base of its type extension chain ('%s') must either have an "
+ "EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or "
+ "LOCK_TYPE"_err_en_US,
+ symbol.name(), scope->GetDerivedTypeBase().GetSymbol()->name());
+ }
}
if (HasIntrinsicTypeName(symbol)) { // C729
messages_.Say("A derived type name cannot be the name of an intrinsic"
@@ -1141,7 +1162,7 @@
CHECK(dtScope.kind() == Scope::Kind::DerivedType);
if (const Symbol * dtSymbol{dtScope.symbol()}) {
if (symbol.attrs().test(Attr::DEFERRED)) {
- if (!dtSymbol->attrs().test(Attr::ABSTRACT)) {
+ if (!dtSymbol->attrs().test(Attr::ABSTRACT)) { // C733
SayWithDeclaration(*dtSymbol,
"Procedure bound to non-ABSTRACT derived type '%s' may not be DEFERRED"_err_en_US,
dtSymbol->name());
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 805a9c7..ee2db03 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -3682,18 +3682,40 @@
}
}
Walk(std::get<std::list<parser::Statement<parser::PrivateOrSequence>>>(x.t));
+ const auto &componentDefs{
+ std::get<std::list<parser::Statement<parser::ComponentDefStmt>>>(x.t)};
+ Walk(componentDefs);
if (derivedTypeInfo_.sequence) {
details.set_sequence(true);
- if (derivedTypeInfo_.extends) {
+ if (componentDefs.empty()) { // C740
Say(stmt.source,
- "A sequence type may not have the EXTENDS attribute"_err_en_US); // C735
+ "A sequence type must have at least one component"_err_en_US);
}
- if (!details.paramNames().empty()) {
+ if (!details.paramNames().empty()) { // C740
Say(stmt.source,
- "A sequence type may not have type parameters"_err_en_US); // C740
+ "A sequence type may not have type parameters"_err_en_US);
+ }
+ if (derivedTypeInfo_.extends) { // C735
+ Say(stmt.source,
+ "A sequence type may not have the EXTENDS attribute"_err_en_US);
+ } else {
+ for (const auto &componentName : details.componentNames()) {
+ const Symbol *componentSymbol{scope.FindComponent(componentName)};
+ if (componentSymbol && componentSymbol->has<ObjectEntityDetails>()) {
+ const auto &componentDetails{
+ componentSymbol->get<ObjectEntityDetails>()};
+ const DeclTypeSpec *componentType{componentDetails.type()};
+ if (componentType && // C740
+ !componentType->AsIntrinsic() &&
+ !componentType->IsSequenceType()) {
+ Say(componentSymbol->name(),
+ "A sequence type data component must either be of an"
+ " intrinsic type or a derived sequence type"_err_en_US);
+ }
+ }
+ }
}
}
- Walk(std::get<std::list<parser::Statement<parser::ComponentDefStmt>>>(x.t));
Walk(std::get<std::optional<parser::TypeBoundProcedurePart>>(x.t));
Walk(std::get<parser::Statement<parser::EndTypeStmt>>(x.t));
derivedTypeInfo_ = {};
@@ -3783,6 +3805,10 @@
return false;
}
bool DeclarationVisitor::Pre(const parser::SequenceStmt &) {
+ if (derivedTypeInfo_.sequence) {
+ Say("SEQUENCE may not appear more than once in"
+ " derived type components"_en_US); // C738
+ }
derivedTypeInfo_.sequence = true;
return false;
}
@@ -3796,7 +3822,7 @@
if (!attrs.HasAny({Attr::POINTER, Attr::ALLOCATABLE})) {
if (const auto *declType{GetDeclTypeSpec()}) {
if (const auto *derived{declType->AsDerived()}) {
- if (derivedTypeInfo_.type == &derived->typeSymbol()) { // C737
+ if (derivedTypeInfo_.type == &derived->typeSymbol()) { // C744
Say("Recursive use of the derived type requires "
"POINTER or ALLOCATABLE"_err_en_US);
}
@@ -4648,7 +4674,7 @@
DerivedTypeDetails details;
details.set_isForwardReferenced();
symbol->set_details(std::move(details));
- } else { // C883
+ } else { // C732
Say(name, "Derived type '%s' not found"_err_en_US);
return std::nullopt;
}
diff --git a/flang/lib/Semantics/scope.cpp b/flang/lib/Semantics/scope.cpp
index dc934a51..85307c2 100644
--- a/flang/lib/Semantics/scope.cpp
+++ b/flang/lib/Semantics/scope.cpp
@@ -362,6 +362,15 @@
return nullptr;
}
+const Scope &Scope::GetDerivedTypeBase() const {
+ const Scope *child{this};
+ for (const Scope *parent{GetDerivedTypeParent()}; parent != nullptr;
+ parent = child->GetDerivedTypeParent()) {
+ child = parent;
+ }
+ return *child;
+}
+
void Scope::InstantiateDerivedTypes(SemanticsContext &context) {
for (DeclTypeSpec &type : declTypeSpecs_) {
if (type.category() == DeclTypeSpec::TypeDerived ||
diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index 108d04a..f4fc7cb 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -472,6 +472,14 @@
bool DeclTypeSpec::IsNumeric(TypeCategory tc) const {
return category_ == Numeric && numericTypeSpec().category() == tc;
}
+bool DeclTypeSpec::IsSequenceType() const {
+ if (const DerivedTypeSpec * derivedType{AsDerived()}) {
+ const auto *typeDetails{
+ derivedType->typeSymbol().detailsIf<DerivedTypeDetails>()};
+ return typeDetails && typeDetails->sequence();
+ }
+ return false;
+}
IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
return const_cast<IntrinsicTypeSpec *>(
const_cast<const DeclTypeSpec *>(this)->AsIntrinsic());
diff --git a/flang/test/Semantics/assign02.f90 b/flang/test/Semantics/assign02.f90
index c504f7a..91bb845 100644
--- a/flang/test/Semantics/assign02.f90
+++ b/flang/test/Semantics/assign02.f90
@@ -7,6 +7,7 @@
end type
type t2
sequence
+ real :: t2Field
end type
contains
diff --git a/flang/test/Semantics/bad-forward-type.f90 b/flang/test/Semantics/bad-forward-type.f90
index 0c6de01..0fda08f 100644
--- a/flang/test/Semantics/bad-forward-type.f90
+++ b/flang/test/Semantics/bad-forward-type.f90
@@ -1,5 +1,7 @@
! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
! Forward references to derived types (error cases)
+! C732 A parent-type-name shall be the name of a previously defined
+! extensible type (7.5.7).
!ERROR: The derived type 'undef' was forward-referenced but not defined
type(undef) function f1()
diff --git a/flang/test/Semantics/bindings01.f90 b/flang/test/Semantics/bindings01.f90
index 4c517ad..9d15515 100644
--- a/flang/test/Semantics/bindings01.f90
+++ b/flang/test/Semantics/bindings01.f90
@@ -1,6 +1,6 @@
! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
! Confirm enforcement of constraints and restrictions in 7.5.7.3
-! and C779-C785.
+! and C733, C734 and C779, C780, C781, C782, C783, C784, and C785.
module m
!ERROR: An ABSTRACT derived type must be extensible
@@ -9,6 +9,7 @@
!ERROR: An ABSTRACT derived type must be extensible
type, abstract :: badAbstract2
sequence
+ real :: badAbstract2Field
end type
type, abstract :: abstract
contains
@@ -50,6 +51,7 @@
end type
type :: inextensible2
sequence
+ real :: inextensible2Field
end type
!ERROR: The parent type is not extensible
type, extends(inextensible2) :: badExtends2
diff --git a/flang/test/Semantics/label11.f90 b/flang/test/Semantics/label11.f90
index 9243566..71c40cf 100644
--- a/flang/test/Semantics/label11.f90
+++ b/flang/test/Semantics/label11.f90
@@ -11,6 +11,8 @@
! CHECK: derived type definition name mismatch
! CHECK: MODULE PROCEDURE name mismatch
! CHECK: MODULE name mismatch
+! C739 If END TYPE is followed by a type-name, the type-name shall be the
+! same as that in the corresponding derived-type-stmt.
block data t1
end block data t2
diff --git a/flang/test/Semantics/modfile33.f90 b/flang/test/Semantics/modfile33.f90
index d5474c7..361542a 100644
--- a/flang/test/Semantics/modfile33.f90
+++ b/flang/test/Semantics/modfile33.f90
@@ -9,6 +9,7 @@
module m1
type :: t
sequence
+ logical :: x
end type
interface operator(+)
pure integer(8) function add_ll(x, y)
@@ -61,6 +62,7 @@
!module m1
! type :: t
! sequence
+! logical(4) :: x
! end type
! interface operator(+)
! procedure :: add_ll
@@ -136,6 +138,7 @@
module m2
type :: t
sequence
+ logical :: x
end type
interface operator(.And.)
pure integer(8) function and_ti(x, y)
@@ -195,6 +198,7 @@
!module m2
! type :: t
! sequence
+! logical(4) :: x
! end type
! interface operator( .and.)
! procedure :: and_ti
@@ -275,6 +279,7 @@
module m3
type :: t
sequence
+ logical :: x
end type
interface operator(<>)
pure integer(8) function ne_it(x, y)
@@ -317,6 +322,7 @@
!module m3
! type :: t
! sequence
+! logical(4) :: x
! end type
! interface operator(<>)
! procedure :: ne_it
@@ -368,6 +374,7 @@
module m4
type :: t
sequence
+ logical :: x
end type
interface operator(//)
pure integer(8) function concat_12(x, y)
@@ -395,6 +402,7 @@
!module m4
! type :: t
! sequence
+! logical(4) :: x
! end type
! interface operator(//)
! procedure :: concat_12
diff --git a/flang/test/Semantics/resolve31.f90 b/flang/test/Semantics/resolve31.f90
index a1fb7ce..14a7bc9c 100644
--- a/flang/test/Semantics/resolve31.f90
+++ b/flang/test/Semantics/resolve31.f90
@@ -1,4 +1,13 @@
! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
+! C735 If EXTENDS appears, SEQUENCE shall not appear.
+! C738 The same private-or-sequence shall not appear more than once in a
+! given derived-type-def .
+!
+! C740 If SEQUENCE appears,
+! the type shall have at least one component,
+! each data component shall be declared to be of an intrinsic type or of a sequence type,
+! the derived type shall not have any type parameter,
+! and a type-bound-procedure-part shall not appear.
subroutine s1
integer :: t0
!ERROR: 't0' is not a derived type
@@ -41,6 +50,8 @@
private
sequence
private ! not a fatal error
+ sequence ! not a fatal error
+ real :: t1Field
end type
type :: t1a
end type
@@ -55,6 +66,32 @@
!ERROR: A sequence type may not have a CONTAINS statement
contains
end type
+ !ERROR: A sequence type must have at least one component
+ type :: emptyType
+ sequence
+ end type emptyType
+ type :: plainType
+ real :: plainField
+ end type plainType
+ type :: sequenceType
+ sequence
+ real :: sequenceField
+ end type sequenceType
+ type :: testType
+ sequence
+ !ERROR: A sequence type data component must either be of an intrinsic type or a derived sequence type
+ class(*), allocatable :: typeStarField
+ !ERROR: A sequence type data component must either be of an intrinsic type or a derived sequence type
+ type(plainType) :: testField1
+ type(sequenceType) :: testField2
+ procedure(real), nopass :: procField
+ end type testType
+ !ERROR: A sequence type may not have type parameters
+ type :: paramType(param)
+ integer, kind :: param
+ sequence
+ real :: paramField
+ end type paramType
contains
subroutine s3
type :: t1
diff --git a/flang/test/Semantics/resolve33.f90 b/flang/test/Semantics/resolve33.f90
index d4265cd..176404b 100644
--- a/flang/test/Semantics/resolve33.f90
+++ b/flang/test/Semantics/resolve33.f90
@@ -1,5 +1,7 @@
! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
! Derived type parameters
+! C731 The same type-param-name shall not appear more than once in a given
+! derived-type-stmt.
module m
!ERROR: Duplicate type parameter name: 'a'
diff --git a/flang/test/Semantics/resolve86.f90 b/flang/test/Semantics/resolve86.f90
new file mode 100644
index 0000000..0c42bce
--- /dev/null
+++ b/flang/test/Semantics/resolve86.f90
@@ -0,0 +1,44 @@
+! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
+! C736 If EXTENDS appears and the type being defined has a coarray ultimate
+! component, its parent type shall have a coarray ultimate component.
+!
+subroutine s()
+ type coarrayParent
+ real,allocatable, codimension[:] :: parentField
+ end type coarrayParent
+
+ type, extends(coarrayParent) :: goodChildType
+ real, allocatable, codimension[:] :: childField
+ end type goodChildType
+
+ type, extends(coarrayParent) :: brotherType
+ real :: brotherField
+ end type brotherType
+
+ type, extends(brotherType) :: grandChildType
+ real, allocatable, codimension[:] :: grandChildField
+ end type grandChildType
+
+ type plainParent
+ end type plainParent
+
+ !ERROR: Type 'badchildtype' has a coarray ultimate component so the type at the base of its type extension chain ('plainparent') must be a type that has a coarray ultimate component
+ type, extends(plainParent) :: badChildType
+ real, allocatable, codimension[:] :: childField
+ end type badChildType
+
+ type, extends(plainParent) :: plainChild
+ real :: realField
+ end type plainChild
+
+ !ERROR: Type 'badchildtype2' has a coarray ultimate component so the type at the base of its type extension chain ('plainparent') must be a type that has a coarray ultimate component
+ type, extends(plainChild) :: badChildType2
+ real, allocatable, codimension[:] :: childField
+ end type badChildType2
+
+ !ERROR: Type 'badchildtype3' has a coarray ultimate component so the type at the base of its type extension chain ('plainparent') must be a type that has a coarray ultimate component
+ type, extends(plainParent) :: badChildType3
+ type(coarrayParent) :: childField
+ end type badChildType3
+
+end subroutine s
diff --git a/flang/test/Semantics/resolve87.f90 b/flang/test/Semantics/resolve87.f90
new file mode 100644
index 0000000..ad09d81
--- /dev/null
+++ b/flang/test/Semantics/resolve87.f90
@@ -0,0 +1,90 @@
+! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
+! C737 If EXTENDS appears and the type being defined has a potential
+! subobject component of type EVENT_TYPE or LOCK_TYPE from the intrinsic
+! module ISO_FORTRAN_ENV, its parent type shall be EVENT_TYPE or LOCK_TYPE
+! or have a potential subobject component of type EVENT_TYPE or LOCK_TYPE.
+module not_iso_fortran_env
+ type event_type
+ end type
+
+ type lock_type
+ end type
+end module
+
+subroutine C737_a()
+ use iso_fortran_env
+
+ type lockGrandParentType
+ type(lock_type) :: grandParentField
+ end type lockGrandParentType
+
+ type, extends(lockGrandParentType) :: lockParentType
+ real :: parentField
+ end type lockParentType
+
+ type eventParentType
+ type(event_type) :: parentField
+ end type eventParentType
+
+ type noLockParentType
+ end type noLockParentType
+
+ type, extends(lockParentType) :: goodChildType1
+ type(lock_type) :: childField
+ end type goodChildType1
+
+ type, extends(lockParentType) :: goodChildType2
+ type(event_type) :: childField
+ end type goodChildType2
+
+ type, extends(lock_type) :: goodChildType3
+ type(event_type) :: childField
+ end type goodChildType3
+
+ type, extends(event_type) :: goodChildType4
+ type(lock_type) :: childField
+ end type goodChildType4
+
+ !ERROR: Type 'badchildtype1' has an EVENT_TYPE or LOCK_TYPE component, so the type at the base of its type extension chain ('nolockparenttype') must either have an EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or LOCK_TYPE
+ type, extends(noLockParentType) :: badChildType1
+ type(lock_type) :: childField
+ end type badChildType1
+
+ !ERROR: Type 'badchildtype2' has an EVENT_TYPE or LOCK_TYPE component, so the type at the base of its type extension chain ('nolockparenttype') must either have an EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or LOCK_TYPE
+ type, extends(noLockParentType) :: badChildType2
+ type(event_type) :: childField
+ end type badChildType2
+
+ !ERROR: Type 'badchildtype3' has an EVENT_TYPE or LOCK_TYPE component, so the type at the base of its type extension chain ('nolockparenttype') must either have an EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or LOCK_TYPE
+ type, extends(noLockParentType) :: badChildType3
+ type(lockParentType) :: childField
+ end type badChildType3
+
+ !ERROR: Type 'badchildtype4' has an EVENT_TYPE or LOCK_TYPE component, so the type at the base of its type extension chain ('nolockparenttype') must either have an EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or LOCK_TYPE
+ type, extends(noLockParentType) :: badChildType4
+ type(eventParentType) :: childField
+ end type badChildType4
+
+end subroutine C737_a
+
+subroutine C737_b()
+ use not_iso_fortran_env
+
+ type lockParentType
+ type(lock_type) :: parentField
+ end type lockParentType
+
+ type noLockParentType
+ end type noLockParentType
+
+ ! actually OK since this is not the predefined lock_type
+ type, extends(noLockParentType) :: notBadChildType1
+ type(lock_type) :: childField
+ end type notBadChildType1
+
+ ! actually OK since this is not the predefined event_type
+ type, extends(noLockParentType) :: notBadChildType2
+ type(event_type) :: childField
+ end type notBadChildType2
+
+end subroutine C737_b