[flang-commits] [flang] [flang] Catch nasty order-of-declarations case (PR #71881)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Thu Nov 9 16:20:41 PST 2023
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/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.
>From aea06c59d855464506301095589a7f23bd612788 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Thu, 9 Nov 2023 16:15:43 -0800
Subject: [PATCH] [flang] Catch nasty order-of-declarations case
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.
---
flang/lib/Semantics/resolve-names.cpp | 41 ++++++++++++++++++++++++-
flang/test/Semantics/declarations07.f90 | 18 +++++++++++
2 files changed, 58 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Semantics/declarations07.f90
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 98773a1b9d6ab45..43d570721567611 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1078,6 +1078,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
void EndCheckOnIndexUseInOwnBounds(const std::optional<SourceName> &restore) {
checkIndexUseInOwnBounds_ = restore;
}
+ void NoteScalarSpecificationArgument(const Symbol &symbol) {
+ mustBeScalar_.emplace(symbol);
+ }
private:
// The attribute corresponding to the statement containing an ObjectDecl
@@ -1116,6 +1119,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
std::optional<SourceName> checkIndexUseInOwnBounds_;
bool hasBindCName_{false};
bool isVectorType_{false};
+ UnorderedSymbolSet mustBeScalar_;
bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
Symbol &HandleAttributeStmt(Attr, const parser::Name &);
@@ -1195,6 +1199,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
return symbol;
}
bool HasCycle(const Symbol &, const Symbol *interface);
+ bool MustBeScalar(const Symbol &symbol) const {
+ return mustBeScalar_.find(symbol) != mustBeScalar_.end();
+ }
};
// Resolve construct entities and statement entities.
@@ -4879,6 +4886,9 @@ Symbol &DeclarationVisitor::DeclareObjectEntity(
"The dimensions of '%s' have already been declared"_err_en_US);
context().SetError(symbol);
}
+ } else if (MustBeScalar(symbol)) {
+ Say(name,
+ "'%s' appeared earlier as a scalar actual argument to a specification function"_warn_en_US);
} else {
details->set_shape(arraySpec());
}
@@ -7622,7 +7632,36 @@ void ResolveNamesVisitor::HandleCall(
},
},
std::get<parser::ProcedureDesignator>(call.t).u);
- Walk(std::get<std::list<parser::ActualArgSpec>>(call.t));
+ const auto &arguments{std::get<std::list<parser::ActualArgSpec>>(call.t)};
+ Walk(arguments);
+ // Once an object has appeared in a specification function reference as
+ // a whole scalar actual argument, it cannot be (re)dimensioned later.
+ // The fact that it appeared to be a scalar may determine the resolution
+ // or the result of an inquiry intrinsic function or generic procedure.
+ if (inSpecificationPart_) {
+ for (const auto &argSpec : arguments) {
+ const auto &actual{std::get<parser::ActualArg>(argSpec.t)};
+ if (const auto *expr{
+ std::get_if<common::Indirection<parser::Expr>>(&actual.u)}) {
+ if (const auto *designator{
+ std::get_if<common::Indirection<parser::Designator>>(
+ &expr->value().u)}) {
+ if (const auto *dataRef{
+ std::get_if<parser::DataRef>(&designator->value().u)}) {
+ if (const auto *name{std::get_if<parser::Name>(&dataRef->u)};
+ name && name->symbol) {
+ const Symbol &symbol{*name->symbol};
+ const auto *object{symbol.detailsIf<ObjectEntityDetails>()};
+ if (symbol.has<EntityDetails>() ||
+ (object && !object->IsArray())) {
+ NoteScalarSpecificationArgument(symbol);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
void ResolveNamesVisitor::HandleProcedureName(
diff --git a/flang/test/Semantics/declarations07.f90 b/flang/test/Semantics/declarations07.f90
new file mode 100644
index 000000000000000..8c95c163b043be7
--- /dev/null
+++ b/flang/test/Semantics/declarations07.f90
@@ -0,0 +1,18 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
+! A nasty case of a weird order of declarations - a symbol may appear
+! as an actual argument to a specification function before its rank
+! has been declared.
+program main
+ interface kind
+ pure integer function mykind(x)
+ real, intent(in) :: x(:)
+ end
+ end interface
+ real a, b
+ integer, parameter :: ak = kind(a)
+ integer, parameter :: br = rank(b)
+ !WARNING: 'a' appeared earlier as a scalar actual argument to a specification function
+ dimension a(1)
+ !WARNING: 'b' appeared earlier as a scalar actual argument to a specification function
+ dimension b(1)
+end
More information about the flang-commits
mailing list