Skip to content

[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

Merged
merged 1 commit into from
May 9, 2024

Conversation

klausler
Copy link
Contributor

@klausler klausler commented May 4, 2024

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.

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.
@klausler klausler requested a review from jeanPerier May 4, 2024 17:20
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels May 4, 2024
@llvmbot
Copy link
Member

llvmbot commented May 4, 2024

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/91073.diff

5 Files Affected:

  • (modified) flang/docs/Extensions.md (+17-6)
  • (modified) flang/lib/Evaluate/formatting.cpp (+2-2)
  • (modified) flang/lib/Semantics/expression.cpp (+6-3)
  • (modified) flang/lib/Semantics/resolve-names.cpp (+2-3)
  • (added) flang/test/Semantics/array-constr-index01.f90 (+8)
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

Copy link
Contributor

@jeanPerier jeanPerier left a 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.

@klausler klausler merged commit 22c59e0 into llvm:main May 9, 2024
@klausler klausler deleted the bug91053 branch May 9, 2024 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Flang] fatal internal error: CHECK(kind_ > 0) failed at /root/llvm-project/flang/include/flang/Evaluate/type.h(149)
3 participants