Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Evaluate/type.h ---------------------------*- C++ -*-===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef FORTRAN_EVALUATE_TYPE_H_ |
10 | #define FORTRAN_EVALUATE_TYPE_H_ |
11 | |
12 | // These definitions map Fortran's intrinsic types, characterized by byte |
13 | // sizes encoded in KIND type parameter values, to their value representation |
14 | // types in the evaluation library, which are parameterized in terms of |
15 | // total bit width and real precision. Instances of the Type class template |
16 | // are suitable for use as template parameters to instantiate other class |
17 | // templates, like expressions, over the supported types and kinds. |
18 | |
19 | #include "common.h" |
20 | #include "complex.h" |
21 | #include "formatting.h" |
22 | #include "integer.h" |
23 | #include "logical.h" |
24 | #include "real.h" |
25 | #include "flang/Common/Fortran-features.h" |
26 | #include "flang/Common/Fortran.h" |
27 | #include "flang/Common/idioms.h" |
28 | #include "flang/Common/real.h" |
29 | #include "flang/Common/template.h" |
30 | #include <cinttypes> |
31 | #include <optional> |
32 | #include <string> |
33 | #include <type_traits> |
34 | #include <variant> |
35 | |
36 | namespace Fortran::semantics { |
37 | class DeclTypeSpec; |
38 | class DerivedTypeSpec; |
39 | class ParamValue; |
40 | class Symbol; |
41 | // IsDescriptor() is true when an object requires the use of a descriptor |
42 | // in memory when "at rest". IsPassedViaDescriptor() is sometimes false |
43 | // when IsDescriptor() is true, including the cases of CHARACTER dummy |
44 | // arguments and explicit & assumed-size dummy arrays. |
45 | bool IsDescriptor(const Symbol &); |
46 | bool IsPassedViaDescriptor(const Symbol &); |
47 | } // namespace Fortran::semantics |
48 | |
49 | namespace Fortran::evaluate { |
50 | |
51 | using common::TypeCategory; |
52 | class TargetCharacteristics; |
53 | |
54 | // Specific intrinsic types are represented by specializations of |
55 | // this class template Type<CATEGORY, KIND>. |
56 | template <TypeCategory CATEGORY, int KIND = 0> class Type; |
57 | |
58 | using SubscriptInteger = Type<TypeCategory::Integer, 8>; |
59 | using CInteger = Type<TypeCategory::Integer, 4>; |
60 | using LargestInt = Type<TypeCategory::Integer, 16>; |
61 | using LogicalResult = Type<TypeCategory::Logical, 4>; |
62 | using LargestReal = Type<TypeCategory::Real, 16>; |
63 | using Ascii = Type<TypeCategory::Character, 1>; |
64 | |
65 | // A predicate that is true when a kind value is a kind that could possibly |
66 | // be supported for an intrinsic type category on some target instruction |
67 | // set architecture. |
68 | static constexpr bool IsValidKindOfIntrinsicType( |
69 | TypeCategory category, std::int64_t kind) { |
70 | switch (category) { |
71 | case TypeCategory::Integer: |
72 | return kind == 1 || kind == 2 || kind == 4 || kind == 8 || kind == 16; |
73 | case TypeCategory::Real: |
74 | case TypeCategory::Complex: |
75 | return kind == 2 || kind == 3 || kind == 4 || kind == 8 || kind == 10 || |
76 | kind == 16; |
77 | case TypeCategory::Character: |
78 | return kind == 1 || kind == 2 || kind == 4; |
79 | case TypeCategory::Logical: |
80 | return kind == 1 || kind == 2 || kind == 4 || kind == 8; |
81 | default: |
82 | return false; |
83 | } |
84 | } |
85 | |
86 | // DynamicType is meant to be suitable for use as the result type for |
87 | // GetType() functions and member functions; consequently, it must be |
88 | // capable of being used in a constexpr context. So it does *not* |
89 | // directly hold anything requiring a destructor, such as an arbitrary |
90 | // CHARACTER length type parameter expression. Those must be derived |
91 | // via LEN() member functions, packaged elsewhere (e.g. as in |
92 | // ArrayConstructor), copied from a parameter spec in the symbol table |
93 | // if one is supplied, or a known integer value. |
94 | class DynamicType { |
95 | public: |
96 | constexpr DynamicType(TypeCategory cat, int k) : category_{cat}, kind_{k} { |
97 | CHECK(IsValidKindOfIntrinsicType(category_, kind_)); |
98 | } |
99 | DynamicType(int charKind, const semantics::ParamValue &len); |
100 | // When a known length is presented, resolve it to its effective |
101 | // length of zero if it is negative. |
102 | constexpr DynamicType(int k, std::int64_t len) |
103 | : category_{TypeCategory::Character}, kind_{k}, knownLength_{ |
104 | len >= 0 ? len : 0} { |
105 | CHECK(IsValidKindOfIntrinsicType(category_, kind_)); |
106 | } |
107 | explicit constexpr DynamicType( |
108 | const semantics::DerivedTypeSpec &dt, bool poly = false) |
109 | : category_{TypeCategory::Derived}, derived_{&dt} { |
110 | if (poly) { |
111 | kind_ = ClassKind; |
112 | } |
113 | } |
114 | CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(DynamicType) |
115 | |
116 | // A rare use case used for representing the characteristics of an |
117 | // intrinsic function like REAL() that accepts a typeless BOZ literal |
118 | // argument and for typeless pointers -- things that real user Fortran can't |
119 | // do. |
120 | static constexpr DynamicType TypelessIntrinsicArgument() { |
121 | DynamicType result; |
122 | result.category_ = TypeCategory::Integer; |
123 | result.kind_ = TypelessKind; |
124 | return result; |
125 | } |
126 | |
127 | static constexpr DynamicType UnlimitedPolymorphic() { |
128 | DynamicType result; |
129 | result.category_ = TypeCategory::Derived; |
130 | result.kind_ = ClassKind; |
131 | result.derived_ = nullptr; |
132 | return result; // CLASS(*) |
133 | } |
134 | |
135 | static constexpr DynamicType AssumedType() { |
136 | DynamicType result; |
137 | result.category_ = TypeCategory::Derived; |
138 | result.kind_ = AssumedTypeKind; |
139 | result.derived_ = nullptr; |
140 | return result; // TYPE(*) |
141 | } |
142 | |
143 | // Comparison is deep -- type parameters are compared independently. |
144 | bool operator==(const DynamicType &) const; |
145 | bool operator!=(const DynamicType &that) const { return !(*this == that); } |
146 | |
147 | constexpr TypeCategory category() const { return category_; } |
148 | constexpr int kind() const { |
149 | CHECK(kind_ > 0); |
150 | return kind_; |
151 | } |
152 | constexpr const semantics::ParamValue *charLengthParamValue() const { |
153 | return charLengthParamValue_; |
154 | } |
155 | constexpr std::optional<std::int64_t> knownLength() const { |
156 | #if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 7 |
157 | if (knownLength_ < 0) { |
158 | return std::nullopt; |
159 | } |
160 | #endif |
161 | return knownLength_; |
162 | } |
163 | std::optional<Expr<SubscriptInteger>> GetCharLength() const; |
164 | |
165 | std::size_t GetAlignment(const TargetCharacteristics &) const; |
166 | std::optional<Expr<SubscriptInteger>> MeasureSizeInBytes(FoldingContext &, |
167 | bool aligned, |
168 | std::optional<std::int64_t> charLength = std::nullopt) const; |
169 | |
170 | std::string AsFortran() const; |
171 | std::string AsFortran(std::string &&charLenExpr) const; |
172 | DynamicType ResultTypeForMultiply(const DynamicType &) const; |
173 | |
174 | bool IsAssumedLengthCharacter() const; |
175 | bool IsNonConstantLengthCharacter() const; |
176 | bool IsTypelessIntrinsicArgument() const; |
177 | constexpr bool IsAssumedType() const { // TYPE(*) |
178 | return kind_ == AssumedTypeKind; |
179 | } |
180 | constexpr bool IsPolymorphic() const { // TYPE(*) or CLASS() |
181 | return kind_ == ClassKind || IsAssumedType(); |
182 | } |
183 | constexpr bool IsUnlimitedPolymorphic() const { // TYPE(*) or CLASS(*) |
184 | return IsPolymorphic() && !derived_; |
185 | } |
186 | bool IsLengthlessIntrinsicType() const; |
187 | constexpr const semantics::DerivedTypeSpec &GetDerivedTypeSpec() const { |
188 | return DEREF(derived_); |
189 | } |
190 | |
191 | bool RequiresDescriptor() const; |
192 | bool HasDeferredTypeParameter() const; |
193 | |
194 | // 7.3.2.3 & 15.5.2.4 type compatibility. |
195 | // x.IsTkCompatibleWith(y) is true if "x => y" or passing actual y to |
196 | // dummy argument x would be valid. Be advised, this is not a reflexive |
197 | // relation. Kind type parameters must match, but CHARACTER lengths |
198 | // need not do so. |
199 | bool IsTkCompatibleWith(const DynamicType &) const; |
200 | bool IsTkCompatibleWith(const DynamicType &, common::IgnoreTKRSet) const; |
201 | |
202 | // A stronger compatibility check that does not allow distinct known |
203 | // values for CHARACTER lengths for e.g. MOVE_ALLOC(). |
204 | bool IsTkLenCompatibleWith(const DynamicType &) const; |
205 | |
206 | // EXTENDS_TYPE_OF (16.9.76); ignores type parameter values |
207 | std::optional<bool> ExtendsTypeOf(const DynamicType &) const; |
208 | // SAME_TYPE_AS (16.9.165); ignores type parameter values |
209 | std::optional<bool> SameTypeAs(const DynamicType &) const; |
210 | |
211 | // 7.5.2.4 type equivalence; like operator==(), but SEQUENCE/BIND(C) |
212 | // derived types can be structurally equivalent. |
213 | bool IsEquivalentTo(const DynamicType &) const; |
214 | |
215 | // Result will be missing when a symbol is absent or |
216 | // has an erroneous type, e.g., REAL(KIND=666). |
217 | static std::optional<DynamicType> From(const semantics::DeclTypeSpec &); |
218 | static std::optional<DynamicType> From(const semantics::Symbol &); |
219 | |
220 | template <typename A> static std::optional<DynamicType> From(const A &x) { |
221 | return x.GetType(); |
222 | } |
223 | template <typename A> static std::optional<DynamicType> From(const A *p) { |
224 | if (!p) { |
225 | return std::nullopt; |
226 | } else { |
227 | return From(*p); |
228 | } |
229 | } |
230 | template <typename A> |
231 | static std::optional<DynamicType> From(const std::optional<A> &x) { |
232 | if (x) { |
233 | return From(*x); |
234 | } else { |
235 | return std::nullopt; |
236 | } |
237 | } |
238 | |
239 | // Get a copy of this dynamic type where charLengthParamValue_ is reset if it |
240 | // is not a constant expression. This avoids propagating symbol references in |
241 | // scopes where they do not belong. Returns the type unmodified if it is not |
242 | // a character or if the length is not explicit. |
243 | DynamicType DropNonConstantCharacterLength() const; |
244 | |
245 | private: |
246 | // Special kind codes are used to distinguish the following Fortran types. |
247 | enum SpecialKind { |
248 | TypelessKind = -1, // BOZ actual argument to intrinsic function or pointer |
249 | // argument to ASSOCIATED |
250 | ClassKind = -2, // CLASS(T) or CLASS(*) |
251 | AssumedTypeKind = -3, // TYPE(*) |
252 | }; |
253 | |
254 | constexpr DynamicType() {} |
255 | |
256 | TypeCategory category_{TypeCategory::Derived}; // overridable default |
257 | int kind_{0}; |
258 | const semantics::ParamValue *charLengthParamValue_{nullptr}; |
259 | #if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 7 |
260 | // GCC 7's optional<> lacks a constexpr operator= |
261 | std::int64_t knownLength_{-1}; |
262 | #else |
263 | std::optional<std::int64_t> knownLength_; |
264 | #endif |
265 | const semantics::DerivedTypeSpec *derived_{nullptr}; // TYPE(T), CLASS(T) |
266 | }; |
267 | |
268 | // Return the DerivedTypeSpec of a DynamicType if it has one. |
269 | const semantics::DerivedTypeSpec *GetDerivedTypeSpec(const DynamicType &); |
270 | const semantics::DerivedTypeSpec *GetDerivedTypeSpec( |
271 | const std::optional<DynamicType> &); |
272 | const semantics::DerivedTypeSpec *GetParentTypeSpec( |
273 | const semantics::DerivedTypeSpec &); |
274 | |
275 | std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &, |
276 | const parser::CharBlock *derivedTypeRename = nullptr); |
277 | |
278 | template <TypeCategory CATEGORY, int KIND = 0> struct TypeBase { |
279 | static constexpr TypeCategory category{CATEGORY}; |
280 | static constexpr int kind{KIND}; |
281 | constexpr bool operator==(const TypeBase &) const { return true; } |
282 | static constexpr DynamicType GetType() { return {category, kind}; } |
283 | static std::string AsFortran() { return GetType().AsFortran(); } |
284 | }; |
285 | |
286 | template <int KIND> |
287 | class Type<TypeCategory::Integer, KIND> |
288 | : public TypeBase<TypeCategory::Integer, KIND> { |
289 | public: |
290 | using Scalar = value::Integer<8 * KIND>; |
291 | }; |
292 | |
293 | template <int KIND> |
294 | class Type<TypeCategory::Real, KIND> |
295 | : public TypeBase<TypeCategory::Real, KIND> { |
296 | public: |
297 | static constexpr int precision{common::PrecisionOfRealKind(KIND)}; |
298 | static constexpr int bits{common::BitsForBinaryPrecision(precision)}; |
299 | using Scalar = |
300 | value::Real<std::conditional_t<precision == 64, |
301 | value::X87IntegerContainer, value::Integer<bits>>, |
302 | precision>; |
303 | }; |
304 | |
305 | // The KIND type parameter on COMPLEX is the kind of each of its components. |
306 | template <int KIND> |
307 | class Type<TypeCategory::Complex, KIND> |
308 | : public TypeBase<TypeCategory::Complex, KIND> { |
309 | public: |
310 | using Part = Type<TypeCategory::Real, KIND>; |
311 | using Scalar = value::Complex<typename Part::Scalar>; |
312 | }; |
313 | |
314 | template <> |
315 | class Type<TypeCategory::Character, 1> |
316 | : public TypeBase<TypeCategory::Character, 1> { |
317 | public: |
318 | using Scalar = std::string; |
319 | }; |
320 | |
321 | template <> |
322 | class Type<TypeCategory::Character, 2> |
323 | : public TypeBase<TypeCategory::Character, 2> { |
324 | public: |
325 | using Scalar = std::u16string; |
326 | }; |
327 | |
328 | template <> |
329 | class Type<TypeCategory::Character, 4> |
330 | : public TypeBase<TypeCategory::Character, 4> { |
331 | public: |
332 | using Scalar = std::u32string; |
333 | }; |
334 | |
335 | template <int KIND> |
336 | class Type<TypeCategory::Logical, KIND> |
337 | : public TypeBase<TypeCategory::Logical, KIND> { |
338 | public: |
339 | using Scalar = value::Logical<8 * KIND>; |
340 | }; |
341 | |
342 | // Type functions |
343 | |
344 | // Given a specific type, find the type of the same kind in another category. |
345 | template <TypeCategory CATEGORY, typename T> |
346 | using SameKind = Type<CATEGORY, std::decay_t<T>::kind>; |
347 | |
348 | // Many expressions, including subscripts, CHARACTER lengths, array bounds, |
349 | // and effective type parameter values, are of a maximal kind of INTEGER. |
350 | using IndirectSubscriptIntegerExpr = |
351 | common::CopyableIndirection<Expr<SubscriptInteger>>; |
352 | |
353 | // For each intrinsic type category CAT, CategoryTypes<CAT> is an instantiation |
354 | // of std::tuple<Type<CAT, K>> that comprises every kind value K in that |
355 | // category that could possibly be supported on any target. |
356 | template <TypeCategory CATEGORY, int KIND> |
357 | using CategoryKindTuple = |
358 | std::conditional_t<IsValidKindOfIntrinsicType(CATEGORY, KIND), |
359 | std::tuple<Type<CATEGORY, KIND>>, std::tuple<>>; |
360 | |
361 | template <TypeCategory CATEGORY, int... KINDS> |
362 | using CategoryTypesHelper = |
363 | common::CombineTuples<CategoryKindTuple<CATEGORY, KINDS>...>; |
364 | |
365 | template <TypeCategory CATEGORY> |
366 | using CategoryTypes = CategoryTypesHelper<CATEGORY, 1, 2, 3, 4, 8, 10, 16, 32>; |
367 | |
368 | using IntegerTypes = CategoryTypes<TypeCategory::Integer>; |
369 | using RealTypes = CategoryTypes<TypeCategory::Real>; |
370 | using ComplexTypes = CategoryTypes<TypeCategory::Complex>; |
371 | using CharacterTypes = CategoryTypes<TypeCategory::Character>; |
372 | using LogicalTypes = CategoryTypes<TypeCategory::Logical>; |
373 | |
374 | using FloatingTypes = common::CombineTuples<RealTypes, ComplexTypes>; |
375 | using NumericTypes = common::CombineTuples<IntegerTypes, FloatingTypes>; |
376 | using RelationalTypes = |
377 | common::CombineTuples<IntegerTypes, RealTypes, CharacterTypes>; |
378 | using AllIntrinsicTypes = |
379 | common::CombineTuples<NumericTypes, CharacterTypes, LogicalTypes>; |
380 | using LengthlessIntrinsicTypes = |
381 | common::CombineTuples<NumericTypes, LogicalTypes>; |
382 | |
383 | // Predicates: does a type represent a specific intrinsic type? |
384 | template <typename T> |
385 | constexpr bool IsSpecificIntrinsicType{common::HasMember<T, AllIntrinsicTypes>}; |
386 | |
387 | // Predicate: is a type an intrinsic type that is completely characterized |
388 | // by its category and kind parameter value, or might it have a derived type |
389 | // &/or a length type parameter? |
390 | template <typename T> |
391 | constexpr bool IsLengthlessIntrinsicType{ |
392 | common::HasMember<T, LengthlessIntrinsicTypes>}; |
393 | |
394 | // Represents a type of any supported kind within a particular category. |
395 | template <TypeCategory CATEGORY> struct SomeKind { |
396 | static constexpr TypeCategory category{CATEGORY}; |
397 | constexpr bool operator==(const SomeKind &) const { return true; } |
398 | static std::string AsFortran() { |
399 | return "Some"s + std::string{common::EnumToString(category)}; |
400 | } |
401 | }; |
402 | |
403 | using NumericCategoryTypes = std::tuple<SomeKind<TypeCategory::Integer>, |
404 | SomeKind<TypeCategory::Real>, SomeKind<TypeCategory::Complex>>; |
405 | using AllIntrinsicCategoryTypes = std::tuple<SomeKind<TypeCategory::Integer>, |
406 | SomeKind<TypeCategory::Real>, SomeKind<TypeCategory::Complex>, |
407 | SomeKind<TypeCategory::Character>, SomeKind<TypeCategory::Logical>>; |
408 | |
409 | // Represents a completely generic type (or, for Expr<SomeType>, a typeless |
410 | // value like a BOZ literal or NULL() pointer). |
411 | struct SomeType { |
412 | static std::string AsFortran() { return "SomeType"s; } |
413 | }; |
414 | |
415 | class StructureConstructor; |
416 | |
417 | // Represents any derived type, polymorphic or not, as well as CLASS(*). |
418 | template <> class SomeKind<TypeCategory::Derived> { |
419 | public: |
420 | static constexpr TypeCategory category{TypeCategory::Derived}; |
421 | using Scalar = StructureConstructor; |
422 | |
423 | constexpr SomeKind() {} // CLASS(*) |
424 | constexpr explicit SomeKind(const semantics::DerivedTypeSpec &dts) |
425 | : derivedTypeSpec_{&dts} {} |
426 | constexpr explicit SomeKind(const DynamicType &dt) |
427 | : SomeKind(dt.GetDerivedTypeSpec()) {} |
428 | CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(SomeKind) |
429 | |
430 | bool IsUnlimitedPolymorphic() const { return !derivedTypeSpec_; } |
431 | constexpr DynamicType GetType() const { |
432 | if (!derivedTypeSpec_) { |
433 | return DynamicType::UnlimitedPolymorphic(); |
434 | } else { |
435 | return DynamicType{*derivedTypeSpec_}; |
436 | } |
437 | } |
438 | const semantics::DerivedTypeSpec &derivedTypeSpec() const { |
439 | CHECK(derivedTypeSpec_); |
440 | return *derivedTypeSpec_; |
441 | } |
442 | bool operator==(const SomeKind &) const; |
443 | std::string AsFortran() const; |
444 | |
445 | private: |
446 | const semantics::DerivedTypeSpec *derivedTypeSpec_{nullptr}; |
447 | }; |
448 | |
449 | using SomeInteger = SomeKind<TypeCategory::Integer>; |
450 | using SomeReal = SomeKind<TypeCategory::Real>; |
451 | using SomeComplex = SomeKind<TypeCategory::Complex>; |
452 | using SomeCharacter = SomeKind<TypeCategory::Character>; |
453 | using SomeLogical = SomeKind<TypeCategory::Logical>; |
454 | using SomeDerived = SomeKind<TypeCategory::Derived>; |
455 | using SomeCategory = std::tuple<SomeInteger, SomeReal, SomeComplex, |
456 | SomeCharacter, SomeLogical, SomeDerived>; |
457 | |
458 | using AllTypes = |
459 | common::CombineTuples<AllIntrinsicTypes, std::tuple<SomeDerived>>; |
460 | |
461 | template <typename T> using Scalar = typename std::decay_t<T>::Scalar; |
462 | |
463 | // When Scalar<T> is S, then TypeOf<S> is T. |
464 | // TypeOf is implemented by scanning all supported types for a match |
465 | // with Type<T>::Scalar. |
466 | template <typename CONST> struct TypeOfHelper { |
467 | template <typename T> struct Predicate { |
468 | static constexpr bool value() { |
469 | return std::is_same_v<std::decay_t<CONST>, |
470 | std::decay_t<typename T::Scalar>>; |
471 | } |
472 | }; |
473 | static constexpr int index{ |
474 | common::SearchMembers<Predicate, AllIntrinsicTypes>}; |
475 | using type = std::conditional_t<index >= 0, |
476 | std::tuple_element_t<index, AllIntrinsicTypes>, void>; |
477 | }; |
478 | |
479 | template <typename CONST> using TypeOf = typename TypeOfHelper<CONST>::type; |
480 | |
481 | int SelectedCharKind(const std::string &, int defaultKind); |
482 | // SelectedIntKind and SelectedRealKind are now member functions of |
483 | // TargetCharactertics. |
484 | |
485 | // Given the dynamic types and kinds of two operands, determine the common |
486 | // type to which they must be converted in order to be compared with |
487 | // intrinsic OPERATOR(==) or .EQV. |
488 | std::optional<DynamicType> ComparisonType( |
489 | const DynamicType &, const DynamicType &); |
490 | |
491 | bool IsInteroperableIntrinsicType(const DynamicType &, |
492 | const common::LanguageFeatureControl * = nullptr, |
493 | bool checkCharLength = true); |
494 | bool IsCUDAIntrinsicType(const DynamicType &); |
495 | |
496 | // Determine whether two derived type specs are sufficiently identical |
497 | // to be considered the "same" type even if declared separately. |
498 | bool AreSameDerivedType( |
499 | const semantics::DerivedTypeSpec &x, const semantics::DerivedTypeSpec &y); |
500 | |
501 | // For generating "[extern] template class", &c. boilerplate |
502 | #define EXPAND_FOR_EACH_INTEGER_KIND(M, P, S) \ |
503 | M(P, S, 1) M(P, S, 2) M(P, S, 4) M(P, S, 8) M(P, S, 16) |
504 | #define EXPAND_FOR_EACH_REAL_KIND(M, P, S) \ |
505 | M(P, S, 2) M(P, S, 3) M(P, S, 4) M(P, S, 8) M(P, S, 10) M(P, S, 16) |
506 | #define EXPAND_FOR_EACH_COMPLEX_KIND(M, P, S) EXPAND_FOR_EACH_REAL_KIND(M, P, S) |
507 | #define EXPAND_FOR_EACH_CHARACTER_KIND(M, P, S) M(P, S, 1) M(P, S, 2) M(P, S, 4) |
508 | #define EXPAND_FOR_EACH_LOGICAL_KIND(M, P, S) \ |
509 | M(P, S, 1) M(P, S, 2) M(P, S, 4) M(P, S, 8) |
510 | |
511 | #define FOR_EACH_INTEGER_KIND_HELP(PREFIX, SUFFIX, K) \ |
512 | PREFIX<Type<TypeCategory::Integer, K>> SUFFIX; |
513 | #define FOR_EACH_REAL_KIND_HELP(PREFIX, SUFFIX, K) \ |
514 | PREFIX<Type<TypeCategory::Real, K>> SUFFIX; |
515 | #define FOR_EACH_COMPLEX_KIND_HELP(PREFIX, SUFFIX, K) \ |
516 | PREFIX<Type<TypeCategory::Complex, K>> SUFFIX; |
517 | #define FOR_EACH_CHARACTER_KIND_HELP(PREFIX, SUFFIX, K) \ |
518 | PREFIX<Type<TypeCategory::Character, K>> SUFFIX; |
519 | #define FOR_EACH_LOGICAL_KIND_HELP(PREFIX, SUFFIX, K) \ |
520 | PREFIX<Type<TypeCategory::Logical, K>> SUFFIX; |
521 | |
522 | #define FOR_EACH_INTEGER_KIND(PREFIX, SUFFIX) \ |
523 | EXPAND_FOR_EACH_INTEGER_KIND(FOR_EACH_INTEGER_KIND_HELP, PREFIX, SUFFIX) |
524 | #define FOR_EACH_REAL_KIND(PREFIX, SUFFIX) \ |
525 | EXPAND_FOR_EACH_REAL_KIND(FOR_EACH_REAL_KIND_HELP, PREFIX, SUFFIX) |
526 | #define FOR_EACH_COMPLEX_KIND(PREFIX, SUFFIX) \ |
527 | EXPAND_FOR_EACH_COMPLEX_KIND(FOR_EACH_COMPLEX_KIND_HELP, PREFIX, SUFFIX) |
528 | #define FOR_EACH_CHARACTER_KIND(PREFIX, SUFFIX) \ |
529 | EXPAND_FOR_EACH_CHARACTER_KIND(FOR_EACH_CHARACTER_KIND_HELP, PREFIX, SUFFIX) |
530 | #define FOR_EACH_LOGICAL_KIND(PREFIX, SUFFIX) \ |
531 | EXPAND_FOR_EACH_LOGICAL_KIND(FOR_EACH_LOGICAL_KIND_HELP, PREFIX, SUFFIX) |
532 | |
533 | #define FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX, SUFFIX) \ |
534 | FOR_EACH_INTEGER_KIND(PREFIX, SUFFIX) \ |
535 | FOR_EACH_REAL_KIND(PREFIX, SUFFIX) \ |
536 | FOR_EACH_COMPLEX_KIND(PREFIX, SUFFIX) \ |
537 | FOR_EACH_LOGICAL_KIND(PREFIX, SUFFIX) |
538 | #define FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \ |
539 | FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX, SUFFIX) \ |
540 | FOR_EACH_CHARACTER_KIND(PREFIX, SUFFIX) |
541 | #define FOR_EACH_SPECIFIC_TYPE(PREFIX, SUFFIX) \ |
542 | FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \ |
543 | PREFIX<SomeDerived> SUFFIX; |
544 | |
545 | #define FOR_EACH_CATEGORY_TYPE(PREFIX, SUFFIX) \ |
546 | PREFIX<SomeInteger> SUFFIX; \ |
547 | PREFIX<SomeReal> SUFFIX; \ |
548 | PREFIX<SomeComplex> SUFFIX; \ |
549 | PREFIX<SomeCharacter> SUFFIX; \ |
550 | PREFIX<SomeLogical> SUFFIX; \ |
551 | PREFIX<SomeDerived> SUFFIX; \ |
552 | PREFIX<SomeType> SUFFIX; |
553 | #define FOR_EACH_TYPE_AND_KIND(PREFIX, SUFFIX) \ |
554 | FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \ |
555 | FOR_EACH_CATEGORY_TYPE(PREFIX, SUFFIX) |
556 | } // namespace Fortran::evaluate |
557 | #endif // FORTRAN_EVALUATE_TYPE_H_ |
558 |
Warning: This file is not a C or C++ file. It does not have highlighting.