-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[flang] Catch nasty order-of-declarations case #71881
Conversation
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.
@llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesIt 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. Full diff: https://github.com/llvm/llvm-project/pull/71881.diff 2 Files Affected:
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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great
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.
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.