Skip to content

Commit 0c0b2ea

Browse files
committed
[flang] Check procedure pointer initializations; clean up ELEMENTAL
Implements compatibility checking for initializers in procedure pointer declarations. This work exposed some inconsistency in how ELEMENTAL interfaces were handled and checked, from both unrestricted intrinsic functions and others, and some refinements needed for function result compatbility checking; these have also been ironed out. Some new warnings are now emitted, and this affected a dozen or so tests. Differential Revision: https://reviews.llvm.org/D159026
1 parent 4c62e94 commit 0c0b2ea

26 files changed

+405
-255
lines changed

flang/include/flang/Evaluate/characteristics.h

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,23 +81,24 @@ class TypeAndShape {
8181
bool operator!=(const TypeAndShape &that) const { return !(*this == that); }
8282

8383
static std::optional<TypeAndShape> Characterize(
84-
const semantics::Symbol &, FoldingContext &);
84+
const semantics::Symbol &, FoldingContext &, bool invariantOnly = false);
8585
static std::optional<TypeAndShape> Characterize(
86-
const semantics::DeclTypeSpec &, FoldingContext &);
86+
const semantics::DeclTypeSpec &, FoldingContext &,
87+
bool invariantOnly = false);
8788
static std::optional<TypeAndShape> Characterize(
88-
const ActualArgument &, FoldingContext &);
89+
const ActualArgument &, FoldingContext &, bool invariantOnly = false);
8990

9091
// General case for Expr<T>, ActualArgument, &c.
9192
template <typename A>
9293
static std::optional<TypeAndShape> Characterize(
93-
const A &x, FoldingContext &context) {
94+
const A &x, FoldingContext &context, bool invariantOnly = false) {
9495
if (const auto *symbol{UnwrapWholeSymbolOrComponentDataRef(x)}) {
95-
if (auto result{Characterize(*symbol, context)}) {
96+
if (auto result{Characterize(*symbol, context, invariantOnly)}) {
9697
return result;
9798
}
9899
}
99100
if (auto type{x.GetType()}) {
100-
TypeAndShape result{*type, GetShape(context, x)};
101+
TypeAndShape result{*type, GetShape(context, x, invariantOnly)};
101102
if (type->category() == TypeCategory::Character) {
102103
if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
103104
if (auto length{chExpr->LEN()}) {
@@ -114,14 +115,14 @@ class TypeAndShape {
114115
template <int KIND>
115116
static std::optional<TypeAndShape> Characterize(
116117
const Designator<Type<TypeCategory::Character, KIND>> &x,
117-
FoldingContext &context) {
118+
FoldingContext &context, bool invariantOnly = true) {
118119
if (const auto *symbol{UnwrapWholeSymbolOrComponentDataRef(x)}) {
119-
if (auto result{Characterize(*symbol, context)}) {
120+
if (auto result{Characterize(*symbol, context, invariantOnly)}) {
120121
return result;
121122
}
122123
}
123124
if (auto type{x.GetType()}) {
124-
TypeAndShape result{*type, GetShape(context, x)};
125+
TypeAndShape result{*type, GetShape(context, x, invariantOnly)};
125126
if (auto length{x.LEN()}) {
126127
result.set_LEN(std::move(*length));
127128
}
@@ -131,19 +132,19 @@ class TypeAndShape {
131132
}
132133

133134
template <typename A>
134-
static std::optional<TypeAndShape> Characterize(
135-
const std::optional<A> &x, FoldingContext &context) {
135+
static std::optional<TypeAndShape> Characterize(const std::optional<A> &x,
136+
FoldingContext &context, bool invariantOnly = false) {
136137
if (x) {
137-
return Characterize(*x, context);
138+
return Characterize(*x, context, invariantOnly);
138139
} else {
139140
return std::nullopt;
140141
}
141142
}
142143
template <typename A>
143144
static std::optional<TypeAndShape> Characterize(
144-
A *ptr, FoldingContext &context) {
145+
A *ptr, FoldingContext &context, bool invariantOnly = false) {
145146
if (ptr) {
146-
return Characterize(std::as_const(*ptr), context);
147+
return Characterize(std::as_const(*ptr), context, invariantOnly);
147148
} else {
148149
return std::nullopt;
149150
}
@@ -181,7 +182,8 @@ class TypeAndShape {
181182

182183
private:
183184
static std::optional<TypeAndShape> Characterize(
184-
const semantics::AssocEntityDetails &, FoldingContext &);
185+
const semantics::AssocEntityDetails &, FoldingContext &,
186+
bool invariantOnly = true);
185187
static std::optional<TypeAndShape> Characterize(
186188
const semantics::ProcEntityDetails &, FoldingContext &);
187189
void AcquireAttrs(const semantics::Symbol &);

flang/include/flang/Evaluate/shape.h

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,14 @@ inline int GetRank(const Shape &s) { return static_cast<int>(s.size()); }
5454
Shape Fold(FoldingContext &, Shape &&);
5555
std::optional<Shape> Fold(FoldingContext &, std::optional<Shape> &&);
5656

57+
// Computes shapes in terms of expressions that are scope-invariant, by
58+
// default, which is nearly always what one wants outside of procedure
59+
// characterization.
5760
template <typename A>
58-
std::optional<Shape> GetShape(FoldingContext &, const A &);
59-
template <typename A> std::optional<Shape> GetShape(const A &);
61+
std::optional<Shape> GetShape(
62+
FoldingContext &, const A &, bool invariantOnly = true);
63+
template <typename A>
64+
std::optional<Shape> GetShape(const A &, bool invariantOnly = true);
6065

6166
// The dimension argument to these inquiries is zero-based,
6267
// unlike the DIM= arguments to many intrinsics.
@@ -68,31 +73,42 @@ template <typename A> std::optional<Shape> GetShape(const A &);
6873
// in those circumstances.
6974
// Similarly, GetUBOUND result will be forced to 0 on an empty dimension,
7075
// but will fail if the extent is not a compile time constant.
71-
ExtentExpr GetRawLowerBound(const NamedEntity &, int dimension);
7276
ExtentExpr GetRawLowerBound(
73-
FoldingContext &, const NamedEntity &, int dimension);
74-
MaybeExtentExpr GetLBOUND(const NamedEntity &, int dimension);
75-
MaybeExtentExpr GetLBOUND(FoldingContext &, const NamedEntity &, int dimension);
76-
MaybeExtentExpr GetRawUpperBound(const NamedEntity &, int dimension);
77+
const NamedEntity &, int dimension, bool invariantOnly = true);
78+
ExtentExpr GetRawLowerBound(FoldingContext &, const NamedEntity &,
79+
int dimension, bool invariantOnly = true);
80+
MaybeExtentExpr GetLBOUND(
81+
const NamedEntity &, int dimension, bool invariantOnly = true);
82+
MaybeExtentExpr GetLBOUND(FoldingContext &, const NamedEntity &, int dimension,
83+
bool invariantOnly = true);
7784
MaybeExtentExpr GetRawUpperBound(
78-
FoldingContext &, const NamedEntity &, int dimension);
79-
MaybeExtentExpr GetUBOUND(const NamedEntity &, int dimension);
80-
MaybeExtentExpr GetUBOUND(FoldingContext &, const NamedEntity &, int dimension);
85+
const NamedEntity &, int dimension, bool invariantOnly = true);
86+
MaybeExtentExpr GetRawUpperBound(FoldingContext &, const NamedEntity &,
87+
int dimension, bool invariantOnly = true);
88+
MaybeExtentExpr GetUBOUND(
89+
const NamedEntity &, int dimension, bool invariantOnly = true);
90+
MaybeExtentExpr GetUBOUND(FoldingContext &, const NamedEntity &, int dimension,
91+
bool invariantOnly = true);
8192
MaybeExtentExpr ComputeUpperBound(ExtentExpr &&lower, MaybeExtentExpr &&extent);
8293
MaybeExtentExpr ComputeUpperBound(
8394
FoldingContext &, ExtentExpr &&lower, MaybeExtentExpr &&extent);
84-
Shape GetRawLowerBounds(const NamedEntity &);
85-
Shape GetRawLowerBounds(FoldingContext &, const NamedEntity &);
86-
Shape GetLBOUNDs(const NamedEntity &);
87-
Shape GetLBOUNDs(FoldingContext &, const NamedEntity &);
88-
Shape GetUBOUNDs(const NamedEntity &);
89-
Shape GetUBOUNDs(FoldingContext &, const NamedEntity &);
90-
MaybeExtentExpr GetExtent(const NamedEntity &, int dimension);
91-
MaybeExtentExpr GetExtent(FoldingContext &, const NamedEntity &, int dimension);
92-
MaybeExtentExpr GetExtent(
93-
const Subscript &, const NamedEntity &, int dimension);
95+
Shape GetRawLowerBounds(const NamedEntity &, bool invariantOnly = true);
96+
Shape GetRawLowerBounds(
97+
FoldingContext &, const NamedEntity &, bool invariantOnly = true);
98+
Shape GetLBOUNDs(const NamedEntity &, bool invariantOnly = true);
99+
Shape GetLBOUNDs(
100+
FoldingContext &, const NamedEntity &, bool invariantOnly = true);
101+
Shape GetUBOUNDs(const NamedEntity &, bool invariantOnly = true);
102+
Shape GetUBOUNDs(
103+
FoldingContext &, const NamedEntity &, bool invariantOnly = true);
94104
MaybeExtentExpr GetExtent(
95-
FoldingContext &, const Subscript &, const NamedEntity &, int dimension);
105+
const NamedEntity &, int dimension, bool invariantOnly = true);
106+
MaybeExtentExpr GetExtent(FoldingContext &, const NamedEntity &, int dimension,
107+
bool invariantOnly = true);
108+
MaybeExtentExpr GetExtent(const Subscript &, const NamedEntity &, int dimension,
109+
bool invariantOnly = true);
110+
MaybeExtentExpr GetExtent(FoldingContext &, const Subscript &,
111+
const NamedEntity &, int dimension, bool invariantOnly = true);
96112

97113
// Compute an element count for a triplet or trip count for a DO.
98114
ExtentExpr CountTrips(
@@ -115,11 +131,14 @@ class GetShapeHelper
115131
using Result = std::optional<Shape>;
116132
using Base = AnyTraverse<GetShapeHelper, Result>;
117133
using Base::operator();
118-
GetShapeHelper() : Base{*this} {}
119-
explicit GetShapeHelper(FoldingContext &c) : Base{*this}, context_{&c} {}
120-
explicit GetShapeHelper(FoldingContext &c, bool useResultSymbolShape)
121-
: Base{*this}, context_{&c}, useResultSymbolShape_{useResultSymbolShape} {
122-
}
134+
explicit GetShapeHelper(bool invariantOnly)
135+
: Base{*this}, invariantOnly_{invariantOnly} {}
136+
explicit GetShapeHelper(FoldingContext &c, bool invariantOnly)
137+
: Base{*this}, context_{&c}, invariantOnly_{invariantOnly} {}
138+
explicit GetShapeHelper(
139+
FoldingContext &c, bool useResultSymbolShape, bool invariantOnly)
140+
: Base{*this}, context_{&c}, useResultSymbolShape_{useResultSymbolShape},
141+
invariantOnly_{invariantOnly} {}
123142

124143
Result operator()(const ImpliedDoIndex &) const { return ScalarShape(); }
125144
Result operator()(const DescriptorInquiry &) const { return ScalarShape(); }
@@ -160,7 +179,7 @@ class GetShapeHelper
160179
static Result ScalarShape() { return Shape{}; }
161180
static Shape ConstantShape(const Constant<ExtentType> &);
162181
Result AsShapeResult(ExtentExpr &&) const;
163-
static Shape CreateShape(int rank, NamedEntity &);
182+
Shape CreateShape(int rank, NamedEntity &) const;
164183

165184
template <typename T>
166185
MaybeExtentExpr GetArrayConstructorValueExtent(
@@ -215,34 +234,40 @@ class GetShapeHelper
215234

216235
FoldingContext *context_{nullptr};
217236
bool useResultSymbolShape_{true};
237+
// When invariantOnly=false, the returned shape need not be invariant
238+
// in its scope; in particular, it may contain references to dummy arguments.
239+
bool invariantOnly_{true};
218240
};
219241

220242
template <typename A>
221-
std::optional<Shape> GetShape(FoldingContext &context, const A &x) {
222-
if (auto shape{GetShapeHelper{context}(x)}) {
243+
std::optional<Shape> GetShape(
244+
FoldingContext &context, const A &x, bool invariantOnly) {
245+
if (auto shape{GetShapeHelper{context, invariantOnly}(x)}) {
223246
return Fold(context, std::move(shape));
224247
} else {
225248
return std::nullopt;
226249
}
227250
}
228251

229-
template <typename A> std::optional<Shape> GetShape(const A &x) {
230-
return GetShapeHelper{}(x);
252+
template <typename A>
253+
std::optional<Shape> GetShape(const A &x, bool invariantOnly) {
254+
return GetShapeHelper{invariantOnly}(x);
231255
}
232256

233257
template <typename A>
234-
std::optional<Shape> GetShape(FoldingContext *context, const A &x) {
258+
std::optional<Shape> GetShape(
259+
FoldingContext *context, const A &x, bool invariantOnly = true) {
235260
if (context) {
236-
return GetShape(*context, x);
261+
return GetShape(*context, x, invariantOnly);
237262
} else {
238-
return GetShapeHelper{}(x);
263+
return GetShapeHelper{invariantOnly}(x);
239264
}
240265
}
241266

242267
template <typename A>
243268
std::optional<Constant<ExtentType>> GetConstantShape(
244269
FoldingContext &context, const A &x) {
245-
if (auto shape{GetShape(context, x)}) {
270+
if (auto shape{GetShape(context, x, /*invariantonly=*/true)}) {
246271
return AsConstantShape(context, *shape);
247272
} else {
248273
return std::nullopt;
@@ -252,7 +277,7 @@ std::optional<Constant<ExtentType>> GetConstantShape(
252277
template <typename A>
253278
std::optional<ConstantSubscripts> GetConstantExtents(
254279
FoldingContext &context, const A &x) {
255-
if (auto shape{GetShape(context, x)}) {
280+
if (auto shape{GetShape(context, x, /*invariantOnly=*/true)}) {
256281
return AsConstantExtents(context, *shape);
257282
} else {
258283
return std::nullopt;
@@ -265,7 +290,8 @@ std::optional<ConstantSubscripts> GetConstantExtents(
265290
// arguments).
266291
template <typename A>
267292
std::optional<Shape> GetContextFreeShape(FoldingContext &context, const A &x) {
268-
return GetShapeHelper{context, false}(x);
293+
return GetShapeHelper{
294+
context, /*useResultSymbolShape=*/false, /*invariantOnly=*/true}(x);
269295
}
270296

271297
// Compilation-time shape conformance checking, when corresponding extents

flang/include/flang/Evaluate/tools.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,7 @@ const Symbol *GetMainEntry(const Symbol *);
11841184
bool IsVariableName(const Symbol &);
11851185
bool IsPureProcedure(const Symbol &);
11861186
bool IsPureProcedure(const Scope &);
1187+
bool IsExplicitlyImpureProcedure(const Symbol &);
11871188
bool IsElementalProcedure(const Symbol &);
11881189
bool IsFunction(const Symbol &);
11891190
bool IsFunction(const Scope &);

0 commit comments

Comments
 (0)