Skip to content

Commit 571ad73

Browse files
authored
[flang] Defer processing of non-pointer variable initializers (#76475)
Initializers in entity-decls don't need to have their expressions analyzed immediately in name resolution unless of course they are defining the values of named constants. By deferring the expression analysis, the compiler can better handle references to module and internal procedures that might appear in structure constructors; at present, these are typically rejected as being forward references (which they can be) to subprogram names that can't yet be checked for compatibility with the characteristics of the corresponding procedure component.
1 parent 02c2bf8 commit 571ad73

File tree

5 files changed

+87
-46
lines changed

5 files changed

+87
-46
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ class ScopeHandler : public ImplicitRulesVisitor {
698698
bool CheckPossibleBadForwardRef(const Symbol &);
699699

700700
bool inSpecificationPart_{false};
701-
bool inDataStmtObject_{false};
701+
bool deferImplicitTyping_{false};
702702
bool inEquivalenceStmt_{false};
703703

704704
// Some information is collected from a specification part for deferred
@@ -1629,6 +1629,7 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
16291629
bool BeginScopeForNode(const ProgramTree &);
16301630
void EndScopeForNode(const ProgramTree &);
16311631
void FinishSpecificationParts(const ProgramTree &);
1632+
void FinishExecutionParts(const ProgramTree &);
16321633
void FinishDerivedTypeInstantiation(Scope &);
16331634
void ResolveExecutionParts(const ProgramTree &);
16341635
void UseCUDABuiltinNames();
@@ -2533,7 +2534,7 @@ void ScopeHandler::ApplyImplicitRules(
25332534
// or object, it'll be caught later.
25342535
return;
25352536
}
2536-
if (inDataStmtObject_) {
2537+
if (deferImplicitTyping_) {
25372538
return;
25382539
}
25392540
if (!context().HasError(symbol)) {
@@ -2709,7 +2710,7 @@ const DeclTypeSpec &ScopeHandler::MakeLogicalType(int kind) {
27092710
}
27102711

27112712
void ScopeHandler::NotePossibleBadForwardRef(const parser::Name &name) {
2712-
if (inSpecificationPart_ && !inDataStmtObject_ && name.symbol) {
2713+
if (inSpecificationPart_ && !deferImplicitTyping_ && name.symbol) {
27132714
auto kind{currScope().kind()};
27142715
if ((kind == Scope::Kind::Subprogram && !currScope().IsStmtFunction()) ||
27152716
kind == Scope::Kind::BlockConstruct) {
@@ -6802,7 +6803,8 @@ bool ConstructVisitor::Pre(const parser::DataStmtObject &x) {
68026803
auto flagRestorer{common::ScopedSet(inSpecificationPart_, false)};
68036804
common::visit(common::visitors{
68046805
[&](const Indirection<parser::Variable> &y) {
6805-
auto restorer{common::ScopedSet(inDataStmtObject_, true)};
6806+
auto restorer{
6807+
common::ScopedSet(deferImplicitTyping_, true)};
68066808
Walk(y.value());
68076809
const parser::Name &first{
68086810
parser::GetFirstName(y.value())};
@@ -7386,7 +7388,7 @@ const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
73867388
}
73877389
return &name;
73887390
}
7389-
if (isImplicitNoneType() && !inDataStmtObject_) {
7391+
if (isImplicitNoneType() && !deferImplicitTyping_) {
73907392
Say(name, "No explicit type declared for '%s'"_err_en_US);
73917393
return nullptr;
73927394
}
@@ -7548,7 +7550,15 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
75487550
common::visit(
75497551
common::visitors{
75507552
[&](const parser::ConstantExpr &expr) {
7551-
NonPointerInitialization(name, expr);
7553+
Walk(expr);
7554+
if (IsNamedConstant(ultimate) || inComponentDecl) {
7555+
NonPointerInitialization(name, expr);
7556+
} else {
7557+
// Defer analysis so forward references to nested subprograms
7558+
// can be properly resolved when they appear in structure
7559+
// constructors.
7560+
ultimate.set(Symbol::Flag::InDataStmt);
7561+
}
75527562
},
75537563
[&](const parser::NullInit &null) { // => NULL()
75547564
Walk(null);
@@ -7569,10 +7579,12 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
75697579
}
75707580
}
75717581
},
7572-
[&](const parser::InitialDataTarget &) {
7582+
[&](const parser::InitialDataTarget &target) {
75737583
// Defer analysis to the end of the specification part
75747584
// so that forward references and attribute checks like SAVE
75757585
// work better.
7586+
auto restorer{common::ScopedSet(deferImplicitTyping_, true)};
7587+
Walk(target);
75767588
ultimate.set(Symbol::Flag::InDataStmt);
75777589
},
75787590
[&](const std::list<Indirection<parser::DataStmtValue>> &values) {
@@ -7590,12 +7602,27 @@ void DeclarationVisitor::PointerInitialization(
75907602
Symbol &ultimate{name.symbol->GetUltimate()};
75917603
if (!context().HasError(ultimate)) {
75927604
if (IsPointer(ultimate)) {
7593-
if (auto *details{ultimate.detailsIf<ObjectEntityDetails>()}) {
7594-
CHECK(!details->init());
7595-
Walk(target);
7596-
if (MaybeExpr expr{EvaluateExpr(target)}) {
7597-
// Validation is done in declaration checking.
7605+
Walk(target);
7606+
if (MaybeExpr expr{EvaluateExpr(target)}) {
7607+
// Validation is done in declaration checking.
7608+
if (auto *details{ultimate.detailsIf<ObjectEntityDetails>()}) {
7609+
CHECK(!details->init());
75987610
details->set_init(std::move(*expr));
7611+
ultimate.set(Symbol::Flag::InDataStmt, false);
7612+
} else if (auto *details{ultimate.detailsIf<ProcEntityDetails>()}) {
7613+
// something like "REAL, EXTERNAL, POINTER :: p => t"
7614+
if (evaluate::IsNullProcedurePointer(*expr)) {
7615+
CHECK(!details->init());
7616+
details->set_init(nullptr);
7617+
} else if (const Symbol *
7618+
targetSymbol{evaluate::UnwrapWholeSymbolDataRef(*expr)}) {
7619+
CHECK(!details->init());
7620+
details->set_init(*targetSymbol);
7621+
} else {
7622+
Say(name,
7623+
"Procedure pointer '%s' must be initialized with a procedure name or NULL()"_err_en_US);
7624+
context().SetError(ultimate);
7625+
}
75997626
}
76007627
}
76017628
} else {
@@ -7635,27 +7662,23 @@ void DeclarationVisitor::PointerInitialization(
76357662

76367663
void DeclarationVisitor::NonPointerInitialization(
76377664
const parser::Name &name, const parser::ConstantExpr &expr) {
7638-
if (name.symbol) {
7665+
if (!context().HasError(name.symbol)) {
76397666
Symbol &ultimate{name.symbol->GetUltimate()};
7640-
if (!context().HasError(ultimate) && !context().HasError(name.symbol)) {
7667+
if (!context().HasError(ultimate)) {
76417668
if (IsPointer(ultimate)) {
76427669
Say(name,
76437670
"'%s' is a pointer but is not initialized like one"_err_en_US);
76447671
} else if (auto *details{ultimate.detailsIf<ObjectEntityDetails>()}) {
7645-
CHECK(!details->init());
7646-
if (IsAllocatable(ultimate)) {
7672+
if (details->init()) {
7673+
} else if (IsAllocatable(ultimate)) {
76477674
Say(name, "Allocatable object '%s' cannot be initialized"_err_en_US);
7648-
return;
7649-
}
7650-
Walk(expr);
7651-
if (ultimate.owner().IsParameterizedDerivedType()) {
7675+
} else if (ultimate.owner().IsParameterizedDerivedType()) {
76527676
// Save the expression for per-instantiation analysis.
76537677
details->set_unanalyzedPDTComponentInit(&expr.thing.value());
7654-
} else {
7655-
if (MaybeExpr folded{EvaluateNonPointerInitializer(
7656-
ultimate, expr, expr.thing.value().source)}) {
7657-
details->set_init(std::move(*folded));
7658-
}
7678+
} else if (MaybeExpr folded{EvaluateNonPointerInitializer(
7679+
ultimate, expr, expr.thing.value().source)}) {
7680+
details->set_init(std::move(*folded));
7681+
ultimate.set(Symbol::Flag::InDataStmt, false);
76597682
}
76607683
} else {
76617684
Say(name, "'%s' is not an object that can be initialized"_err_en_US);
@@ -8424,6 +8447,7 @@ bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
84248447
ResolveSpecificationParts(root);
84258448
FinishSpecificationParts(root);
84268449
ResolveExecutionParts(root);
8450+
FinishExecutionParts(root);
84278451
ResolveAccParts(context(), x);
84288452
ResolveOmpParts(context(), x);
84298453
return false;
@@ -8841,6 +8865,8 @@ class DeferredCheckVisitor {
88418865
}
88428866
}
88438867

8868+
bool Pre(const parser::BlockConstruct &x) { return true; }
8869+
88448870
void Post(const parser::ProcInterface &pi) {
88458871
if (const auto *name{std::get_if<parser::Name>(&pi.u)}) {
88468872
resolver_.CheckExplicitInterface(*name);
@@ -8871,7 +8897,6 @@ class DeferredCheckVisitor {
88718897
resolver_.CheckBindings(tbps);
88728898
}
88738899
}
8874-
bool Pre(const parser::StmtFunctionStmt &stmtFunc) { return false; }
88758900

88768901
private:
88778902
void Init(const parser::Name &name,
@@ -8880,6 +8905,9 @@ class DeferredCheckVisitor {
88808905
if (const auto *target{
88818906
std::get_if<parser::InitialDataTarget>(&init->u)}) {
88828907
resolver_.PointerInitialization(name, *target);
8908+
} else if (const auto *expr{
8909+
std::get_if<parser::ConstantExpr>(&init->u)}) {
8910+
resolver_.NonPointerInitialization(name, *expr);
88838911
}
88848912
}
88858913
}
@@ -8894,15 +8922,16 @@ void ResolveNamesVisitor::FinishSpecificationParts(const ProgramTree &node) {
88948922
if (!node.scope()) {
88958923
return; // error occurred creating scope
88968924
}
8925+
auto flagRestorer{common::ScopedSet(inSpecificationPart_, true)};
88978926
SetScope(*node.scope());
8898-
// The initializers of pointers, the default initializers of pointer
8899-
// components, non-deferred type-bound procedure bindings have not
8900-
// yet been traversed.
8901-
// We do that now, when any (formerly) forward references that appear
8927+
// The initializers of pointers and non-PARAMETER objects, the default
8928+
// initializers of components, and non-deferred type-bound procedure
8929+
// bindings have not yet been traversed.
8930+
// We do that now, when any forward references that appeared
89028931
// in those initializers will resolve to the right symbols without
8903-
// incurring spurious errors with IMPLICIT NONE.
8932+
// incurring spurious errors with IMPLICIT NONE or forward references
8933+
// to nested subprograms.
89048934
DeferredCheckVisitor{*this}.Walk(node.spec());
8905-
DeferredCheckVisitor{*this}.Walk(node.exec()); // for BLOCK
89068935
for (Scope &childScope : currScope().children()) {
89078936
if (childScope.IsParameterizedDerivedTypeInstantiation()) {
89088937
FinishDerivedTypeInstantiation(childScope);
@@ -8913,6 +8942,18 @@ void ResolveNamesVisitor::FinishSpecificationParts(const ProgramTree &node) {
89138942
}
89148943
}
89158944

8945+
void ResolveNamesVisitor::FinishExecutionParts(const ProgramTree &node) {
8946+
if (node.scope()) {
8947+
SetScope(*node.scope());
8948+
if (node.exec()) {
8949+
DeferredCheckVisitor{*this}.Walk(*node.exec());
8950+
}
8951+
for (const auto &child : node.children()) {
8952+
FinishExecutionParts(child);
8953+
}
8954+
}
8955+
}
8956+
89168957
// Duplicate and fold component object pointer default initializer designators
89178958
// using the actual type parameter values of each particular instantiation.
89188959
// Validation is done later in declaration checking.

flang/test/Semantics/bad-forward-type.f90

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ subroutine s9
8484
type con
8585
Type(t(3)), pointer :: y
8686
end type
87-
!ERROR: Cannot construct value for derived type 't' before it is defined
8887
Integer :: nn = Size(Transfer(t(3)(666),[0]))
8988
type :: t(n)
9089
integer, kind :: n = 3

flang/test/Semantics/init01.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ subroutine components(n)
9090
real, pointer :: p10 => o3%x
9191
associate (a1 => o3, a2 => o3%x)
9292
block
93-
real, pointer :: p11 => a1
93+
type(t3), pointer :: p11 => a1
9494
real, pointer :: p12 => a2
9595
end block
9696
end associate

flang/test/Semantics/pointer01.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ program main
1616
!ERROR: 'inner' cannot have the POINTER attribute
1717
pointer inner
1818
real obj
19+
!ERROR: 'ip' is a pointer but is not initialized like one
1920
!ERROR: 'ip' may not have both the POINTER and PARAMETER attributes
2021
integer, parameter :: ip = 123
2122
pointer ip

flang/test/Semantics/symbol15.f90

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ subroutine iface
1414
!DEF: /m/op2 POINTER, PUBLIC ObjectEntity REAL(4)
1515
!DEF: /m/null INTRINSIC, PUBLIC, PURE (Function) ProcEntity
1616
real, pointer :: op2 => null()
17-
!DEF: /m/op3 POINTER, PUBLIC (InDataStmt) ObjectEntity REAL(4)
17+
!DEF: /m/op3 POINTER, PUBLIC ObjectEntity REAL(4)
1818
!DEF: /m/x PUBLIC, TARGET ObjectEntity REAL(4)
1919
real, pointer :: op3 => x
20-
!DEF: /m/op4 POINTER, PUBLIC (InDataStmt) ObjectEntity REAL(4)
20+
!DEF: /m/op4 POINTER, PUBLIC ObjectEntity REAL(4)
2121
!DEF: /m/y PUBLIC, TARGET ObjectEntity REAL(4)
2222
real, pointer :: op4 => y(1)
2323
!REF: /m/iface
@@ -50,10 +50,10 @@ subroutine iface
5050
!DEF: /m/t1/opc2 POINTER ObjectEntity REAL(4)
5151
!REF: /m/null
5252
real, pointer :: opc2 => null()
53-
!DEF: /m/t1/opc3 POINTER (InDataStmt) ObjectEntity REAL(4)
53+
!DEF: /m/t1/opc3 POINTER ObjectEntity REAL(4)
5454
!REF: /m/x
5555
real, pointer :: opc3 => x
56-
!DEF: /m/t1/opc4 POINTER (InDataStmt) ObjectEntity REAL(4)
56+
!DEF: /m/t1/opc4 POINTER ObjectEntity REAL(4)
5757
!REF: /m/y
5858
real, pointer :: opc4 => y(1)
5959
!REF: /m/iface
@@ -100,10 +100,10 @@ subroutine iface
100100
!DEF: /m/pdt1/opc2 POINTER ObjectEntity REAL(4)
101101
!REF: /m/null
102102
real, pointer :: opc2 => null()
103-
!DEF: /m/pdt1/opc3 POINTER (InDataStmt) ObjectEntity REAL(4)
103+
!DEF: /m/pdt1/opc3 POINTER ObjectEntity REAL(4)
104104
!REF: /m/x
105105
real, pointer :: opc3 => x
106-
!DEF: /m/pdt1/opc4 POINTER (InDataStmt) ObjectEntity REAL(4)
106+
!DEF: /m/pdt1/opc4 POINTER ObjectEntity REAL(4)
107107
!REF: /m/y
108108
!REF: /m/pdt1/k
109109
real, pointer :: opc4 => y(k)
@@ -160,10 +160,10 @@ subroutine iface
160160
subroutine ext2
161161
end subroutine
162162
end interface
163-
!DEF: /m/op10 POINTER, PUBLIC(InDataStmt) ObjectEntity REAL(4)
163+
!DEF: /m/op10 POINTER, PUBLIC ObjectEntity REAL(4)
164164
!REF: /m/x
165165
real, pointer :: op10 => x
166-
!DEF: /m/op11 POINTER, PUBLIC(InDataStmt) ObjectEntity REAL(4)
166+
!DEF: /m/op11 POINTER, PUBLIC ObjectEntity REAL(4)
167167
!REF: /m/y
168168
real, pointer :: op11 => y(1)
169169
!REF: /m/iface
@@ -176,10 +176,10 @@ subroutine ext2
176176
procedure(iface), pointer :: pp11 => ext2
177177
!DEF: /m/t2 PUBLIC DerivedType
178178
type :: t2
179-
!DEF: /m/t2/opc10 POINTER (InDataStmt) ObjectEntity REAL(4)
179+
!DEF: /m/t2/opc10 POINTER ObjectEntity REAL(4)
180180
!REF: /m/x
181181
real, pointer :: opc10 => x
182-
!DEF: /m/t2/opc11 POINTER (InDataStmt) ObjectEntity REAL(4)
182+
!DEF: /m/t2/opc11 POINTER ObjectEntity REAL(4)
183183
!REF: /m/y
184184
real, pointer :: opc11 => y(1)
185185
!REF: /m/iface
@@ -203,10 +203,10 @@ subroutine ext2
203203
type :: pdt2(k)
204204
!REF: /m/pdt2/k
205205
integer, kind :: k
206-
!DEF: /m/pdt2/opc10 POINTER (InDataStmt) ObjectEntity REAL(4)
206+
!DEF: /m/pdt2/opc10 POINTER ObjectEntity REAL(4)
207207
!REF: /m/x
208208
real, pointer :: opc10 => x
209-
!DEF: /m/pdt2/opc11 POINTER (InDataStmt) ObjectEntity REAL(4)
209+
!DEF: /m/pdt2/opc11 POINTER ObjectEntity REAL(4)
210210
!REF: /m/y
211211
!REF: /m/pdt2/k
212212
real, pointer :: opc11 => y(k)

0 commit comments

Comments
 (0)