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