Skip to content

Commit 22c59e0

Browse files
authored
[flang] Don't crash on bad inherited implied DO type (llvm#91073)
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.
1 parent 785b143 commit 22c59e0

File tree

5 files changed

+35
-14
lines changed

5 files changed

+35
-14
lines changed

flang/docs/Extensions.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,6 @@ end
107107
These definitions yield fairly poor results due to floating-point
108108
cancellation, and every Fortran compiler (including this one)
109109
uses better algorithms.
110-
* When an index variable of a `FORALL` or `DO CONCURRENT` is present
111-
in the enclosing scope, and the construct does not have an explicit
112-
type specification for its index variables, some weird restrictions
113-
in F'2023 subclause 19.4 paragraphs 6 & 8 should apply. Since this
114-
compiler properly scopes these names, violations of these restrictions
115-
elicit only portability warnings by default.
116110
* The rules for pairwise distinguishing the specific procedures of a
117111
generic interface are inadequate, as admitted in note C.11.6 of F'2023.
118112
Generic interfaces whose specific procedures can be easily proven by
@@ -728,6 +722,23 @@ end
728722
array and structure constructors not to be finalized, so it also makes sense
729723
not to finalize their allocatable components when releasing their storage).
730724

725+
* F'2023 19.4 paragraph 5: "If integer-type-spec appears in data-implied-do or
726+
ac-implied-do-control it has the specified type and type parameters; otherwise
727+
it has the type and type parameters that it would have if it were the name of
728+
a variable in the innermost executable construct or scoping unit that includes
729+
the DATA statement or array constructor, and this type shall be integer type."
730+
Reading "would have if it were" as being the subjunctive, this would mean that
731+
an untyped implied DO index variable should be implicitly typed according to
732+
the rules active in the enclosing scope. But all other Fortran compilers interpret
733+
the "would have if it were" as meaning "has if it is" -- i.e., if the name
734+
is visible in the enclosing scope, the type of that name is used as the
735+
type of the implied DO index. So this is an error, not a simple application
736+
of the default implicit typing rule:
737+
```
738+
character j
739+
print *, [(j,j=1,10)]
740+
```
741+
731742
## De Facto Standard Features
732743

733744
* `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the

flang/lib/Evaluate/formatting.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,10 +539,10 @@ std::string DynamicType::AsFortran() const {
539539
result += length->AsFortran();
540540
}
541541
return result + ')';
542-
} else if (IsUnlimitedPolymorphic()) {
543-
return "CLASS(*)";
544542
} else if (IsAssumedType()) {
545543
return "TYPE(*)";
544+
} else if (IsUnlimitedPolymorphic()) {
545+
return "CLASS(*)";
546546
} else if (IsTypelessIntrinsicArgument()) {
547547
return "(typeless intrinsic function argument)";
548548
} else {

flang/lib/Semantics/expression.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,10 +1805,13 @@ void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
18051805
const auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
18061806
exprAnalyzer_.Analyze(bounds.name);
18071807
parser::CharBlock name{bounds.name.thing.thing.source};
1808-
const Symbol *symbol{bounds.name.thing.thing.symbol};
18091808
int kind{ImpliedDoIntType::kind};
1810-
if (const auto dynamicType{DynamicType::From(symbol)}) {
1811-
kind = dynamicType->kind();
1809+
if (const Symbol * symbol{bounds.name.thing.thing.symbol}) {
1810+
if (auto dynamicType{DynamicType::From(symbol)}) {
1811+
if (dynamicType->category() == TypeCategory::Integer) {
1812+
kind = dynamicType->kind();
1813+
}
1814+
}
18121815
}
18131816
std::optional<Expr<ImpliedDoIntType>> lower{
18141817
GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.lower)};

flang/lib/Semantics/resolve-names.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6555,6 +6555,7 @@ Symbol *DeclarationVisitor::DeclareStatementEntity(
65556555
return nullptr;
65566556
}
65576557
name.symbol = nullptr;
6558+
// F'2023 19.4 p5 ambiguous rule about outer declarations
65586559
declTypeSpec = prev->GetType();
65596560
}
65606561
Symbol &symbol{DeclareEntity<ObjectEntityDetails>(name, {})};
@@ -6573,9 +6574,7 @@ Symbol *DeclarationVisitor::DeclareStatementEntity(
65736574
} else {
65746575
ApplyImplicitRules(symbol);
65756576
}
6576-
Symbol *result{Resolve(name, &symbol)};
6577-
AnalyzeExpr(context(), doVar); // enforce INTEGER type
6578-
return result;
6577+
return Resolve(name, &symbol);
65796578
}
65806579

65816580
// Set the type of an entity or report an error.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
!RUN: %python %S/test_errors.py %s %flang_fc1
2+
subroutine s(i)
3+
type(*) :: i
4+
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
5+
!ERROR: Assumed-type entity 'i' must be a dummy argument
6+
!ERROR: Must have INTEGER type, but is TYPE(*)
7+
print *, [(i, i = 1,1)]
8+
end

0 commit comments

Comments
 (0)