Skip to content

Commit 8f01eca

Browse files
authored
[flang] Special-case handling of INTRINSIC in type-decl-stmt (#86518)
Fortran allows the INTRINSIC attribute to be specified with a distinct attribute statement, and also as part of the attribute list of a type-declaration-stmt. This is an odd case (especially as the declared type is mandated to be ignored if it doesn't match the type of the intrinsic function) that can lead to odd error messages and crashes, since the rest of name resolution expects that intrinsics with explicit declarations will have been declared with INTRINSIC attribute statements. Resolve by handling an "inline" INTRINSIC attribute as a special case while processing a type-declaration-stmt, so that real, intrinsic :: acos, asin, atan is processed exactly as if it had been intrinsic acos, asin, atan; real acos, asin, atan Fixes #86382.
1 parent e75989e commit 8f01eca

File tree

5 files changed

+61
-35
lines changed

5 files changed

+61
-35
lines changed

flang/include/flang/Parser/tools.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const Name &GetFirstName(const ProcedureDesignator &);
4040
const Name &GetFirstName(const Call &);
4141
const Name &GetFirstName(const FunctionReference &);
4242
const Name &GetFirstName(const Variable &);
43+
const Name &GetFirstName(const EntityDecl &);
4344

4445
// When a parse tree node is an instance of a specific type wrapped in
4546
// layers of packaging, return a pointer to that object.

flang/lib/Parser/tools.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ const Name &GetFirstName(const Variable &x) {
123123
x.u);
124124
}
125125

126+
const Name &GetFirstName(const EntityDecl &x) {
127+
return std::get<ObjectName>(x.t);
128+
}
129+
126130
const CoindexedNamedObject *GetCoindexedNamedObject(const DataRef &base) {
127131
return common::visit(
128132
common::visitors{

flang/lib/Semantics/resolve-names.cpp

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
955955
void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
956956
void Post(const parser::DimensionStmt::Declaration &);
957957
void Post(const parser::CodimensionDecl &);
958-
bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
958+
bool Pre(const parser::TypeDeclarationStmt &);
959959
void Post(const parser::TypeDeclarationStmt &);
960960
void Post(const parser::IntegerTypeSpec &);
961961
void Post(const parser::IntrinsicTypeSpec::Real &);
@@ -1202,6 +1202,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
12021202
bool MustBeScalar(const Symbol &symbol) const {
12031203
return mustBeScalar_.find(symbol) != mustBeScalar_.end();
12041204
}
1205+
void DeclareIntrinsic(const parser::Name &);
12051206
};
12061207

12071208
// Resolve construct entities and statement entities.
@@ -4550,6 +4551,20 @@ void DeclarationVisitor::CheckAccessibility(
45504551
}
45514552
}
45524553

4554+
bool DeclarationVisitor::Pre(const parser::TypeDeclarationStmt &x) {
4555+
BeginDecl();
4556+
// If INTRINSIC appears as an attr-spec, handle it now as if the
4557+
// names had appeared on an INTRINSIC attribute statement beforehand.
4558+
for (const auto &attr : std::get<std::list<parser::AttrSpec>>(x.t)) {
4559+
if (std::holds_alternative<parser::Intrinsic>(attr.u)) {
4560+
for (const auto &decl : std::get<std::list<parser::EntityDecl>>(x.t)) {
4561+
DeclareIntrinsic(parser::GetFirstName(decl));
4562+
}
4563+
break;
4564+
}
4565+
}
4566+
return true;
4567+
}
45534568
void DeclarationVisitor::Post(const parser::TypeDeclarationStmt &) {
45544569
EndDecl();
45554570
}
@@ -4571,6 +4586,7 @@ bool DeclarationVisitor::Pre(const parser::Initialization &) {
45714586
void DeclarationVisitor::Post(const parser::EntityDecl &x) {
45724587
const auto &name{std::get<parser::ObjectName>(x.t)};
45734588
Attrs attrs{attrs_ ? HandleSaveName(name.source, *attrs_) : Attrs{}};
4589+
attrs.set(Attr::INTRINSIC, false); // dealt with in Pre(TypeDeclarationStmt)
45744590
Symbol &symbol{DeclareUnknownEntity(name, attrs)};
45754591
symbol.ReplaceName(name.source);
45764592
SetCUDADataAttr(name.source, symbol, cudaDataAttr());
@@ -4811,45 +4827,47 @@ bool DeclarationVisitor::Pre(const parser::IntentStmt &x) {
48114827
HandleAttributeStmt(IntentSpecToAttr(intentSpec), names);
48124828
}
48134829
bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) {
4814-
HandleAttributeStmt(Attr::INTRINSIC, x.v);
48154830
for (const auto &name : x.v) {
4816-
if (!IsIntrinsic(name.source, std::nullopt)) {
4817-
Say(name.source, "'%s' is not a known intrinsic procedure"_err_en_US);
4818-
}
4819-
auto &symbol{DEREF(FindSymbol(name))};
4820-
if (symbol.has<GenericDetails>()) {
4821-
// Generic interface is extending intrinsic; ok
4822-
} else if (!ConvertToProcEntity(symbol)) {
4823-
SayWithDecl(
4824-
name, symbol, "INTRINSIC attribute not allowed on '%s'"_err_en_US);
4825-
} else if (symbol.attrs().test(Attr::EXTERNAL)) { // C840
4831+
DeclareIntrinsic(name);
4832+
}
4833+
return false;
4834+
}
4835+
void DeclarationVisitor::DeclareIntrinsic(const parser::Name &name) {
4836+
HandleAttributeStmt(Attr::INTRINSIC, name);
4837+
if (!IsIntrinsic(name.source, std::nullopt)) {
4838+
Say(name.source, "'%s' is not a known intrinsic procedure"_err_en_US);
4839+
}
4840+
auto &symbol{DEREF(FindSymbol(name))};
4841+
if (symbol.has<GenericDetails>()) {
4842+
// Generic interface is extending intrinsic; ok
4843+
} else if (!ConvertToProcEntity(symbol)) {
4844+
SayWithDecl(
4845+
name, symbol, "INTRINSIC attribute not allowed on '%s'"_err_en_US);
4846+
} else if (symbol.attrs().test(Attr::EXTERNAL)) { // C840
4847+
Say(symbol.name(),
4848+
"Symbol '%s' cannot have both EXTERNAL and INTRINSIC attributes"_err_en_US,
4849+
symbol.name());
4850+
} else {
4851+
if (symbol.GetType()) {
4852+
// These warnings are worded so that they should make sense in either
4853+
// order.
48264854
Say(symbol.name(),
4827-
"Symbol '%s' cannot have both EXTERNAL and INTRINSIC attributes"_err_en_US,
4828-
symbol.name());
4829-
} else {
4830-
if (symbol.GetType()) {
4831-
// These warnings are worded so that they should make sense in either
4832-
// order.
4833-
Say(symbol.name(),
4834-
"Explicit type declaration ignored for intrinsic function '%s'"_warn_en_US,
4835-
symbol.name())
4836-
.Attach(name.source,
4837-
"INTRINSIC statement for explicitly-typed '%s'"_en_US,
4838-
name.source);
4839-
}
4840-
if (!symbol.test(Symbol::Flag::Function) &&
4841-
!symbol.test(Symbol::Flag::Subroutine)) {
4842-
if (context().intrinsics().IsIntrinsicFunction(
4843-
name.source.ToString())) {
4844-
symbol.set(Symbol::Flag::Function);
4845-
} else if (context().intrinsics().IsIntrinsicSubroutine(
4846-
name.source.ToString())) {
4847-
symbol.set(Symbol::Flag::Subroutine);
4848-
}
4855+
"Explicit type declaration ignored for intrinsic function '%s'"_warn_en_US,
4856+
symbol.name())
4857+
.Attach(name.source,
4858+
"INTRINSIC statement for explicitly-typed '%s'"_en_US,
4859+
name.source);
4860+
}
4861+
if (!symbol.test(Symbol::Flag::Function) &&
4862+
!symbol.test(Symbol::Flag::Subroutine)) {
4863+
if (context().intrinsics().IsIntrinsicFunction(name.source.ToString())) {
4864+
symbol.set(Symbol::Flag::Function);
4865+
} else if (context().intrinsics().IsIntrinsicSubroutine(
4866+
name.source.ToString())) {
4867+
symbol.set(Symbol::Flag::Subroutine);
48494868
}
48504869
}
48514870
}
4852-
return false;
48534871
}
48544872
bool DeclarationVisitor::Pre(const parser::OptionalStmt &x) {
48554873
return CheckNotInBlock("OPTIONAL") && // C1107

flang/test/Semantics/init01.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,10 @@ subroutine notObjects
158158
real, external :: x1 = 1.
159159
!ERROR: 'x2' is not a pointer but is initialized like one
160160
real, external :: x2 => sin
161+
!ERROR: 'x3' is not a known intrinsic procedure
161162
!ERROR: 'x3' is not an object that can be initialized
162163
real, intrinsic :: x3 = 1.
164+
!ERROR: 'x4' is not a known intrinsic procedure
163165
!ERROR: 'x4' is not a pointer but is initialized like one
164166
real, intrinsic :: x4 => cos
165167
end subroutine

flang/test/Semantics/resolve81.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ module m
2828
!WARNING: Attribute 'EXTERNAL' cannot be used more than once
2929
real, external, external :: externFunc
3030
!WARNING: Attribute 'INTRINSIC' cannot be used more than once
31+
!ERROR: An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement
3132
real, intrinsic, bind(c), intrinsic :: cos
3233
!WARNING: Attribute 'BIND(C)' cannot be used more than once
3334
integer, bind(c), volatile, bind(c) :: bindVar

0 commit comments

Comments
 (0)