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