Skip to content

Commit 94d47e6

Browse files
authored
[flang] Catch nasty order-of-declarations case (llvm#71881)
It is possible to declare the rank of an object after that object has been used in the same specification part in a specification function reference whose result or generic resolution may well have depended on the object being apparently a scalar. Catch this case, and emit a warning -- not an error, yet, due to fear of false positives. See the new test for examples.
1 parent 1c91d9b commit 94d47e6

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
10781078
void EndCheckOnIndexUseInOwnBounds(const std::optional<SourceName> &restore) {
10791079
checkIndexUseInOwnBounds_ = restore;
10801080
}
1081+
void NoteScalarSpecificationArgument(const Symbol &symbol) {
1082+
mustBeScalar_.emplace(symbol);
1083+
}
10811084

10821085
private:
10831086
// The attribute corresponding to the statement containing an ObjectDecl
@@ -1116,6 +1119,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
11161119
std::optional<SourceName> checkIndexUseInOwnBounds_;
11171120
bool hasBindCName_{false};
11181121
bool isVectorType_{false};
1122+
UnorderedSymbolSet mustBeScalar_;
11191123

11201124
bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
11211125
Symbol &HandleAttributeStmt(Attr, const parser::Name &);
@@ -1195,6 +1199,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
11951199
return symbol;
11961200
}
11971201
bool HasCycle(const Symbol &, const Symbol *interface);
1202+
bool MustBeScalar(const Symbol &symbol) const {
1203+
return mustBeScalar_.find(symbol) != mustBeScalar_.end();
1204+
}
11981205
};
11991206

12001207
// Resolve construct entities and statement entities.
@@ -4886,6 +4893,9 @@ Symbol &DeclarationVisitor::DeclareObjectEntity(
48864893
"The dimensions of '%s' have already been declared"_err_en_US);
48874894
context().SetError(symbol);
48884895
}
4896+
} else if (MustBeScalar(symbol)) {
4897+
Say(name,
4898+
"'%s' appeared earlier as a scalar actual argument to a specification function"_warn_en_US);
48894899
} else {
48904900
details->set_shape(arraySpec());
48914901
}
@@ -7635,7 +7645,36 @@ void ResolveNamesVisitor::HandleCall(
76357645
},
76367646
},
76377647
std::get<parser::ProcedureDesignator>(call.t).u);
7638-
Walk(std::get<std::list<parser::ActualArgSpec>>(call.t));
7648+
const auto &arguments{std::get<std::list<parser::ActualArgSpec>>(call.t)};
7649+
Walk(arguments);
7650+
// Once an object has appeared in a specification function reference as
7651+
// a whole scalar actual argument, it cannot be (re)dimensioned later.
7652+
// The fact that it appeared to be a scalar may determine the resolution
7653+
// or the result of an inquiry intrinsic function or generic procedure.
7654+
if (inSpecificationPart_) {
7655+
for (const auto &argSpec : arguments) {
7656+
const auto &actual{std::get<parser::ActualArg>(argSpec.t)};
7657+
if (const auto *expr{
7658+
std::get_if<common::Indirection<parser::Expr>>(&actual.u)}) {
7659+
if (const auto *designator{
7660+
std::get_if<common::Indirection<parser::Designator>>(
7661+
&expr->value().u)}) {
7662+
if (const auto *dataRef{
7663+
std::get_if<parser::DataRef>(&designator->value().u)}) {
7664+
if (const auto *name{std::get_if<parser::Name>(&dataRef->u)};
7665+
name && name->symbol) {
7666+
const Symbol &symbol{*name->symbol};
7667+
const auto *object{symbol.detailsIf<ObjectEntityDetails>()};
7668+
if (symbol.has<EntityDetails>() ||
7669+
(object && !object->IsArray())) {
7670+
NoteScalarSpecificationArgument(symbol);
7671+
}
7672+
}
7673+
}
7674+
}
7675+
}
7676+
}
7677+
}
76397678
}
76407679

76417680
void ResolveNamesVisitor::HandleProcedureName(
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
2+
! A nasty case of a weird order of declarations - a symbol may appear
3+
! as an actual argument to a specification function before its rank
4+
! has been declared.
5+
program main
6+
interface kind
7+
pure integer function mykind(x)
8+
real, intent(in) :: x(:)
9+
end
10+
end interface
11+
real a, b
12+
integer, parameter :: ak = kind(a)
13+
integer, parameter :: br = rank(b)
14+
!WARNING: 'a' appeared earlier as a scalar actual argument to a specification function
15+
dimension a(1)
16+
!WARNING: 'b' appeared earlier as a scalar actual argument to a specification function
17+
dimension b(1)
18+
end

0 commit comments

Comments
 (0)