diff --git a/flang/include/flang/Evaluate/check-expression.h b/flang/include/flang/Evaluate/check-expression.h --- a/flang/include/flang/Evaluate/check-expression.h +++ b/flang/include/flang/Evaluate/check-expression.h @@ -48,6 +48,8 @@ // expressions, including BOZ literals. template bool IsActuallyConstant(const A &); extern template bool IsActuallyConstant(const Expr &); +extern template bool IsActuallyConstant(const Expr &); +extern template bool IsActuallyConstant(const Expr &); // Checks whether an expression is an object designator with // constant addressing and no vector-valued subscript. diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp --- a/flang/lib/Evaluate/check-expression.cpp +++ b/flang/lib/Evaluate/check-expression.cpp @@ -192,6 +192,8 @@ } template bool IsActuallyConstant(const Expr &); +template bool IsActuallyConstant(const Expr &); +template bool IsActuallyConstant(const Expr &); // Object pointer initialization checking predicate IsInitialDataTarget(). // This code determines whether an expression is allowable as the static diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp --- a/flang/lib/Semantics/type.cpp +++ b/flang/lib/Semantics/type.cpp @@ -425,11 +425,28 @@ } } +/// Fold explicit length parameters of character components when the explicit +/// expression is a constant expression (if it only depends on KIND parameters). +/// Do not fold `character(len=pdt_length)`, even if the length parameter is +/// constant in the pdt instantiation, in order to avoid losing the information +/// that the character component is automatic (and must be a descriptor). +static ParamValue FoldCharacterLength(evaluate::FoldingContext &foldingContext, + const CharacterTypeSpec &characterSpec) { + if (const auto &len{characterSpec.length().GetExplicit()}) { + if (evaluate::IsConstantExpr(*len)) { + return ParamValue{evaluate::Fold(foldingContext, common::Clone(*len)), + common::TypeParamAttr::Len}; + } + } + return characterSpec.length(); +} + // Apply type parameter values to an intrinsic type spec. const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType( SourceName symbolName, const DeclTypeSpec &spec) { const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())}; - if (evaluate::ToInt64(intrinsic.kind())) { + if (spec.category() != DeclTypeSpec::Character && + evaluate::IsActuallyConstant(intrinsic.kind())) { return spec; // KIND is already a known constant } // The expression was not originally constant, but now it must be so @@ -454,7 +471,8 @@ return scope_.MakeLogicalType(KindExpr{kind}); case DeclTypeSpec::Character: return scope_.MakeCharacterType( - ParamValue{spec.characterTypeSpec().length()}, KindExpr{kind}); + FoldCharacterLength(foldingContext(), spec.characterTypeSpec()), + KindExpr{kind}); default: CRASH_NO_CASE; } diff --git a/flang/test/Lower/derived-types-kind-params.f90 b/flang/test/Lower/derived-types-kind-params.f90 --- a/flang/test/Lower/derived-types-kind-params.f90 +++ b/flang/test/Lower/derived-types-kind-params.f90 @@ -31,13 +31,13 @@ ! ----------------------------------------------------------------------------- ! CHECK-LABEL: func @_QMmPfoo - ! CHECK-SAME: !fir.ref> + ! CHECK-SAME: !fir.ref> subroutine foo(at) type(t(k2=12)) :: at end subroutine ! CHECK-LABEL: func @_QMmPfoo2 - ! CHECK-SAME: !fir.ref>}>}>> + ! CHECK-SAME: !fir.ref>}>}>> subroutine foo2(at2) type(t2(12, 13)) :: at2 end subroutine diff --git a/flang/test/Semantics/offsets02.f90 b/flang/test/Semantics/offsets02.f90 --- a/flang/test/Semantics/offsets02.f90 +++ b/flang/test/Semantics/offsets02.f90 @@ -52,3 +52,13 @@ !CHECK: d3 size=24 offset=40: type(t(4, 20)) :: x4 end + +subroutine s4 + type t(k) + integer, kind :: k + character(len=k) :: c + end type + type(t(7)) :: x4 + !CHECK: DerivedType scope: size=7 alignment=1 instantiation of t(k=7_4) + !CHECK: c size=7 offset=0: ObjectEntity type: CHARACTER(7_4,1) +end subroutine