diff options
Diffstat (limited to 'flang/lib/Semantics/resolve-names.cpp')
-rw-r--r-- | flang/lib/Semantics/resolve-names.cpp | 150 |
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 ¶mNames{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. } } } |