aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Semantics/resolve-names.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Semantics/resolve-names.cpp')
-rw-r--r--flang/lib/Semantics/resolve-names.cpp150
1 files changed, 121 insertions, 29 deletions
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index b7c7603d..86121880 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -7,6 +7,7 @@
#include "resolve-names.h"
#include "assignment.h"
+#include "data-to-inits.h"
#include "definable.h"
#include "mod-file.h"
#include "pointer-assignment.h"
@@ -357,6 +358,7 @@ protected:
DeclTypeSpec::Category category{DeclTypeSpec::TypeDerived};
} derived;
bool allowForwardReferenceToDerivedType{false};
+ const parser::Expr *originalKindParameter{nullptr};
};
bool allowForwardReferenceToDerivedType() const {
@@ -365,8 +367,10 @@ protected:
void set_allowForwardReferenceToDerivedType(bool yes) {
state_.allowForwardReferenceToDerivedType = yes;
}
+ void set_inPDTDefinition(bool yes) { inPDTDefinition_ = yes; }
- const DeclTypeSpec *GetDeclTypeSpec();
+ const DeclTypeSpec *GetDeclTypeSpec() const;
+ const parser::Expr *GetOriginalKindParameter() const;
void BeginDeclTypeSpec();
void EndDeclTypeSpec();
void SetDeclTypeSpec(const DeclTypeSpec &);
@@ -380,6 +384,7 @@ protected:
private:
State state_;
+ bool inPDTDefinition_{false};
void MakeNumericType(TypeCategory, int kind);
};
@@ -1081,8 +1086,12 @@ public:
const parser::Name &, const parser::InitialDataTarget &);
void PointerInitialization(
const parser::Name &, const parser::ProcPointerInit &);
+ bool CheckNonPointerInitialization(
+ const parser::Name &, bool inLegacyDataInitialization);
void NonPointerInitialization(
const parser::Name &, const parser::ConstantExpr &);
+ void LegacyDataInitialization(const parser::Name &,
+ const std::list<common::Indirection<parser::DataStmtValue>> &values);
void CheckExplicitInterface(const parser::Name &);
void CheckBindings(const parser::TypeBoundProcedureStmt::WithoutInterface &);
@@ -2454,9 +2463,12 @@ bool AttrsVisitor::Pre(const common::CUDADataAttr x) {
// DeclTypeSpecVisitor implementation
-const DeclTypeSpec *DeclTypeSpecVisitor::GetDeclTypeSpec() {
+const DeclTypeSpec *DeclTypeSpecVisitor::GetDeclTypeSpec() const {
return state_.declTypeSpec;
}
+const parser::Expr *DeclTypeSpecVisitor::GetOriginalKindParameter() const {
+ return state_.originalKindParameter;
+}
void DeclTypeSpecVisitor::BeginDeclTypeSpec() {
CHECK(!state_.expectDeclTypeSpec);
@@ -2541,6 +2553,21 @@ void DeclTypeSpecVisitor::SetDeclTypeSpec(const DeclTypeSpec &declTypeSpec) {
KindExpr DeclTypeSpecVisitor::GetKindParamExpr(
TypeCategory category, const std::optional<parser::KindSelector> &kind) {
+ if (inPDTDefinition_) {
+ if (category != TypeCategory::Derived && kind) {
+ if (const auto *expr{
+ std::get_if<parser::ScalarIntConstantExpr>(&kind->u)}) {
+ CHECK(!state_.originalKindParameter);
+ // Save a pointer to the KIND= expression in the parse tree
+ // in case we need to reanalyze it during PDT instantiation.
+ state_.originalKindParameter = &expr->thing.thing.thing.value();
+ }
+ }
+ // Inhibit some errors now that will be caught later during instantiations.
+ auto restorer{
+ context().foldingContext().AnalyzingPDTComponentKindSelector()};
+ return AnalyzeKindSelector(context(), category, kind);
+ }
return AnalyzeKindSelector(context(), category, kind);
}
@@ -6410,6 +6437,7 @@ bool DeclarationVisitor::Pre(const parser::DerivedTypeDef &x) {
details.set_isForwardReferenced(false);
derivedTypeInfo_ = {};
PopScope();
+ set_inPDTDefinition(false);
return false;
}
@@ -6437,6 +6465,10 @@ void DeclarationVisitor::Post(const parser::DerivedTypeStmt &x) {
// component without producing spurious errors about already
// existing.
const Symbol &extendsSymbol{extendsType->typeSymbol()};
+ if (extendsSymbol.scope() &&
+ extendsSymbol.scope()->IsParameterizedDerivedType()) {
+ set_inPDTDefinition(true);
+ }
auto restorer{common::ScopedSet(extendsName->symbol, nullptr)};
if (OkToAddComponent(*extendsName, &extendsSymbol)) {
auto &comp{DeclareEntity<ObjectEntityDetails>(*extendsName, Attrs{})};
@@ -6455,8 +6487,12 @@ void DeclarationVisitor::Post(const parser::DerivedTypeStmt &x) {
}
// Create symbols now for type parameters so that they shadow names
// from the enclosing specification part.
+ const auto &paramNames{std::get<std::list<parser::Name>>(x.t)};
+ if (!paramNames.empty()) {
+ set_inPDTDefinition(true);
+ }
if (auto *details{symbol.detailsIf<DerivedTypeDetails>()}) {
- for (const auto &name : std::get<std::list<parser::Name>>(x.t)) {
+ for (const auto &name : paramNames) {
if (Symbol * symbol{MakeTypeSymbol(name, TypeParamDetails{})}) {
details->add_paramNameOrder(*symbol);
}
@@ -6544,8 +6580,7 @@ void DeclarationVisitor::Post(const parser::ComponentDecl &x) {
if (const auto *derived{declType->AsDerived()}) {
if (!attrs.HasAny({Attr::POINTER, Attr::ALLOCATABLE})) {
if (derivedTypeInfo_.type == &derived->typeSymbol()) { // C744
- Say("Recursive use of the derived type requires "
- "POINTER or ALLOCATABLE"_err_en_US);
+ Say("Recursive use of the derived type requires POINTER or ALLOCATABLE"_err_en_US);
}
}
}
@@ -6558,7 +6593,11 @@ void DeclarationVisitor::Post(const parser::ComponentDecl &x) {
Initialization(name, *init, /*inComponentDecl=*/true);
}
}
- currScope().symbol()->get<DerivedTypeDetails>().add_component(symbol);
+ auto &details{currScope().symbol()->get<DerivedTypeDetails>()};
+ details.add_component(symbol);
+ if (const parser::Expr *kindExpr{GetOriginalKindParameter()}) {
+ details.add_originalKindParameter(name.source, kindExpr);
+ }
}
ClearArraySpec();
ClearCoarraySpec();
@@ -8995,6 +9034,14 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
ultimate.set(Symbol::Flag::InDataStmt);
}
},
+ [&](const std::list<Indirection<parser::DataStmtValue>> &values) {
+ Walk(values);
+ if (inComponentDecl) {
+ LegacyDataInitialization(name, values);
+ } else {
+ ultimate.set(Symbol::Flag::InDataStmt);
+ }
+ },
[&](const parser::NullInit &null) { // => NULL()
Walk(null);
if (auto nullInit{EvaluateExpr(null)}) {
@@ -9028,11 +9075,6 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
ultimate.set(Symbol::Flag::InDataStmt);
}
},
- [&](const std::list<Indirection<parser::DataStmtValue>> &values) {
- // Handled later in data-to-inits conversion
- ultimate.set(Symbol::Flag::InDataStmt);
- Walk(values);
- },
},
init.u);
}
@@ -9103,36 +9145,82 @@ void DeclarationVisitor::PointerInitialization(
}
}
-void DeclarationVisitor::NonPointerInitialization(
- const parser::Name &name, const parser::ConstantExpr &expr) {
+bool DeclarationVisitor::CheckNonPointerInitialization(
+ const parser::Name &name, bool inLegacyDataInitialization) {
if (!context().HasError(name.symbol)) {
Symbol &ultimate{name.symbol->GetUltimate()};
if (!context().HasError(ultimate)) {
- if (IsPointer(ultimate)) {
+ if (IsPointer(ultimate) && !inLegacyDataInitialization) {
Say(name,
"'%s' is a pointer but is not initialized like one"_err_en_US);
} else if (auto *details{ultimate.detailsIf<ObjectEntityDetails>()}) {
if (details->init()) {
SayWithDecl(name, *name.symbol,
"'%s' has already been initialized"_err_en_US);
- } else if (details->isCDefined()) {
- context().Warn(common::UsageWarning::CdefinedInit, name.source,
- "CDEFINED variable should not have an initializer"_warn_en_US);
} else if (IsAllocatable(ultimate)) {
Say(name, "Allocatable object '%s' cannot be initialized"_err_en_US);
- } else if (ultimate.owner().IsParameterizedDerivedType()) {
- // Save the expression for per-instantiation analysis.
- details->set_unanalyzedPDTComponentInit(&expr.thing.value());
- } else if (MaybeExpr folded{EvaluateNonPointerInitializer(
- ultimate, expr, expr.thing.value().source)}) {
- details->set_init(std::move(*folded));
- ultimate.set(Symbol::Flag::InDataStmt, false);
+ } else {
+ if (details->isCDefined()) {
+ context().Warn(common::UsageWarning::CdefinedInit, name.source,
+ "CDEFINED variable should not have an initializer"_warn_en_US);
+ }
+ return true;
}
} else {
Say(name, "'%s' is not an object that can be initialized"_err_en_US);
}
}
}
+ return false;
+}
+
+void DeclarationVisitor::NonPointerInitialization(
+ const parser::Name &name, const parser::ConstantExpr &expr) {
+ if (CheckNonPointerInitialization(
+ name, /*inLegacyDataInitialization=*/false)) {
+ Symbol &ultimate{name.symbol->GetUltimate()};
+ auto &details{ultimate.get<ObjectEntityDetails>()};
+ if (ultimate.owner().IsParameterizedDerivedType()) {
+ // Save the expression for per-instantiation analysis.
+ details.set_unanalyzedPDTComponentInit(&expr.thing.value());
+ } else if (MaybeExpr folded{EvaluateNonPointerInitializer(
+ ultimate, expr, expr.thing.value().source)}) {
+ details.set_init(std::move(*folded));
+ ultimate.set(Symbol::Flag::InDataStmt, false);
+ }
+ }
+}
+
+void DeclarationVisitor::LegacyDataInitialization(const parser::Name &name,
+ const std::list<common::Indirection<parser::DataStmtValue>> &values) {
+ if (CheckNonPointerInitialization(
+ name, /*inLegacyDataInitialization=*/true)) {
+ Symbol &ultimate{name.symbol->GetUltimate()};
+ if (ultimate.owner().IsParameterizedDerivedType()) {
+ Say(name,
+ "Component '%s' in a parameterized data type may not be initialized with a legacy DATA-style value list"_err_en_US,
+ name.source);
+ } else {
+ evaluate::ExpressionAnalyzer exprAnalyzer{context()};
+ for (const auto &value : values) {
+ exprAnalyzer.Analyze(value.value());
+ }
+ DataInitializations inits;
+ auto oldSize{ultimate.size()};
+ if (auto chars{evaluate::characteristics::TypeAndShape::Characterize(
+ ultimate, GetFoldingContext())}) {
+ if (auto size{evaluate::ToInt64(
+ chars->MeasureSizeInBytes(GetFoldingContext()))}) {
+ // Temporarily set the byte size of the component so that we don't
+ // get bogus "initialization out of range" errors below.
+ ultimate.set_size(*size);
+ }
+ }
+ AccumulateDataInitializations(inits, exprAnalyzer, ultimate, values);
+ ConvertToInitializers(inits, exprAnalyzer);
+ ultimate.set_size(oldSize);
+ }
+ }
}
void ResolveNamesVisitor::HandleCall(
@@ -10482,12 +10570,16 @@ private:
if (const auto *target{
std::get_if<parser::InitialDataTarget>(&init->u)}) {
resolver_.PointerInitialization(name, *target);
- } else if (const auto *expr{
- std::get_if<parser::ConstantExpr>(&init->u)}) {
- if (name.symbol) {
- if (const auto *object{name.symbol->detailsIf<ObjectEntityDetails>()};
- !object || !object->init()) {
+ } else if (name.symbol) {
+ if (const auto *object{name.symbol->detailsIf<ObjectEntityDetails>()};
+ !object || !object->init()) {
+ if (const auto *expr{std::get_if<parser::ConstantExpr>(&init->u)}) {
resolver_.NonPointerInitialization(name, *expr);
+ } else {
+ // Don't check legacy DATA /initialization/ here. Component
+ // initializations will have already been handled, and variable
+ // initializations need to be done in DATA checking so that
+ // EQUIVALENCE storage association can be handled.
}
}
}