diff options
Diffstat (limited to 'flang/lib/Semantics')
-rw-r--r-- | flang/lib/Semantics/check-call.cpp | 17 | ||||
-rw-r--r-- | flang/lib/Semantics/check-data.cpp | 12 | ||||
-rw-r--r-- | flang/lib/Semantics/check-data.h | 3 | ||||
-rw-r--r-- | flang/lib/Semantics/check-declarations.cpp | 5 | ||||
-rw-r--r-- | flang/lib/Semantics/check-omp-structure.cpp | 2 | ||||
-rw-r--r-- | flang/lib/Semantics/expression.cpp | 36 | ||||
-rw-r--r-- | flang/lib/Semantics/resolve-names.cpp | 150 | ||||
-rw-r--r-- | flang/lib/Semantics/symbol.cpp | 5 | ||||
-rw-r--r-- | flang/lib/Semantics/type.cpp | 42 |
9 files changed, 199 insertions, 73 deletions
diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp index 81c53aa..e4d2a0d 100644 --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -185,7 +185,8 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual, } else if (static_cast<std::size_t>(actualOffset->offset()) >= actualOffset->symbol().size() || !evaluate::IsContiguous( - actualOffset->symbol(), foldingContext)) { + actualOffset->symbol(), foldingContext) + .value_or(false)) { // If substring, take rest of substring if (*actualLength > 0) { actualChars -= @@ -598,7 +599,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy, context.IsEnabled( common::LanguageFeature::ContiguousOkForSeqAssociation) && actualLastSymbol && - evaluate::IsContiguous(*actualLastSymbol, foldingContext)}; + evaluate::IsContiguous(*actualLastSymbol, foldingContext) + .value_or(false)}; if (actualIsArrayElement && actualLastSymbol && !dummy.ignoreTKR.test(common::IgnoreTKR::Contiguous)) { if (IsPointer(*actualLastSymbol)) { @@ -663,7 +665,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy, } else if (static_cast<std::size_t>(actualOffset->offset()) >= actualOffset->symbol().size() || !evaluate::IsContiguous( - actualOffset->symbol(), foldingContext)) { + actualOffset->symbol(), foldingContext) + .value_or(false)) { actualElements = 1; } else if (auto actualSymType{evaluate::DynamicType::From( actualOffset->symbol())}) { @@ -1566,10 +1569,10 @@ static bool CheckElementalConformance(parser::ContextualMessages &messages, ") corresponding to dummy argument #" + std::to_string(index) + " ('" + dummy.name + "')"}; if (shape) { - auto tristate{evaluate::CheckConformance(messages, *shape, - *argShape, evaluate::CheckConformanceFlags::None, - shapeName.c_str(), argName.c_str())}; - if (tristate && !*tristate) { + if (!evaluate::CheckConformance(messages, *shape, *argShape, + evaluate::CheckConformanceFlags::None, shapeName.c_str(), + argName.c_str()) + .value_or(true)) { return false; } } else { diff --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp index d6f1351..5459290 100644 --- a/flang/lib/Semantics/check-data.cpp +++ b/flang/lib/Semantics/check-data.cpp @@ -257,9 +257,7 @@ void DataChecker::Leave(const parser::DataStmtSet &set) { currentSetHasFatalErrors_ = false; } -// Handle legacy DATA-style initialization, e.g. REAL PI/3.14159/, for -// variables and components (esp. for DEC STRUCTUREs) -template <typename A> void DataChecker::LegacyDataInit(const A &decl) { +void DataChecker::Leave(const parser::EntityDecl &decl) { if (const auto &init{ std::get<std::optional<parser::Initialization>>(decl.t)}) { const Symbol *name{std::get<parser::Name>(decl.t).symbol}; @@ -272,14 +270,6 @@ template <typename A> void DataChecker::LegacyDataInit(const A &decl) { } } -void DataChecker::Leave(const parser::ComponentDecl &decl) { - LegacyDataInit(decl); -} - -void DataChecker::Leave(const parser::EntityDecl &decl) { - LegacyDataInit(decl); -} - void DataChecker::CompileDataInitializationsIntoInitializers() { ConvertToInitializers(inits_, exprAnalyzer_); } diff --git a/flang/lib/Semantics/check-data.h b/flang/lib/Semantics/check-data.h index 479d325..8cd2ac9 100644 --- a/flang/lib/Semantics/check-data.h +++ b/flang/lib/Semantics/check-data.h @@ -37,10 +37,7 @@ public: void Enter(const parser::DataImpliedDo &); void Leave(const parser::DataImpliedDo &); void Leave(const parser::DataStmtSet &); - // These cases are for legacy DATA-like /initializations/ - void Leave(const parser::ComponentDecl &); void Leave(const parser::EntityDecl &); - // After all DATA statements have been processed, converts their // initializations into per-symbol static initializers. void CompileDataInitializationsIntoInitializers(); diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp index 7593424..ea5e2c0 100644 --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -1984,9 +1984,8 @@ bool CheckHelper::CheckDistinguishableFinals(const Symbol &f1, const Procedure *p1{Characterize(f1)}; const Procedure *p2{Characterize(f2)}; if (p1 && p2) { - std::optional<bool> areDistinct{characteristics::Distinguishable( - context_.languageFeatures(), *p1, *p2)}; - if (areDistinct.value_or(false)) { + if (characteristics::Distinguishable(context_.languageFeatures(), *p1, *p2) + .value_or(false)) { return true; } if (auto *msg{messages_.Say(f1Name, diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index c0c41c1..d65a89e 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -5085,7 +5085,7 @@ void OmpStructureChecker::CheckWorkdistributeBlockStmts( } void OmpStructureChecker::CheckIfContiguous(const parser::OmpObject &object) { - if (auto contig{IsContiguous(context_, object)}; contig && !*contig) { + if (!IsContiguous(context_, object).value_or(true)) { // known discontiguous const parser::Name *name{GetObjectName(object)}; assert(name && "Expecting name component"); context_.Say(name->source, diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index fc26888..2feec98 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2171,17 +2171,29 @@ MaybeExpr ExpressionAnalyzer::CheckStructureConstructor( // T(1) or T(PT=PT(1)). There may be multiple parent components. if (nextAnonymous == components.begin() && parentComponent && valueType && context().IsEnabled(LanguageFeature::AnonymousParents)) { - for (auto parent{components.begin()}; - parent != afterLastParentComponentIter; ++parent) { - if (auto parentType{DynamicType::From(*parent)}; parentType && - parent->test(Symbol::Flag::ParentComp) && - valueType->IsEquivalentTo(*parentType)) { - symbol = &*parent; - nextAnonymous = ++parent; - Warn(LanguageFeature::AnonymousParents, source, - "Whole parent component '%s' in structure constructor should not be anonymous"_port_en_US, - symbol->name()); - break; + auto parent{components.begin()}; + if (!parent->test(Symbol::Flag::ParentComp)) { + // Ensure that the first value can't initialize the first actual + // component. + if (auto firstComponentType{DynamicType::From(*parent)}) { + if (firstComponentType->IsTkCompatibleWith(*valueType) && + value.Rank() == parent->Rank()) { + parent = afterLastParentComponentIter; // skip next loop + } + } + } + for (; parent != afterLastParentComponentIter; ++parent) { + if (auto parentType{DynamicType::From(*parent)}) { + if (parent->test(Symbol::Flag::ParentComp) && + valueType->IsEquivalentTo(*parentType) && + value.Rank() == 0 /* scalar only */) { + symbol = &*parent; + nextAnonymous = ++parent; + Warn(LanguageFeature::AnonymousParents, source, + "Whole parent component '%s' in structure constructor should not be anonymous"_port_en_US, + symbol->name()); + break; + } } } } @@ -2317,7 +2329,7 @@ MaybeExpr ExpressionAnalyzer::CheckStructureConstructor( auto checked{CheckConformance(messages, *componentShape, *valueShape, CheckConformanceFlags::RightIsExpandableDeferred, "component", "value")}; - if (checked && *checked && GetRank(*componentShape) > 0 && + if (checked.value_or(false) && GetRank(*componentShape) > 0 && GetRank(*valueShape) == 0 && (IsDeferredShape(*symbol) || !IsExpandableScalar(*converted, foldingContext, 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. } } } diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp index 6152f61..69169469 100644 --- a/flang/lib/Semantics/symbol.cpp +++ b/flang/lib/Semantics/symbol.cpp @@ -769,6 +769,11 @@ void DerivedTypeDetails::add_component(const Symbol &symbol) { componentNames_.push_back(symbol.name()); } +void DerivedTypeDetails::add_originalKindParameter( + SourceName name, const parser::Expr *expr) { + originalKindParameterMap_.emplace(name, expr); +} + const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const { if (auto extends{GetParentComponentName()}) { if (auto iter{scope.find(*extends)}; iter != scope.cend()) { diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp index 69e6ffa..dba15e6 100644 --- a/flang/lib/Semantics/type.cpp +++ b/flang/lib/Semantics/type.cpp @@ -443,9 +443,9 @@ void InstantiateHelper::InstantiateComponents(const Scope &fromScope) { // Walks a parsed expression to prepare it for (re)analysis; // clears out the typedExpr analysis results and re-resolves // symbol table pointers of type parameters. -class ComponentInitResetHelper { +class ResetHelper { public: - explicit ComponentInitResetHelper(Scope &scope) : scope_{scope} {} + explicit ResetHelper(Scope &scope) : scope_{scope} {} template <typename A> bool Pre(const A &) { return true; } @@ -498,7 +498,7 @@ void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) { } if (const auto *parsedExpr{details->unanalyzedPDTComponentInit()}) { // Analyze the parsed expression in this PDT instantiation context. - ComponentInitResetHelper resetter{scope_}; + ResetHelper resetter{scope_}; parser::Walk(*parsedExpr, resetter); auto restorer{foldingContext().messages().SetLocation(newSymbol.name())}; details->set_init(evaluate::Fold( @@ -564,16 +564,44 @@ static ParamValue FoldCharacterLength(evaluate::FoldingContext &foldingContext, // Apply type parameter values to an intrinsic type spec. const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType( SourceName symbolName, const DeclTypeSpec &spec) { + const parser::Expr *originalKindExpr{nullptr}; + if (const DerivedTypeSpec *derived{scope_.derivedTypeSpec()}) { + if (const auto *details{derived->originalTypeSymbol() + .GetUltimate() + .detailsIf<DerivedTypeDetails>()}) { + const auto &originalKindMap{details->originalKindParameterMap()}; + if (auto iter{originalKindMap.find(symbolName)}; + iter != originalKindMap.end()) { + originalKindExpr = iter->second; + } + } + } const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())}; - if (spec.category() != DeclTypeSpec::Character && + if (spec.category() != DeclTypeSpec::Character && !originalKindExpr && evaluate::IsActuallyConstant(intrinsic.kind())) { return spec; // KIND is already a known constant } // The expression was not originally constant, but now it must be so // in the context of a parameterized derived type instantiation. - KindExpr copy{Fold(common::Clone(intrinsic.kind()))}; + std::optional<KindExpr> kindExpr; + if (originalKindExpr) { + ResetHelper resetter{scope_}; + parser::Walk(*originalKindExpr, resetter); + auto restorer{foldingContext().messages().DiscardMessages()}; + if (MaybeExpr analyzed{AnalyzeExpr(scope_.context(), *originalKindExpr)}) { + if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*analyzed)}) { + kindExpr = evaluate::ConvertToType<evaluate::SubscriptInteger>( + std::move(*intExpr)); + } + } + } + if (!kindExpr) { + kindExpr = KindExpr{intrinsic.kind()}; + CHECK(kindExpr.has_value()); + } + KindExpr folded{Fold(std::move(*kindExpr))}; int kind{context().GetDefaultKind(intrinsic.category())}; - if (auto value{evaluate::ToInt64(copy)}) { + if (auto value{evaluate::ToInt64(folded)}) { if (foldingContext().targetCharacteristics().IsTypeEnabled( intrinsic.category(), *value)) { kind = *value; @@ -586,7 +614,7 @@ const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType( } else { std::string exprString; llvm::raw_string_ostream sstream(exprString); - copy.AsFortran(sstream); + folded.AsFortran(sstream); foldingContext().messages().Say(symbolName, "KIND parameter expression (%s) of intrinsic type %s did not resolve to a constant value"_err_en_US, exprString, |