bool Pre(const parser::DeclarationTypeSpec::Class &);
bool Pre(const parser::DeclarationTypeSpec::Record &);
void Post(const parser::DerivedTypeSpec &);
- void Post(const parser::DerivedTypeDef &x);
+ bool Pre(const parser::DerivedTypeDef &);
bool Pre(const parser::DerivedTypeStmt &x);
void Post(const parser::DerivedTypeStmt &x);
bool Pre(const parser::TypeParamDefStmt &x) { return BeginDecl(); }
bool Pre(const parser::SequenceStmt &x);
bool Pre(const parser::ComponentDefStmt &) { return BeginDecl(); }
void Post(const parser::ComponentDefStmt &) { EndDecl(); }
- void Post(const parser::ComponentDecl &x);
+ void Post(const parser::ComponentDecl &);
bool Pre(const parser::ProcedureDeclarationStmt &);
void Post(const parser::ProcedureDeclarationStmt &);
bool Pre(const parser::ProcComponentDefStmt &);
void Post(const parser::ProcInterface &x);
void Post(const parser::ProcDecl &x);
bool Pre(const parser::TypeBoundProcedurePart &);
+ void Post(const parser::ContainsStmt &);
bool Pre(const parser::TypeBoundProcBinding &) { return BeginAttrs(); }
void Post(const parser::TypeBoundProcBinding &) { EndAttrs(); }
void Post(const parser::TypeBoundProcedureStmt::WithoutInterface &);
std::optional<ParamValue> length;
std::optional<KindExpr> kind;
} charInfo_;
- // Info about current derived type while walking DerivedTypeStmt
+ // Info about current derived type while walking DerivedTypeDef
struct {
const parser::Name *extends{nullptr}; // EXTENDS(name)
bool privateComps{false}; // components are private by default
bool privateBindings{false}; // bindings are private by default
bool sawContains{false}; // currently processing bindings
bool sequence{false}; // is a sequence type
+ const Symbol *type{nullptr}; // derived type being defined
} derivedTypeInfo_;
// Info about common blocks in the current scope
struct {
x.derivedTypeSpec = &GetDeclTypeSpec()->derivedTypeSpec();
}
-void DeclarationVisitor::Post(const parser::DerivedTypeDef &x) {
- std::set<SourceName> paramNames;
+// The descendents of DerivedTypeDef in the parse tree are visited directly
+// in this Pre() routine so that recursive use of the derived type can be
+// supported in the components.
+bool DeclarationVisitor::Pre(const parser::DerivedTypeDef &x) {
+ Walk(std::get<parser::Statement<parser::DerivedTypeStmt>>(x.t));
+ Walk(std::get<std::list<parser::Statement<parser::TypeParamDefStmt>>>(x.t));
auto &scope{currScope()};
CHECK(scope.symbol() != nullptr);
CHECK(scope.symbol()->scope() == &scope);
auto &details{scope.symbol()->get<DerivedTypeDetails>()};
auto &stmt{std::get<parser::Statement<parser::DerivedTypeStmt>>(x.t)};
+ std::set<SourceName> paramNames;
for (auto ¶mName : std::get<std::list<parser::Name>>(stmt.statement.t)) {
details.add_paramName(paramName.source);
auto *symbol{FindInScope(scope, paramName)};
currScope()); // C742
}
}
+ Walk(std::get<std::list<parser::Statement<parser::PrivateOrSequence>>>(x.t));
if (derivedTypeInfo_.sequence) {
details.set_sequence(true);
if (derivedTypeInfo_.extends) {
Say(stmt.source,
"A sequence type may not have type parameters"_err_en_US); // C740
}
- if (derivedTypeInfo_.sawContains) {
- Say(stmt.source,
- "A sequence type may not have a CONTAINS statement"_err_en_US); // C740
- }
}
+ 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_ = {};
PopScope();
+ return false;
}
bool DeclarationVisitor::Pre(const parser::DerivedTypeStmt &x) {
return BeginAttrs();
void DeclarationVisitor::Post(const parser::DerivedTypeStmt &x) {
auto &name{std::get<parser::Name>(x.t)};
auto &symbol{MakeSymbol(name, GetAttrs(), DerivedTypeDetails{})};
+ derivedTypeInfo_.type = &symbol;
PushScope(Scope::Kind::DerivedType, &symbol);
if (auto *extendsName{derivedTypeInfo_.extends}) {
if (const Symbol * extends{ResolveDerivedType(*extendsName)}) {
!attrs.HasAny({Attr::PUBLIC, Attr::PRIVATE})) {
attrs.set(Attr::PRIVATE);
}
+ if (!attrs.HasAny({Attr::POINTER, Attr::ALLOCATABLE})) {
+ if (const auto *declType{GetDeclTypeSpec()}) {
+ if (const auto *derived{declType->AsDerived()}) {
+ if (derivedTypeInfo_.type == &derived->typeSymbol()) { // C737
+ Say("Recursive use of the derived type requires "
+ "POINTER or ALLOCATABLE"_err_en_US);
+ }
+ }
+ }
+ }
if (OkToAddComponent(name)) {
auto &symbol{DeclareObjectEntity(name, attrs)};
if (auto *details{symbol.detailsIf<ObjectEntityDetails>()}) {
return true;
}
+void DeclarationVisitor::Post(const parser::ContainsStmt &) {
+ if (derivedTypeInfo_.sequence) {
+ Say("A sequence type may not have a CONTAINS statement"_err_en_US); // C740
+ }
+}
+
void DeclarationVisitor::Post(
const parser::TypeBoundProcedureStmt::WithoutInterface &x) {
if (GetAttrs().test(Attr::DEFERRED)) { // C783
--- /dev/null
+! Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+!
+! Licensed under the Apache License, Version 2.0 (the "License");
+! you may not use this file except in compliance with the License.
+! You may obtain a copy of the License at
+!
+! http://www.apache.org/licenses/LICENSE-2.0
+!
+! Unless required by applicable law or agreed to in writing, software
+! distributed under the License is distributed on an "AS IS" BASIS,
+! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+! See the License for the specific language governing permissions and
+! limitations under the License.
+
+! Error tests for recursive use of derived types.
+
+program main
+ type :: recursive1
+ !ERROR: Recursive use of the derived type requires POINTER or ALLOCATABLE
+ type(recursive1) :: bad
+ type(recursive1), pointer :: ok1
+ type(recursive1), allocatable :: ok2
+ end type recursive1
+ type :: recursive2(kind,len)
+ integer, kind :: kind
+ integer, len :: len
+ !ERROR: Recursive use of the derived type requires POINTER or ALLOCATABLE
+ type(recursive2(kind,len)) :: bad
+ type(recursive2(kind,len)), pointer :: ok1
+ type(recursive2(kind,len)), allocatable :: ok2
+ end type recursive2
+ type :: recursive3(kind,len)
+ integer, kind :: kind = 1
+ integer, len :: len = 2
+ !ERROR: Recursive use of the derived type requires POINTER or ALLOCATABLE
+ type(recursive3) :: bad
+ type(recursive3), pointer :: ok1
+ type(recursive3), allocatable :: ok2
+ end type recursive3
+end program main