Skip to content

Commit 05a3f76

Browse files
authored
[flang] Process legacy DATA-style /initializers/ sooner (#162722)
The compiler can't defer the conversion of legacy DATA-style /initializers/ in component declarations to their init() expressions to the general DATA statement conversion pass, since default component values must be present during structure constructor analysis. So move their conversions into name resolution and handle them at the same times as standard '=' initializers are processed. Avoid any potential problems with type parameters being used as repetition counts or values by disallowing legacy DATA-style initializers in PDTs. Fixes #161989.
1 parent 471ed9a commit 05a3f76

File tree

5 files changed

+111
-38
lines changed

5 files changed

+111
-38
lines changed

flang/lib/Semantics/check-data.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,7 @@ void DataChecker::Leave(const parser::DataStmtSet &set) {
257257
currentSetHasFatalErrors_ = false;
258258
}
259259

260-
// Handle legacy DATA-style initialization, e.g. REAL PI/3.14159/, for
261-
// variables and components (esp. for DEC STRUCTUREs)
262-
template <typename A> void DataChecker::LegacyDataInit(const A &decl) {
260+
void DataChecker::Leave(const parser::EntityDecl &decl) {
263261
if (const auto &init{
264262
std::get<std::optional<parser::Initialization>>(decl.t)}) {
265263
const Symbol *name{std::get<parser::Name>(decl.t).symbol};
@@ -272,14 +270,6 @@ template <typename A> void DataChecker::LegacyDataInit(const A &decl) {
272270
}
273271
}
274272

275-
void DataChecker::Leave(const parser::ComponentDecl &decl) {
276-
LegacyDataInit(decl);
277-
}
278-
279-
void DataChecker::Leave(const parser::EntityDecl &decl) {
280-
LegacyDataInit(decl);
281-
}
282-
283273
void DataChecker::CompileDataInitializationsIntoInitializers() {
284274
ConvertToInitializers(inits_, exprAnalyzer_);
285275
}

flang/lib/Semantics/check-data.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ class DataChecker : public virtual BaseChecker {
3737
void Enter(const parser::DataImpliedDo &);
3838
void Leave(const parser::DataImpliedDo &);
3939
void Leave(const parser::DataStmtSet &);
40-
// These cases are for legacy DATA-like /initializations/
41-
void Leave(const parser::ComponentDecl &);
4240
void Leave(const parser::EntityDecl &);
43-
4441
// After all DATA statements have been processed, converts their
4542
// initializations into per-symbol static initializers.
4643
void CompileDataInitializationsIntoInitializers();

flang/lib/Semantics/resolve-names.cpp

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "resolve-names.h"
99
#include "assignment.h"
10+
#include "data-to-inits.h"
1011
#include "definable.h"
1112
#include "mod-file.h"
1213
#include "pointer-assignment.h"
@@ -1085,8 +1086,12 @@ class DeclarationVisitor : public ArraySpecVisitor,
10851086
const parser::Name &, const parser::InitialDataTarget &);
10861087
void PointerInitialization(
10871088
const parser::Name &, const parser::ProcPointerInit &);
1089+
bool CheckNonPointerInitialization(
1090+
const parser::Name &, bool inLegacyDataInitialization);
10881091
void NonPointerInitialization(
10891092
const parser::Name &, const parser::ConstantExpr &);
1093+
void LegacyDataInitialization(const parser::Name &,
1094+
const std::list<common::Indirection<parser::DataStmtValue>> &values);
10901095
void CheckExplicitInterface(const parser::Name &);
10911096
void CheckBindings(const parser::TypeBoundProcedureStmt::WithoutInterface &);
10921097

@@ -9029,6 +9034,14 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
90299034
ultimate.set(Symbol::Flag::InDataStmt);
90309035
}
90319036
},
9037+
[&](const std::list<Indirection<parser::DataStmtValue>> &values) {
9038+
Walk(values);
9039+
if (inComponentDecl) {
9040+
LegacyDataInitialization(name, values);
9041+
} else {
9042+
ultimate.set(Symbol::Flag::InDataStmt);
9043+
}
9044+
},
90329045
[&](const parser::NullInit &null) { // => NULL()
90339046
Walk(null);
90349047
if (auto nullInit{EvaluateExpr(null)}) {
@@ -9062,11 +9075,6 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
90629075
ultimate.set(Symbol::Flag::InDataStmt);
90639076
}
90649077
},
9065-
[&](const std::list<Indirection<parser::DataStmtValue>> &values) {
9066-
// Handled later in data-to-inits conversion
9067-
ultimate.set(Symbol::Flag::InDataStmt);
9068-
Walk(values);
9069-
},
90709078
},
90719079
init.u);
90729080
}
@@ -9137,36 +9145,82 @@ void DeclarationVisitor::PointerInitialization(
91379145
}
91389146
}
91399147

9140-
void DeclarationVisitor::NonPointerInitialization(
9141-
const parser::Name &name, const parser::ConstantExpr &expr) {
9148+
bool DeclarationVisitor::CheckNonPointerInitialization(
9149+
const parser::Name &name, bool inLegacyDataInitialization) {
91429150
if (!context().HasError(name.symbol)) {
91439151
Symbol &ultimate{name.symbol->GetUltimate()};
91449152
if (!context().HasError(ultimate)) {
9145-
if (IsPointer(ultimate)) {
9153+
if (IsPointer(ultimate) && !inLegacyDataInitialization) {
91469154
Say(name,
91479155
"'%s' is a pointer but is not initialized like one"_err_en_US);
91489156
} else if (auto *details{ultimate.detailsIf<ObjectEntityDetails>()}) {
91499157
if (details->init()) {
91509158
SayWithDecl(name, *name.symbol,
91519159
"'%s' has already been initialized"_err_en_US);
9152-
} else if (details->isCDefined()) {
9153-
context().Warn(common::UsageWarning::CdefinedInit, name.source,
9154-
"CDEFINED variable should not have an initializer"_warn_en_US);
91559160
} else if (IsAllocatable(ultimate)) {
91569161
Say(name, "Allocatable object '%s' cannot be initialized"_err_en_US);
9157-
} else if (ultimate.owner().IsParameterizedDerivedType()) {
9158-
// Save the expression for per-instantiation analysis.
9159-
details->set_unanalyzedPDTComponentInit(&expr.thing.value());
9160-
} else if (MaybeExpr folded{EvaluateNonPointerInitializer(
9161-
ultimate, expr, expr.thing.value().source)}) {
9162-
details->set_init(std::move(*folded));
9163-
ultimate.set(Symbol::Flag::InDataStmt, false);
9162+
} else {
9163+
if (details->isCDefined()) {
9164+
context().Warn(common::UsageWarning::CdefinedInit, name.source,
9165+
"CDEFINED variable should not have an initializer"_warn_en_US);
9166+
}
9167+
return true;
91649168
}
91659169
} else {
91669170
Say(name, "'%s' is not an object that can be initialized"_err_en_US);
91679171
}
91689172
}
91699173
}
9174+
return false;
9175+
}
9176+
9177+
void DeclarationVisitor::NonPointerInitialization(
9178+
const parser::Name &name, const parser::ConstantExpr &expr) {
9179+
if (CheckNonPointerInitialization(
9180+
name, /*inLegacyDataInitialization=*/false)) {
9181+
Symbol &ultimate{name.symbol->GetUltimate()};
9182+
auto &details{ultimate.get<ObjectEntityDetails>()};
9183+
if (ultimate.owner().IsParameterizedDerivedType()) {
9184+
// Save the expression for per-instantiation analysis.
9185+
details.set_unanalyzedPDTComponentInit(&expr.thing.value());
9186+
} else if (MaybeExpr folded{EvaluateNonPointerInitializer(
9187+
ultimate, expr, expr.thing.value().source)}) {
9188+
details.set_init(std::move(*folded));
9189+
ultimate.set(Symbol::Flag::InDataStmt, false);
9190+
}
9191+
}
9192+
}
9193+
9194+
void DeclarationVisitor::LegacyDataInitialization(const parser::Name &name,
9195+
const std::list<common::Indirection<parser::DataStmtValue>> &values) {
9196+
if (CheckNonPointerInitialization(
9197+
name, /*inLegacyDataInitialization=*/true)) {
9198+
Symbol &ultimate{name.symbol->GetUltimate()};
9199+
if (ultimate.owner().IsParameterizedDerivedType()) {
9200+
Say(name,
9201+
"Component '%s' in a parameterized data type may not be initialized with a legacy DATA-style value list"_err_en_US,
9202+
name.source);
9203+
} else {
9204+
evaluate::ExpressionAnalyzer exprAnalyzer{context()};
9205+
for (const auto &value : values) {
9206+
exprAnalyzer.Analyze(value.value());
9207+
}
9208+
DataInitializations inits;
9209+
auto oldSize{ultimate.size()};
9210+
if (auto chars{evaluate::characteristics::TypeAndShape::Characterize(
9211+
ultimate, GetFoldingContext())}) {
9212+
if (auto size{evaluate::ToInt64(
9213+
chars->MeasureSizeInBytes(GetFoldingContext()))}) {
9214+
// Temporarily set the byte size of the component so that we don't
9215+
// get bogus "initialization out of range" errors below.
9216+
ultimate.set_size(*size);
9217+
}
9218+
}
9219+
AccumulateDataInitializations(inits, exprAnalyzer, ultimate, values);
9220+
ConvertToInitializers(inits, exprAnalyzer);
9221+
ultimate.set_size(oldSize);
9222+
}
9223+
}
91709224
}
91719225

91729226
void ResolveNamesVisitor::HandleCall(
@@ -10516,12 +10570,16 @@ class DeferredCheckVisitor {
1051610570
if (const auto *target{
1051710571
std::get_if<parser::InitialDataTarget>(&init->u)}) {
1051810572
resolver_.PointerInitialization(name, *target);
10519-
} else if (const auto *expr{
10520-
std::get_if<parser::ConstantExpr>(&init->u)}) {
10521-
if (name.symbol) {
10522-
if (const auto *object{name.symbol->detailsIf<ObjectEntityDetails>()};
10523-
!object || !object->init()) {
10573+
} else if (name.symbol) {
10574+
if (const auto *object{name.symbol->detailsIf<ObjectEntityDetails>()};
10575+
!object || !object->init()) {
10576+
if (const auto *expr{std::get_if<parser::ConstantExpr>(&init->u)}) {
1052410577
resolver_.NonPointerInitialization(name, *expr);
10578+
} else {
10579+
// Don't check legacy DATA /initialization/ here. Component
10580+
// initializations will have already been handled, and variable
10581+
// initializations need to be done in DATA checking so that
10582+
// EQUIVALENCE storage association can be handled.
1052510583
}
1052610584
}
1052710585
}

flang/test/Semantics/bug161989.f90

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
!RUN: %python %S/test_errors.py %s %flang_fc1
2+
program test
3+
real, target :: x
4+
type t1
5+
integer :: j/1/
6+
real, pointer :: ap/x/
7+
end type
8+
type, extends(t1) :: t2
9+
integer :: k/2/
10+
end type
11+
type t3(k)
12+
integer, kind :: k
13+
!ERROR: Component 'j' in a parameterized data type may not be initialized with a legacy DATA-style value list
14+
integer :: j/3/
15+
end type
16+
type t4
17+
!ERROR: DATA statement set has more values than objects
18+
integer j(1) /4, 5/
19+
end type
20+
type t5
21+
integer uninitialized
22+
end type
23+
type(t2), parameter :: x2 = t2() !ok
24+
integer(kind=merge(1,-1,x2%j==1)) tx2j
25+
integer(kind=merge(2,-1,x2%k==2)) tx2k
26+
!ERROR: Structure constructor lacks a value for component 'uninitialized'
27+
type(t5), parameter :: x5 = t5()
28+
end

flang/test/Semantics/data21.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
! RUN: %flang_fc1 -fdebug-dump-symbols %s 2>&1 | FileCheck %s
22
! Ensure that DATA-like default component initializers work.
3-
! CHECK: j (InDataStmt) size=4 offset=0: ObjectEntity type: INTEGER(4) init:123_4
3+
! CHECK: j size=4 offset=0: ObjectEntity type: INTEGER(4) init:123_4
44
type t
55
integer j/123/
66
end type

0 commit comments

Comments
 (0)