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