Skip to content

Commit e02b518

Browse files
committed
[flang] Process legacy DATA-style /initializers/ sooner
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 a4015d9 commit e02b518

File tree

5 files changed

+109
-51
lines changed

5 files changed

+109
-51
lines changed

flang/lib/Semantics/check-data.cpp

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -257,29 +257,6 @@ 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) {
263-
if (const auto &init{
264-
std::get<std::optional<parser::Initialization>>(decl.t)}) {
265-
const Symbol *name{std::get<parser::Name>(decl.t).symbol};
266-
const auto *list{
267-
std::get_if<std::list<common::Indirection<parser::DataStmtValue>>>(
268-
&init->u)};
269-
if (name && list) {
270-
AccumulateDataInitializations(inits_, exprAnalyzer_, *name, *list);
271-
}
272-
}
273-
}
274-
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-
283260
void DataChecker::CompileDataInitializationsIntoInitializers() {
284261
ConvertToInitializers(inits_, exprAnalyzer_);
285262
}

flang/lib/Semantics/check-data.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ 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 &);
42-
void Leave(const parser::EntityDecl &);
43-
4440
// After all DATA statements have been processed, converts their
4541
// initializations into per-symbol static initializers.
4642
void CompileDataInitializationsIntoInitializers();

flang/lib/Semantics/resolve-names.cpp

Lines changed: 80 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"
@@ -1081,8 +1082,12 @@ class DeclarationVisitor : public ArraySpecVisitor,
10811082
const parser::Name &, const parser::InitialDataTarget &);
10821083
void PointerInitialization(
10831084
const parser::Name &, const parser::ProcPointerInit &);
1085+
bool CheckNonPointerInitialization(
1086+
const parser::Name &, bool inLegacyDataInitialization);
10841087
void NonPointerInitialization(
10851088
const parser::Name &, const parser::ConstantExpr &);
1089+
void LegacyDataInitialization(const parser::Name &,
1090+
const std::list<common::Indirection<parser::DataStmtValue>> &values);
10861091
void CheckExplicitInterface(const parser::Name &);
10871092
void CheckBindings(const parser::TypeBoundProcedureStmt::WithoutInterface &);
10881093

@@ -8995,6 +9000,14 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
89959000
ultimate.set(Symbol::Flag::InDataStmt);
89969001
}
89979002
},
9003+
[&](const std::list<Indirection<parser::DataStmtValue>> &values) {
9004+
Walk(values);
9005+
if (inComponentDecl) {
9006+
LegacyDataInitialization(name, values);
9007+
} else {
9008+
ultimate.set(Symbol::Flag::InDataStmt);
9009+
}
9010+
},
89989011
[&](const parser::NullInit &null) { // => NULL()
89999012
Walk(null);
90009013
if (auto nullInit{EvaluateExpr(null)}) {
@@ -9028,11 +9041,6 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
90289041
ultimate.set(Symbol::Flag::InDataStmt);
90299042
}
90309043
},
9031-
[&](const std::list<Indirection<parser::DataStmtValue>> &values) {
9032-
// Handled later in data-to-inits conversion
9033-
ultimate.set(Symbol::Flag::InDataStmt);
9034-
Walk(values);
9035-
},
90369044
},
90379045
init.u);
90389046
}
@@ -9103,36 +9111,82 @@ void DeclarationVisitor::PointerInitialization(
91039111
}
91049112
}
91059113

9106-
void DeclarationVisitor::NonPointerInitialization(
9107-
const parser::Name &name, const parser::ConstantExpr &expr) {
9114+
bool DeclarationVisitor::CheckNonPointerInitialization(
9115+
const parser::Name &name, bool inLegacyDataInitialization) {
91089116
if (!context().HasError(name.symbol)) {
91099117
Symbol &ultimate{name.symbol->GetUltimate()};
91109118
if (!context().HasError(ultimate)) {
9111-
if (IsPointer(ultimate)) {
9119+
if (IsPointer(ultimate) && !inLegacyDataInitialization) {
91129120
Say(name,
91139121
"'%s' is a pointer but is not initialized like one"_err_en_US);
91149122
} else if (auto *details{ultimate.detailsIf<ObjectEntityDetails>()}) {
91159123
if (details->init()) {
91169124
SayWithDecl(name, *name.symbol,
91179125
"'%s' has already been initialized"_err_en_US);
9118-
} else if (details->isCDefined()) {
9119-
context().Warn(common::UsageWarning::CdefinedInit, name.source,
9120-
"CDEFINED variable should not have an initializer"_warn_en_US);
91219126
} else if (IsAllocatable(ultimate)) {
91229127
Say(name, "Allocatable object '%s' cannot be initialized"_err_en_US);
9123-
} else if (ultimate.owner().IsParameterizedDerivedType()) {
9124-
// Save the expression for per-instantiation analysis.
9125-
details->set_unanalyzedPDTComponentInit(&expr.thing.value());
9126-
} else if (MaybeExpr folded{EvaluateNonPointerInitializer(
9127-
ultimate, expr, expr.thing.value().source)}) {
9128-
details->set_init(std::move(*folded));
9129-
ultimate.set(Symbol::Flag::InDataStmt, false);
9128+
} else {
9129+
if (details->isCDefined()) {
9130+
context().Warn(common::UsageWarning::CdefinedInit, name.source,
9131+
"CDEFINED variable should not have an initializer"_warn_en_US);
9132+
}
9133+
return true;
91309134
}
91319135
} else {
91329136
Say(name, "'%s' is not an object that can be initialized"_err_en_US);
91339137
}
91349138
}
91359139
}
9140+
return false;
9141+
}
9142+
9143+
void DeclarationVisitor::NonPointerInitialization(
9144+
const parser::Name &name, const parser::ConstantExpr &expr) {
9145+
if (CheckNonPointerInitialization(
9146+
name, /*inLegacyDataInitialization=*/false)) {
9147+
Symbol &ultimate{name.symbol->GetUltimate()};
9148+
auto &details{ultimate.get<ObjectEntityDetails>()};
9149+
if (ultimate.owner().IsParameterizedDerivedType()) {
9150+
// Save the expression for per-instantiation analysis.
9151+
details.set_unanalyzedPDTComponentInit(&expr.thing.value());
9152+
} else if (MaybeExpr folded{EvaluateNonPointerInitializer(
9153+
ultimate, expr, expr.thing.value().source)}) {
9154+
details.set_init(std::move(*folded));
9155+
ultimate.set(Symbol::Flag::InDataStmt, false);
9156+
}
9157+
}
9158+
}
9159+
9160+
void DeclarationVisitor::LegacyDataInitialization(const parser::Name &name,
9161+
const std::list<common::Indirection<parser::DataStmtValue>> &values) {
9162+
if (CheckNonPointerInitialization(
9163+
name, /*inLegacyDataInitialization=*/true)) {
9164+
Symbol &ultimate{name.symbol->GetUltimate()};
9165+
if (ultimate.owner().IsParameterizedDerivedType()) {
9166+
Say(name,
9167+
"Component '%s' in a parameterized data type may not be initialized with a legacy DATA-style value list"_err_en_US,
9168+
name.source);
9169+
} else {
9170+
evaluate::ExpressionAnalyzer exprAnalyzer{context()};
9171+
for (const auto &value : values) {
9172+
exprAnalyzer.Analyze(value.value());
9173+
}
9174+
DataInitializations inits;
9175+
auto oldSize{ultimate.size()};
9176+
if (auto chars{evaluate::characteristics::TypeAndShape::Characterize(
9177+
ultimate, GetFoldingContext())}) {
9178+
if (auto size{evaluate::ToInt64(
9179+
chars->MeasureSizeInBytes(GetFoldingContext()))}) {
9180+
// Temporarily set the byte size of the component so that we don't
9181+
// get bogus "initialization out of range" errors below.
9182+
ultimate.set_size(*size);
9183+
}
9184+
}
9185+
AccumulateDataInitializations(inits, exprAnalyzer, ultimate, values);
9186+
ConvertToInitializers(inits, exprAnalyzer);
9187+
ultimate.set_size(oldSize);
9188+
}
9189+
}
91369190
}
91379191

91389192
void ResolveNamesVisitor::HandleCall(
@@ -10482,12 +10536,15 @@ class DeferredCheckVisitor {
1048210536
if (const auto *target{
1048310537
std::get_if<parser::InitialDataTarget>(&init->u)}) {
1048410538
resolver_.PointerInitialization(name, *target);
10485-
} else if (const auto *expr{
10486-
std::get_if<parser::ConstantExpr>(&init->u)}) {
10487-
if (name.symbol) {
10488-
if (const auto *object{name.symbol->detailsIf<ObjectEntityDetails>()};
10489-
!object || !object->init()) {
10539+
} else if (name.symbol) {
10540+
if (const auto *object{name.symbol->detailsIf<ObjectEntityDetails>()};
10541+
!object || !object->init()) {
10542+
if (const auto *expr{std::get_if<parser::ConstantExpr>(&init->u)}) {
1049010543
resolver_.NonPointerInitialization(name, *expr);
10544+
} else if (const auto *values{std::get_if<
10545+
std::list<common::Indirection<parser::DataStmtValue>>>(
10546+
&init->u)}) {
10547+
resolver_.LegacyDataInitialization(name, *values);
1049110548
}
1049210549
}
1049310550
}

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)