Skip to content

Commit 8c7bf2f

Browse files
committed
[flang] Improve constant folding for type parameter inquiries
We were not folding type parameter inquiries for the form 'var%typeParam' where 'typeParam' was a KIND or LEN type parameter of a derived type and 'var' was a designator of the derived type. I fixed this by adding code to the function 'FoldOperation()' for 'TypeParamInquiry's to handle this case. I also cleaned up the code for the case where there is no designator. In order to make the error messages correctly refer to both the points of declaration and instantiation, I needed to add an argument to the function 'InstantiateIntrinsicType()' for the location of the instantiation. I also changed the formatting of 'TypeParamInquiry' to correctly format this case. I also added tests for both KIND and LEN type parameter inquiries in resolve104.f90. Making these changes revealed an error in resolve89.f90 and caused one of the error messages in assign04.f90 to be different. Differential Revision: https://reviews.llvm.org/D99892
1 parent 0e92cbd commit 8c7bf2f

File tree

6 files changed

+100
-16
lines changed

6 files changed

+100
-16
lines changed

flang/lib/Evaluate/fold-integer.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -658,24 +658,43 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
658658
// Substitute a bare type parameter reference with its value if it has one now
659659
Expr<TypeParamInquiry::Result> FoldOperation(
660660
FoldingContext &context, TypeParamInquiry &&inquiry) {
661-
if (!inquiry.base()) {
661+
std::optional<NamedEntity> base{inquiry.base()};
662+
parser::CharBlock parameterName{inquiry.parameter().name()};
663+
if (base) {
664+
// Handling "designator%typeParam". Get the value of the type parameter
665+
// from the instantiation of the base
666+
if (const semantics::DeclTypeSpec *
667+
declType{base->GetLastSymbol().GetType()}) {
668+
const semantics::DerivedTypeSpec dType{declType->derivedTypeSpec()};
669+
if (const semantics::ParamValue *
670+
paramValue{dType.FindParameter(parameterName)}) {
671+
const semantics::MaybeIntExpr &paramExpr{paramValue->GetExplicit()};
672+
if (paramExpr && IsConstantExpr(*paramExpr)) {
673+
Expr<SomeInteger> intExpr{*paramExpr};
674+
return Fold(context,
675+
ConvertToType<TypeParamInquiry::Result>(std::move(intExpr)));
676+
}
677+
}
678+
}
679+
} else {
662680
// A "bare" type parameter: replace with its value, if that's now known.
663681
if (const auto *pdt{context.pdtInstance()}) {
664682
if (const semantics::Scope * scope{context.pdtInstance()->scope()}) {
665-
auto iter{scope->find(inquiry.parameter().name())};
683+
auto iter{scope->find(parameterName)};
666684
if (iter != scope->end()) {
667685
const Symbol &symbol{*iter->second};
668686
const auto *details{symbol.detailsIf<semantics::TypeParamDetails>()};
669-
if (details && details->init() &&
670-
(details->attr() == common::TypeParamAttr::Kind ||
671-
IsConstantExpr(*details->init()))) {
672-
Expr<SomeInteger> expr{*details->init()};
673-
return Fold(context,
674-
ConvertToType<TypeParamInquiry::Result>(std::move(expr)));
687+
if (details) {
688+
const semantics::MaybeIntExpr &initExpr{details->init()};
689+
if (initExpr && IsConstantExpr(*initExpr)) {
690+
Expr<SomeInteger> expr{*initExpr};
691+
return Fold(context,
692+
ConvertToType<TypeParamInquiry::Result>(std::move(expr)));
693+
}
675694
}
676695
}
677696
}
678-
if (const auto *value{pdt->FindParameter(inquiry.parameter().name())}) {
697+
if (const auto *value{pdt->FindParameter(parameterName)}) {
679698
if (value->isExplicit()) {
680699
return Fold(context,
681700
AsExpr(ConvertToType<TypeParamInquiry::Result>(

flang/lib/Evaluate/formatting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ llvm::raw_ostream &BaseObject::AsFortran(llvm::raw_ostream &o) const {
614614

615615
llvm::raw_ostream &TypeParamInquiry::AsFortran(llvm::raw_ostream &o) const {
616616
if (base_) {
617-
return base_->AsFortran(o) << '%';
617+
base_.value().AsFortran(o) << '%';
618618
}
619619
return EmitVar(o, parameter_);
620620
}

flang/lib/Semantics/type.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ class InstantiateHelper {
205205
}
206206
void InstantiateComponent(const Symbol &);
207207
const DeclTypeSpec *InstantiateType(const Symbol &);
208-
const DeclTypeSpec &InstantiateIntrinsicType(const DeclTypeSpec &);
208+
const DeclTypeSpec &InstantiateIntrinsicType(
209+
SourceName, const DeclTypeSpec &);
209210
DerivedTypeSpec CreateDerivedTypeSpec(const DerivedTypeSpec &, bool);
210211

211212
SemanticsContext &context_;
@@ -364,7 +365,7 @@ const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) {
364365
CreateDerivedTypeSpec(*spec, symbol.test(Symbol::Flag::ParentComp)),
365366
context_, type->category());
366367
} else if (type->AsIntrinsic()) {
367-
return &InstantiateIntrinsicType(*type);
368+
return &InstantiateIntrinsicType(symbol.name(), *type);
368369
} else if (type->category() == DeclTypeSpec::ClassStar) {
369370
return type;
370371
} else {
@@ -374,7 +375,7 @@ const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) {
374375

375376
// Apply type parameter values to an intrinsic type spec.
376377
const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType(
377-
const DeclTypeSpec &spec) {
378+
SourceName symbolName, const DeclTypeSpec &spec) {
378379
const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())};
379380
if (evaluate::ToInt64(intrinsic.kind())) {
380381
return spec; // KIND is already a known constant
@@ -387,7 +388,7 @@ const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType(
387388
if (evaluate::IsValidKindOfIntrinsicType(intrinsic.category(), *value)) {
388389
kind = *value;
389390
} else {
390-
foldingContext().messages().Say(
391+
foldingContext().messages().Say(symbolName,
391392
"KIND parameter value (%jd) of intrinsic type %s "
392393
"did not resolve to a supported value"_err_en_US,
393394
*value,

flang/test/Semantics/assign04.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ subroutine s1
88
type(t(1, 2)) :: x
99
!ERROR: Assignment to constant 'x%k' is not allowed
1010
x%k = 4
11-
!ERROR: Left-hand side of assignment is not modifiable
11+
!ERROR: Assignment to constant 'x%l' is not allowed
1212
x%l = 3
1313
end
1414

flang/test/Semantics/resolve104.f90

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
! RUN: %S/test_errors.sh %s %t %f18
2+
! Test constant folding of type parameter values both a base value and a
3+
! parameter name are supplied.
4+
!
5+
! Type parameters are described in 7.5.3 and constant expressions are described
6+
! in 10.1.12. 10.1.12, paragraph 4 defines whether a specification inquiry is
7+
! a constant expression. Section 10.1.11, paragraph 3, item (2) states that a
8+
! type parameter inquiry is a specification inquiry.
9+
10+
module m1
11+
type dtype(goodDefaultKind, badDefaultKind)
12+
integer, kind :: goodDefaultKind = 4
13+
integer, kind :: badDefaultKind = 343
14+
! next field OK only if instantiated with a good value of goodDefaultKind
15+
!ERROR: KIND parameter value (99) of intrinsic type REAL did not resolve to a supported value
16+
real(goodDefaultKind) :: goodDefaultField
17+
! next field OK only if instantiated with a good value of goodDefaultKind
18+
!ERROR: KIND parameter value (343) of intrinsic type REAL did not resolve to a supported value
19+
!ERROR: KIND parameter value (99) of intrinsic type REAL did not resolve to a supported value
20+
real(badDefaultKind) :: badDefaultField
21+
end type dtype
22+
type(dtype) :: v1
23+
type(dtype(4, 4)) :: v2
24+
type(dtype(99, 4)) :: v3
25+
type(dtype(4, 99)) :: v4
26+
end module m1
27+
28+
module m2
29+
type baseType(baseParam)
30+
integer, kind :: baseParam = 4
31+
end type baseType
32+
type dtype(dtypeParam)
33+
integer, kind :: dtypeParam = 4
34+
type(baseType(dtypeParam)) :: baseField
35+
!ERROR: KIND parameter value (343) of intrinsic type REAL did not resolve to a supported value
36+
real(baseField%baseParam) :: realField
37+
end type dtype
38+
39+
type(dtype) :: v1
40+
type(dtype(8)) :: v2
41+
type(dtype(343)) :: v3
42+
end module m2
43+
44+
module m3
45+
type dtype(goodDefaultLen, badDefaultLen)
46+
integer, len :: goodDefaultLen = 4
47+
integer, len :: badDefaultLen = 343
48+
end type dtype
49+
type(dtype) :: v1
50+
type(dtype(4, 4)) :: v2
51+
type(dtype(99, 4)) :: v3
52+
type(dtype(4, 99)) :: v4
53+
real(v1%goodDefaultLen), pointer :: pGood1
54+
!ERROR: REAL(KIND=343) is not a supported type
55+
real(v1%badDefaultLen), pointer :: pBad1
56+
real(v2%goodDefaultLen), pointer :: pGood2
57+
real(v2%badDefaultLen), pointer :: pBad2
58+
!ERROR: REAL(KIND=99) is not a supported type
59+
real(v3%goodDefaultLen), pointer :: pGood3
60+
real(v3%badDefaultLen), pointer :: pBad3
61+
real(v4%goodDefaultLen), pointer :: pGood4
62+
!ERROR: REAL(KIND=99) is not a supported type
63+
real(v4%badDefaultLen), pointer :: pBad4
64+
end module m3

flang/test/Semantics/resolve89.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ subroutine inner (derivedArg)
107107
type localDerivedType
108108
! OK because the specification inquiry is a constant
109109
integer, dimension(localDerived%kindParam) :: goodField
110-
!ERROR: Invalid specification expression: non-constant reference to a type parameter inquiry not allowed for derived type components or type parameter values
110+
! OK because the value of lenParam is constant in this context
111111
integer, dimension(derivedArg%lenParam) :: badField
112112
end type localDerivedType
113113

0 commit comments

Comments
 (0)