diff --git a/flang/include/flang/Parser/tools.h b/flang/include/flang/Parser/tools.h index 1e347fab6461a..f1ead11734fa0 100644 --- a/flang/include/flang/Parser/tools.h +++ b/flang/include/flang/Parser/tools.h @@ -40,6 +40,7 @@ const Name &GetFirstName(const ProcedureDesignator &); const Name &GetFirstName(const Call &); const Name &GetFirstName(const FunctionReference &); const Name &GetFirstName(const Variable &); +const Name &GetFirstName(const EntityDecl &); // When a parse tree node is an instance of a specific type wrapped in // layers of packaging, return a pointer to that object. diff --git a/flang/lib/Parser/tools.cpp b/flang/lib/Parser/tools.cpp index 899fb0f069a93..6e5f1ed2fc66f 100644 --- a/flang/lib/Parser/tools.cpp +++ b/flang/lib/Parser/tools.cpp @@ -123,6 +123,10 @@ const Name &GetFirstName(const Variable &x) { x.u); } +const Name &GetFirstName(const EntityDecl &x) { + return std::get(x.t); +} + const CoindexedNamedObject *GetCoindexedNamedObject(const DataRef &base) { return common::visit( common::visitors{ diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 73450c49d5fe2..2e88a2daff2c0 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -955,7 +955,7 @@ class DeclarationVisitor : public ArraySpecVisitor, void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; } void Post(const parser::DimensionStmt::Declaration &); void Post(const parser::CodimensionDecl &); - bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); } + bool Pre(const parser::TypeDeclarationStmt &); void Post(const parser::TypeDeclarationStmt &); void Post(const parser::IntegerTypeSpec &); void Post(const parser::IntrinsicTypeSpec::Real &); @@ -1202,6 +1202,7 @@ class DeclarationVisitor : public ArraySpecVisitor, bool MustBeScalar(const Symbol &symbol) const { return mustBeScalar_.find(symbol) != mustBeScalar_.end(); } + void DeclareIntrinsic(const parser::Name &); }; // Resolve construct entities and statement entities. @@ -4550,6 +4551,20 @@ void DeclarationVisitor::CheckAccessibility( } } +bool DeclarationVisitor::Pre(const parser::TypeDeclarationStmt &x) { + BeginDecl(); + // If INTRINSIC appears as an attr-spec, handle it now as if the + // names had appeared on an INTRINSIC attribute statement beforehand. + for (const auto &attr : std::get>(x.t)) { + if (std::holds_alternative(attr.u)) { + for (const auto &decl : std::get>(x.t)) { + DeclareIntrinsic(parser::GetFirstName(decl)); + } + break; + } + } + return true; +} void DeclarationVisitor::Post(const parser::TypeDeclarationStmt &) { EndDecl(); } @@ -4571,6 +4586,7 @@ bool DeclarationVisitor::Pre(const parser::Initialization &) { void DeclarationVisitor::Post(const parser::EntityDecl &x) { const auto &name{std::get(x.t)}; Attrs attrs{attrs_ ? HandleSaveName(name.source, *attrs_) : Attrs{}}; + attrs.set(Attr::INTRINSIC, false); // dealt with in Pre(TypeDeclarationStmt) Symbol &symbol{DeclareUnknownEntity(name, attrs)}; symbol.ReplaceName(name.source); SetCUDADataAttr(name.source, symbol, cudaDataAttr()); @@ -4811,45 +4827,47 @@ bool DeclarationVisitor::Pre(const parser::IntentStmt &x) { HandleAttributeStmt(IntentSpecToAttr(intentSpec), names); } bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) { - HandleAttributeStmt(Attr::INTRINSIC, x.v); for (const auto &name : x.v) { - if (!IsIntrinsic(name.source, std::nullopt)) { - Say(name.source, "'%s' is not a known intrinsic procedure"_err_en_US); - } - auto &symbol{DEREF(FindSymbol(name))}; - if (symbol.has()) { - // Generic interface is extending intrinsic; ok - } else if (!ConvertToProcEntity(symbol)) { - SayWithDecl( - name, symbol, "INTRINSIC attribute not allowed on '%s'"_err_en_US); - } else if (symbol.attrs().test(Attr::EXTERNAL)) { // C840 + DeclareIntrinsic(name); + } + return false; +} +void DeclarationVisitor::DeclareIntrinsic(const parser::Name &name) { + HandleAttributeStmt(Attr::INTRINSIC, name); + if (!IsIntrinsic(name.source, std::nullopt)) { + Say(name.source, "'%s' is not a known intrinsic procedure"_err_en_US); + } + auto &symbol{DEREF(FindSymbol(name))}; + if (symbol.has()) { + // Generic interface is extending intrinsic; ok + } else if (!ConvertToProcEntity(symbol)) { + SayWithDecl( + name, symbol, "INTRINSIC attribute not allowed on '%s'"_err_en_US); + } else if (symbol.attrs().test(Attr::EXTERNAL)) { // C840 + Say(symbol.name(), + "Symbol '%s' cannot have both EXTERNAL and INTRINSIC attributes"_err_en_US, + symbol.name()); + } else { + if (symbol.GetType()) { + // These warnings are worded so that they should make sense in either + // order. Say(symbol.name(), - "Symbol '%s' cannot have both EXTERNAL and INTRINSIC attributes"_err_en_US, - symbol.name()); - } else { - if (symbol.GetType()) { - // These warnings are worded so that they should make sense in either - // order. - Say(symbol.name(), - "Explicit type declaration ignored for intrinsic function '%s'"_warn_en_US, - symbol.name()) - .Attach(name.source, - "INTRINSIC statement for explicitly-typed '%s'"_en_US, - name.source); - } - if (!symbol.test(Symbol::Flag::Function) && - !symbol.test(Symbol::Flag::Subroutine)) { - if (context().intrinsics().IsIntrinsicFunction( - name.source.ToString())) { - symbol.set(Symbol::Flag::Function); - } else if (context().intrinsics().IsIntrinsicSubroutine( - name.source.ToString())) { - symbol.set(Symbol::Flag::Subroutine); - } + "Explicit type declaration ignored for intrinsic function '%s'"_warn_en_US, + symbol.name()) + .Attach(name.source, + "INTRINSIC statement for explicitly-typed '%s'"_en_US, + name.source); + } + if (!symbol.test(Symbol::Flag::Function) && + !symbol.test(Symbol::Flag::Subroutine)) { + if (context().intrinsics().IsIntrinsicFunction(name.source.ToString())) { + symbol.set(Symbol::Flag::Function); + } else if (context().intrinsics().IsIntrinsicSubroutine( + name.source.ToString())) { + symbol.set(Symbol::Flag::Subroutine); } } } - return false; } bool DeclarationVisitor::Pre(const parser::OptionalStmt &x) { return CheckNotInBlock("OPTIONAL") && // C1107 diff --git a/flang/test/Semantics/init01.f90 b/flang/test/Semantics/init01.f90 index f85feef097cdc..65d524b16a23a 100644 --- a/flang/test/Semantics/init01.f90 +++ b/flang/test/Semantics/init01.f90 @@ -158,8 +158,10 @@ subroutine notObjects real, external :: x1 = 1. !ERROR: 'x2' is not a pointer but is initialized like one real, external :: x2 => sin +!ERROR: 'x3' is not a known intrinsic procedure !ERROR: 'x3' is not an object that can be initialized real, intrinsic :: x3 = 1. +!ERROR: 'x4' is not a known intrinsic procedure !ERROR: 'x4' is not a pointer but is initialized like one real, intrinsic :: x4 => cos end subroutine diff --git a/flang/test/Semantics/resolve81.f90 b/flang/test/Semantics/resolve81.f90 index 2a0b961d48e5c..87901fd7d2efc 100644 --- a/flang/test/Semantics/resolve81.f90 +++ b/flang/test/Semantics/resolve81.f90 @@ -28,6 +28,7 @@ module m !WARNING: Attribute 'EXTERNAL' cannot be used more than once real, external, external :: externFunc !WARNING: Attribute 'INTRINSIC' cannot be used more than once + !ERROR: An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement real, intrinsic, bind(c), intrinsic :: cos !WARNING: Attribute 'BIND(C)' cannot be used more than once integer, bind(c), volatile, bind(c) :: bindVar