-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[flang] Don't crash on bad inherited implied DO type #91073
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
Conversation
Fortran has an ambiguously defined rule about the typing of index variables of implied DO loops in DATA statements and array constructors that omit an explicit type specification. Such indices have the type that they would have "if they were variables" in the innermost enclosing scope. Although this could, and perhaps should, be read to mean that implicit typing rules active in that innermost enclosing scope should be applied, every other Fortran compiler interprets that language to mean that if there is a type declaration for that name that is visible from the enclosing scope, it is applied, and it is an error if that type is not integer. Fixes llvm#91053.
@llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesFortran has an ambiguously defined rule about the typing of index variables of implied DO loops in DATA statements and array constructors that omit an explicit type specification. Such indices have the type that they would have "if they were variables" in the innermost enclosing scope. Although this could, and perhaps should, be read to mean that implicit typing rules active in that innermost enclosing scope should be applied, every other Fortran compiler interprets that language to mean that if there is a type declaration for that name that is visible from the enclosing scope, it is applied, and it is an error if that type is not integer. Fixes #91053. Full diff: https://github.com/llvm/llvm-project/pull/91073.diff 5 Files Affected:
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 9030207d9bda5d..0a5bcdc6ff3f4f 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -107,12 +107,6 @@ end
These definitions yield fairly poor results due to floating-point
cancellation, and every Fortran compiler (including this one)
uses better algorithms.
-* When an index variable of a `FORALL` or `DO CONCURRENT` is present
- in the enclosing scope, and the construct does not have an explicit
- type specification for its index variables, some weird restrictions
- in F'2023 subclause 19.4 paragraphs 6 & 8 should apply. Since this
- compiler properly scopes these names, violations of these restrictions
- elicit only portability warnings by default.
* The rules for pairwise distinguishing the specific procedures of a
generic interface are inadequate, as admitted in note C.11.6 of F'2023.
Generic interfaces whose specific procedures can be easily proven by
@@ -728,6 +722,23 @@ end
array and structure constructors not to be finalized, so it also makes sense
not to finalize their allocatable components when releasing their storage).
+* F'2023 19.4 paragraph 5: "If integer-type-spec appears in data-implied-do or
+ ac-implied-do-control it has the specified type and type parameters; otherwise
+ it has the type and type parameters that it would have if it were the name of
+ a variable in the innermost executable construct or scoping unit that includes
+ the DATA statement or array constructor, and this type shall be integer type."
+ Reading "would have if it were" as being the subjunctive, this would mean that
+ an untyped implied DO index variable should be implicitly typed according to
+ the rules active in the enclosing scope. But all other Fortran compilers interpret
+ the "would have if it were" as meaning "has if it is" -- i.e., if the name
+ is visible in the enclosing scope, the type of that name is used as the
+ type of the implied DO index. So this is an error, not a simple application
+ of the default implicit typing rule:
+```
+character j
+print *, [(j,j=1,10)]
+```
+
## De Facto Standard Features
* `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the
diff --git a/flang/lib/Evaluate/formatting.cpp b/flang/lib/Evaluate/formatting.cpp
index 5f822bbcbb04f4..20193b006bf2fd 100644
--- a/flang/lib/Evaluate/formatting.cpp
+++ b/flang/lib/Evaluate/formatting.cpp
@@ -539,10 +539,10 @@ std::string DynamicType::AsFortran() const {
result += length->AsFortran();
}
return result + ')';
- } else if (IsUnlimitedPolymorphic()) {
- return "CLASS(*)";
} else if (IsAssumedType()) {
return "TYPE(*)";
+ } else if (IsUnlimitedPolymorphic()) {
+ return "CLASS(*)";
} else if (IsTypelessIntrinsicArgument()) {
return "(typeless intrinsic function argument)";
} else {
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index f677973ca2753b..cb0174043ca1a7 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -1805,10 +1805,13 @@ void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
const auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
exprAnalyzer_.Analyze(bounds.name);
parser::CharBlock name{bounds.name.thing.thing.source};
- const Symbol *symbol{bounds.name.thing.thing.symbol};
int kind{ImpliedDoIntType::kind};
- if (const auto dynamicType{DynamicType::From(symbol)}) {
- kind = dynamicType->kind();
+ if (const Symbol * symbol{bounds.name.thing.thing.symbol}) {
+ if (auto dynamicType{DynamicType::From(symbol)}) {
+ if (dynamicType->category() == TypeCategory::Integer) {
+ kind = dynamicType->kind();
+ }
+ }
}
std::optional<Expr<ImpliedDoIntType>> lower{
GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.lower)};
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 61394b0f41de75..deccd4ea2ced41 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6556,6 +6556,7 @@ Symbol *DeclarationVisitor::DeclareStatementEntity(
return nullptr;
}
name.symbol = nullptr;
+ // F'2023 19.4 p5 ambiguous rule about outer declarations
declTypeSpec = prev->GetType();
}
Symbol &symbol{DeclareEntity<ObjectEntityDetails>(name, {})};
@@ -6574,9 +6575,7 @@ Symbol *DeclarationVisitor::DeclareStatementEntity(
} else {
ApplyImplicitRules(symbol);
}
- Symbol *result{Resolve(name, &symbol)};
- AnalyzeExpr(context(), doVar); // enforce INTEGER type
- return result;
+ return Resolve(name, &symbol);
}
// Set the type of an entity or report an error.
diff --git a/flang/test/Semantics/array-constr-index01.f90 b/flang/test/Semantics/array-constr-index01.f90
new file mode 100644
index 00000000000000..560b6be8313958
--- /dev/null
+++ b/flang/test/Semantics/array-constr-index01.f90
@@ -0,0 +1,8 @@
+!RUN: %python %S/test_errors.py %s %flang_fc1
+subroutine s(i)
+ type(*) :: i
+ !ERROR: TYPE(*) dummy argument may only be used as an actual argument
+ !ERROR: Assumed-type entity 'i' must be a dummy argument
+ !ERROR: Must have INTEGER type, but is TYPE(*)
+ print *, [(i, i = 1,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.
Great lesson about subjunctive for me. I hope the standard authors would have explicitly written something like "otherwise, its type and type parameters are defined by the implicit typing rules in effect in the innermost [...]" instead of using subjunctive on purpose if they had wanted something different from what other compilers are doing.
Fortran has an ambiguously defined rule about the typing of index variables of implied DO loops in DATA statements and array constructors that omit an explicit type specification. Such indices have the type that they would have "if they were variables" in the innermost enclosing scope. Although this could, and perhaps should, be read to mean that implicit typing rules active in that innermost enclosing scope should be applied, every other Fortran compiler interprets that language to mean that if there is a type declaration for that name that is visible from the enclosing scope, it is applied, and it is an error if that type is not integer.
Fixes #91053.