-
Notifications
You must be signed in to change notification settings - Fork 11.6k
/
characteristics.h
331 lines (294 loc) · 11.6 KB
/
characteristics.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
//===-- include/flang/Evaluate/characteristics.h ----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Defines data structures to represent "characteristics" of Fortran
// procedures and other entities as they are specified in section 15.3
// of Fortran 2018.
#ifndef FORTRAN_EVALUATE_CHARACTERISTICS_H_
#define FORTRAN_EVALUATE_CHARACTERISTICS_H_
#include "common.h"
#include "expression.h"
#include "shape.h"
#include "type.h"
#include "flang/Common/Fortran.h"
#include "flang/Common/enum-set.h"
#include "flang/Common/idioms.h"
#include "flang/Common/indirection.h"
#include "flang/Parser/char-block.h"
#include "flang/Semantics/symbol.h"
#include <optional>
#include <string>
#include <variant>
#include <vector>
namespace llvm {
class raw_ostream;
}
namespace Fortran::evaluate::characteristics {
struct Procedure;
}
extern template class Fortran::common::Indirection<
Fortran::evaluate::characteristics::Procedure, true>;
namespace Fortran::evaluate::characteristics {
using common::CopyableIndirection;
// Are these procedures distinguishable for a generic name or FINAL?
bool Distinguishable(const Procedure &, const Procedure &);
// Are these procedures distinguishable for a generic operator or assignment?
bool DistinguishableOpOrAssign(const Procedure &, const Procedure &);
// Shapes of function results and dummy arguments have to have
// the same rank, the same deferred dimensions, and the same
// values for explicit dimensions when constant.
bool ShapesAreCompatible(const Shape &, const Shape &);
class TypeAndShape {
public:
ENUM_CLASS(
Attr, AssumedRank, AssumedShape, AssumedSize, DeferredShape, Coarray)
using Attrs = common::EnumSet<Attr, Attr_enumSize>;
explicit TypeAndShape(DynamicType t) : type_{t} { AcquireLEN(); }
TypeAndShape(DynamicType t, int rank) : type_{t}, shape_(rank) {
AcquireLEN();
}
TypeAndShape(DynamicType t, Shape &&s) : type_{t}, shape_{std::move(s)} {
AcquireLEN();
}
TypeAndShape(DynamicType t, std::optional<Shape> &&s) : type_{t} {
if (s) {
shape_ = std::move(*s);
}
AcquireLEN();
}
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(TypeAndShape)
bool operator==(const TypeAndShape &) const;
bool operator!=(const TypeAndShape &that) const { return !(*this == that); }
static std::optional<TypeAndShape> Characterize(
const semantics::Symbol &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
const semantics::ProcInterface &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
const semantics::DeclTypeSpec &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
const ActualArgument &, FoldingContext &);
// Handle Expr<T> & Designator<T>
template <typename A>
static std::optional<TypeAndShape> Characterize(
const A &x, FoldingContext &context) {
if (const auto *symbol{UnwrapWholeSymbolOrComponentDataRef(x)}) {
if (auto result{Characterize(*symbol, context)}) {
return result;
}
}
if (auto type{x.GetType()}) {
TypeAndShape result{*type, GetShape(context, x)};
if (type->category() == TypeCategory::Character) {
if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
if (auto length{chExpr->LEN()}) {
result.set_LEN(std::move(*length));
}
}
}
return std::move(result.Rewrite(context));
}
return std::nullopt;
}
template <typename A>
static std::optional<TypeAndShape> Characterize(
const std::optional<A> &x, FoldingContext &context) {
if (x) {
return Characterize(*x, context);
} else {
return std::nullopt;
}
}
template <typename A>
static std::optional<TypeAndShape> Characterize(
const A *p, FoldingContext &context) {
if (p) {
return Characterize(*p, context);
} else {
return std::nullopt;
}
}
DynamicType type() const { return type_; }
TypeAndShape &set_type(DynamicType t) {
type_ = t;
return *this;
}
const std::optional<Expr<SubscriptInteger>> &LEN() const { return LEN_; }
TypeAndShape &set_LEN(Expr<SubscriptInteger> &&len) {
LEN_ = std::move(len);
return *this;
}
const Shape &shape() const { return shape_; }
const Attrs &attrs() const { return attrs_; }
int corank() const { return corank_; }
int Rank() const { return GetRank(shape_); }
bool IsCompatibleWith(parser::ContextualMessages &, const TypeAndShape &that,
const char *thisIs = "pointer", const char *thatIs = "target",
bool isElemental = false, bool thisIsDeferredShape = false,
bool thatIsDeferredShape = false) const;
std::optional<Expr<SubscriptInteger>> MeasureSizeInBytes(
FoldingContext &) const;
// called by Fold() to rewrite in place
TypeAndShape &Rewrite(FoldingContext &);
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
private:
static std::optional<TypeAndShape> Characterize(
const semantics::AssocEntityDetails &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
const semantics::ProcEntityDetails &, FoldingContext &);
void AcquireAttrs(const semantics::Symbol &);
void AcquireLEN();
void AcquireLEN(const semantics::Symbol &);
protected:
DynamicType type_;
std::optional<Expr<SubscriptInteger>> LEN_;
Shape shape_;
Attrs attrs_;
int corank_{0};
};
// 15.3.2.2
struct DummyDataObject {
ENUM_CLASS(Attr, Optional, Allocatable, Asynchronous, Contiguous, Value,
Volatile, Pointer, Target)
using Attrs = common::EnumSet<Attr, Attr_enumSize>;
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyDataObject)
explicit DummyDataObject(const TypeAndShape &t) : type{t} {}
explicit DummyDataObject(TypeAndShape &&t) : type{std::move(t)} {}
explicit DummyDataObject(DynamicType t) : type{t} {}
bool operator==(const DummyDataObject &) const;
bool operator!=(const DummyDataObject &that) const {
return !(*this == that);
}
static std::optional<DummyDataObject> Characterize(
const semantics::Symbol &, FoldingContext &);
bool CanBePassedViaImplicitInterface() const;
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
TypeAndShape type;
std::vector<Expr<SubscriptInteger>> coshape;
common::Intent intent{common::Intent::Default};
Attrs attrs;
};
// 15.3.2.3
struct DummyProcedure {
ENUM_CLASS(Attr, Pointer, Optional)
using Attrs = common::EnumSet<Attr, Attr_enumSize>;
DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(DummyProcedure)
explicit DummyProcedure(Procedure &&);
bool operator==(const DummyProcedure &) const;
bool operator!=(const DummyProcedure &that) const { return !(*this == that); }
static std::optional<DummyProcedure> Characterize(
const semantics::Symbol &, FoldingContext &context);
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
CopyableIndirection<Procedure> procedure;
common::Intent intent{common::Intent::Default};
Attrs attrs;
};
// 15.3.2.4
struct AlternateReturn {
bool operator==(const AlternateReturn &) const { return true; }
bool operator!=(const AlternateReturn &) const { return false; }
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
};
// 15.3.2.1
struct DummyArgument {
DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(DummyArgument)
DummyArgument(std::string &&name, DummyDataObject &&x)
: name{std::move(name)}, u{std::move(x)} {}
DummyArgument(std::string &&name, DummyProcedure &&x)
: name{std::move(name)}, u{std::move(x)} {}
explicit DummyArgument(AlternateReturn &&x) : u{std::move(x)} {}
~DummyArgument();
bool operator==(const DummyArgument &) const;
bool operator!=(const DummyArgument &that) const { return !(*this == that); }
static std::optional<DummyArgument> Characterize(
const semantics::Symbol &, FoldingContext &);
static std::optional<DummyArgument> FromActual(
std::string &&, const Expr<SomeType> &, FoldingContext &);
bool IsOptional() const;
void SetOptional(bool = true);
common::Intent GetIntent() const;
void SetIntent(common::Intent);
bool CanBePassedViaImplicitInterface() const;
bool IsTypelessIntrinsicDummy() const;
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
// name and pass are not characteristics and so does not participate in
// operator== but are needed to determine if procedures are distinguishable
std::string name;
bool pass{false}; // is this the PASS argument of its procedure
std::variant<DummyDataObject, DummyProcedure, AlternateReturn> u;
};
using DummyArguments = std::vector<DummyArgument>;
// 15.3.3
struct FunctionResult {
ENUM_CLASS(Attr, Allocatable, Pointer, Contiguous)
using Attrs = common::EnumSet<Attr, Attr_enumSize>;
DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(FunctionResult)
explicit FunctionResult(DynamicType);
explicit FunctionResult(TypeAndShape &&);
explicit FunctionResult(Procedure &&);
~FunctionResult();
bool operator==(const FunctionResult &) const;
bool operator!=(const FunctionResult &that) const { return !(*this == that); }
static std::optional<FunctionResult> Characterize(
const Symbol &, FoldingContext &);
bool IsAssumedLengthCharacter() const;
const Procedure *IsProcedurePointer() const {
if (const auto *pp{std::get_if<CopyableIndirection<Procedure>>(&u)}) {
return &pp->value();
} else {
return nullptr;
}
}
const TypeAndShape *GetTypeAndShape() const {
return std::get_if<TypeAndShape>(&u);
}
void SetType(DynamicType t) { std::get<TypeAndShape>(u).set_type(t); }
bool CanBeReturnedViaImplicitInterface() const;
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
Attrs attrs;
std::variant<TypeAndShape, CopyableIndirection<Procedure>> u;
};
// 15.3.1
struct Procedure {
ENUM_CLASS(
Attr, Pure, Elemental, BindC, ImplicitInterface, NullPointer, Subroutine)
using Attrs = common::EnumSet<Attr, Attr_enumSize>;
Procedure(FunctionResult &&, DummyArguments &&, Attrs);
Procedure(DummyArguments &&, Attrs); // for subroutines and NULL()
DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(Procedure)
~Procedure();
bool operator==(const Procedure &) const;
bool operator!=(const Procedure &that) const { return !(*this == that); }
// Characterizes the procedure represented by a symbol, which may be an
// "unrestricted specific intrinsic function".
static std::optional<Procedure> Characterize(
const semantics::Symbol &, FoldingContext &);
static std::optional<Procedure> Characterize(
const ProcedureDesignator &, FoldingContext &);
static std::optional<Procedure> Characterize(
const ProcedureRef &, FoldingContext &);
// At most one of these will return true.
// For "EXTERNAL P" with no type for or calls to P, both will be false.
bool IsFunction() const { return functionResult.has_value(); }
bool IsSubroutine() const { return attrs.test(Attr::Subroutine); }
bool IsPure() const { return attrs.test(Attr::Pure); }
bool IsElemental() const { return attrs.test(Attr::Elemental); }
bool IsBindC() const { return attrs.test(Attr::BindC); }
bool HasExplicitInterface() const {
return !attrs.test(Attr::ImplicitInterface);
}
int FindPassIndex(std::optional<parser::CharBlock>) const;
bool CanBeCalledViaImplicitInterface() const;
bool CanOverride(const Procedure &, std::optional<int> passIndex) const;
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
std::optional<FunctionResult> functionResult;
DummyArguments dummyArguments;
Attrs attrs;
private:
Procedure() {}
};
} // namespace Fortran::evaluate::characteristics
#endif // FORTRAN_EVALUATE_CHARACTERISTICS_H_