1 | //===-- lib/Evaluate/intrinsics.cpp ---------------------------------------===// |
---|---|
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 | #include "flang/Evaluate/intrinsics.h" |
10 | #include "flang/Common/enum-set.h" |
11 | #include "flang/Common/float128.h" |
12 | #include "flang/Common/idioms.h" |
13 | #include "flang/Evaluate/check-expression.h" |
14 | #include "flang/Evaluate/common.h" |
15 | #include "flang/Evaluate/expression.h" |
16 | #include "flang/Evaluate/fold.h" |
17 | #include "flang/Evaluate/shape.h" |
18 | #include "flang/Evaluate/tools.h" |
19 | #include "flang/Evaluate/type.h" |
20 | #include "flang/Semantics/scope.h" |
21 | #include "flang/Semantics/tools.h" |
22 | #include "flang/Support/Fortran.h" |
23 | #include "llvm/Support/raw_ostream.h" |
24 | #include <algorithm> |
25 | #include <cmath> |
26 | #include <map> |
27 | #include <string> |
28 | #include <utility> |
29 | |
30 | using namespace Fortran::parser::literals; |
31 | |
32 | namespace Fortran::evaluate { |
33 | |
34 | class FoldingContext; |
35 | |
36 | // This file defines the supported intrinsic procedures and implements |
37 | // their recognition and validation. It is largely table-driven. See |
38 | // docs/intrinsics.md and section 16 of the Fortran 2018 standard |
39 | // for full details on each of the intrinsics. Be advised, they have |
40 | // complicated details, and the design of these tables has to accommodate |
41 | // that complexity. |
42 | |
43 | // Dummy arguments to generic intrinsic procedures are each specified by |
44 | // their keyword name (rarely used, but always defined), allowable type |
45 | // categories, a kind pattern, a rank pattern, and information about |
46 | // optionality and defaults. The kind and rank patterns are represented |
47 | // here with code values that are significant to the matching/validation engine. |
48 | |
49 | // An actual argument to an intrinsic procedure may be a procedure itself |
50 | // only if the dummy argument is Rank::reduceOperation, |
51 | // KindCode::addressable, or the special case of NULL(MOLD=procedurePointer). |
52 | |
53 | // These are small bit-sets of type category enumerators. |
54 | // Note that typeless (BOZ literal) values don't have a distinct type category. |
55 | // These typeless arguments are represented in the tables as if they were |
56 | // INTEGER with a special "typeless" kind code. Arguments of intrinsic types |
57 | // that can also be typeless values are encoded with an "elementalOrBOZ" |
58 | // rank pattern. |
59 | // Assumed-type (TYPE(*)) dummy arguments can be forwarded along to some |
60 | // intrinsic functions that accept AnyType + Rank::anyOrAssumedRank, |
61 | // AnyType + Rank::arrayOrAssumedRank, or AnyType + Kind::addressable. |
62 | using CategorySet = common::EnumSet<TypeCategory, 8>; |
63 | static constexpr CategorySet IntType{TypeCategory::Integer}; |
64 | static constexpr CategorySet UnsignedType{TypeCategory::Unsigned}; |
65 | static constexpr CategorySet RealType{TypeCategory::Real}; |
66 | static constexpr CategorySet ComplexType{TypeCategory::Complex}; |
67 | static constexpr CategorySet CharType{TypeCategory::Character}; |
68 | static constexpr CategorySet LogicalType{TypeCategory::Logical}; |
69 | static constexpr CategorySet IntOrUnsignedType{IntType | UnsignedType}; |
70 | static constexpr CategorySet IntOrRealType{IntType | RealType}; |
71 | static constexpr CategorySet IntUnsignedOrRealType{ |
72 | IntType | UnsignedType | RealType}; |
73 | static constexpr CategorySet IntOrRealOrCharType{IntType | RealType | CharType}; |
74 | static constexpr CategorySet IntOrLogicalType{IntType | LogicalType}; |
75 | static constexpr CategorySet FloatingType{RealType | ComplexType}; |
76 | static constexpr CategorySet NumericType{ |
77 | IntType | UnsignedType | RealType | ComplexType}; |
78 | static constexpr CategorySet RelatableType{ |
79 | IntType | UnsignedType | RealType | CharType}; |
80 | static constexpr CategorySet DerivedType{TypeCategory::Derived}; |
81 | static constexpr CategorySet IntrinsicType{ |
82 | IntType | UnsignedType | RealType | ComplexType | CharType | LogicalType}; |
83 | static constexpr CategorySet AnyType{IntrinsicType | DerivedType}; |
84 | |
85 | ENUM_CLASS(KindCode, none, defaultIntegerKind, |
86 | defaultRealKind, // is also the default COMPLEX kind |
87 | doublePrecision, quadPrecision, defaultCharKind, defaultLogicalKind, |
88 | greaterOrEqualToKind, // match kind value greater than or equal to a single |
89 | // explicit kind value |
90 | any, // matches any kind value; each instance is independent |
91 | // match any kind, but all "same" kinds must be equal. For characters, also |
92 | // implies that lengths must be equal. |
93 | same, |
94 | // for characters that only require the same kind, not length |
95 | sameKind, |
96 | operand, // match any kind, with promotion (non-standard) |
97 | typeless, // BOZ literals are INTEGER with this kind |
98 | ieeeFlagType, // IEEE_FLAG_TYPE from ISO_FORTRAN_EXCEPTION |
99 | ieeeRoundType, // IEEE_ROUND_TYPE from ISO_FORTRAN_ARITHMETIC |
100 | eventType, // EVENT_TYPE from module ISO_FORTRAN_ENV (for coarrays) |
101 | teamType, // TEAM_TYPE from module ISO_FORTRAN_ENV (for coarrays) |
102 | kindArg, // this argument is KIND= |
103 | effectiveKind, // for function results: "kindArg" value, possibly defaulted |
104 | dimArg, // this argument is DIM= |
105 | likeMultiply, // for DOT_PRODUCT and MATMUL |
106 | subscript, // address-sized integer |
107 | size, // default KIND= for SIZE(), UBOUND, &c. |
108 | addressable, // for PRESENT(), &c.; anything (incl. procedure) but BOZ |
109 | nullPointerType, // for ASSOCIATED(NULL()) |
110 | exactKind, // a single explicit exactKindValue |
111 | atomicIntKind, // atomic_int_kind from iso_fortran_env |
112 | atomicIntOrLogicalKind, // atomic_int_kind or atomic_logical_kind |
113 | sameAtom, // same type and kind as atom |
114 | ) |
115 | |
116 | struct TypePattern { |
117 | CategorySet categorySet; |
118 | KindCode kindCode{KindCode::none}; |
119 | int kindValue{0}; // for KindCode::exactKind and greaterOrEqualToKind |
120 | llvm::raw_ostream &Dump(llvm::raw_ostream &) const; |
121 | }; |
122 | |
123 | // Abbreviations for argument and result patterns in the intrinsic prototypes: |
124 | |
125 | // Match specific kinds of intrinsic types |
126 | static constexpr TypePattern DefaultInt{IntType, KindCode::defaultIntegerKind}; |
127 | static constexpr TypePattern DefaultReal{RealType, KindCode::defaultRealKind}; |
128 | static constexpr TypePattern DefaultComplex{ |
129 | ComplexType, KindCode::defaultRealKind}; |
130 | static constexpr TypePattern DefaultChar{CharType, KindCode::defaultCharKind}; |
131 | static constexpr TypePattern DefaultLogical{ |
132 | LogicalType, KindCode::defaultLogicalKind}; |
133 | static constexpr TypePattern BOZ{IntType, KindCode::typeless}; |
134 | static constexpr TypePattern EventType{DerivedType, KindCode::eventType}; |
135 | static constexpr TypePattern IeeeFlagType{DerivedType, KindCode::ieeeFlagType}; |
136 | static constexpr TypePattern IeeeRoundType{ |
137 | DerivedType, KindCode::ieeeRoundType}; |
138 | static constexpr TypePattern TeamType{DerivedType, KindCode::teamType}; |
139 | static constexpr TypePattern DoublePrecision{ |
140 | RealType, KindCode::doublePrecision}; |
141 | static constexpr TypePattern DoublePrecisionComplex{ |
142 | ComplexType, KindCode::doublePrecision}; |
143 | static constexpr TypePattern QuadPrecision{RealType, KindCode::quadPrecision}; |
144 | static constexpr TypePattern SubscriptInt{IntType, KindCode::subscript}; |
145 | |
146 | // Match any kind of some intrinsic or derived types |
147 | static constexpr TypePattern AnyInt{IntType, KindCode::any}; |
148 | static constexpr TypePattern AnyIntOrUnsigned{IntOrUnsignedType, KindCode::any}; |
149 | static constexpr TypePattern AnyReal{RealType, KindCode::any}; |
150 | static constexpr TypePattern AnyIntOrReal{IntOrRealType, KindCode::any}; |
151 | static constexpr TypePattern AnyIntUnsignedOrReal{ |
152 | IntUnsignedOrRealType, KindCode::any}; |
153 | static constexpr TypePattern AnyIntOrRealOrChar{ |
154 | IntOrRealOrCharType, KindCode::any}; |
155 | static constexpr TypePattern AnyIntOrLogical{IntOrLogicalType, KindCode::any}; |
156 | static constexpr TypePattern AnyComplex{ComplexType, KindCode::any}; |
157 | static constexpr TypePattern AnyFloating{FloatingType, KindCode::any}; |
158 | static constexpr TypePattern AnyNumeric{NumericType, KindCode::any}; |
159 | static constexpr TypePattern AnyChar{CharType, KindCode::any}; |
160 | static constexpr TypePattern AnyLogical{LogicalType, KindCode::any}; |
161 | static constexpr TypePattern AnyRelatable{RelatableType, KindCode::any}; |
162 | static constexpr TypePattern AnyIntrinsic{IntrinsicType, KindCode::any}; |
163 | static constexpr TypePattern ExtensibleDerived{DerivedType, KindCode::any}; |
164 | static constexpr TypePattern AnyData{AnyType, KindCode::any}; |
165 | |
166 | // Type is irrelevant, but not BOZ (for PRESENT(), OPTIONAL(), &c.) |
167 | static constexpr TypePattern Addressable{AnyType, KindCode::addressable}; |
168 | |
169 | // Match some kind of some intrinsic type(s); all "Same" values must match, |
170 | // even when not in the same category (e.g., SameComplex and SameReal). |
171 | // Can be used to specify a result so long as at least one argument is |
172 | // a "Same". |
173 | static constexpr TypePattern SameInt{IntType, KindCode::same}; |
174 | static constexpr TypePattern SameIntOrUnsigned{ |
175 | IntOrUnsignedType, KindCode::same}; |
176 | static constexpr TypePattern SameReal{RealType, KindCode::same}; |
177 | static constexpr TypePattern SameIntOrReal{IntOrRealType, KindCode::same}; |
178 | static constexpr TypePattern SameIntUnsignedOrReal{ |
179 | IntUnsignedOrRealType, KindCode::same}; |
180 | static constexpr TypePattern SameComplex{ComplexType, KindCode::same}; |
181 | static constexpr TypePattern SameFloating{FloatingType, KindCode::same}; |
182 | static constexpr TypePattern SameNumeric{NumericType, KindCode::same}; |
183 | static constexpr TypePattern SameChar{CharType, KindCode::same}; |
184 | static constexpr TypePattern SameCharNoLen{CharType, KindCode::sameKind}; |
185 | static constexpr TypePattern SameLogical{LogicalType, KindCode::same}; |
186 | static constexpr TypePattern SameRelatable{RelatableType, KindCode::same}; |
187 | static constexpr TypePattern SameIntrinsic{IntrinsicType, KindCode::same}; |
188 | static constexpr TypePattern SameType{AnyType, KindCode::same}; |
189 | |
190 | // Match some kind of some INTEGER or REAL type(s); when argument types |
191 | // &/or kinds differ, their values are converted as if they were operands to |
192 | // an intrinsic operation like addition. This is a nonstandard but nearly |
193 | // universal extension feature. |
194 | static constexpr TypePattern OperandInt{IntType, KindCode::operand}; |
195 | static constexpr TypePattern OperandReal{RealType, KindCode::operand}; |
196 | static constexpr TypePattern OperandIntOrReal{IntOrRealType, KindCode::operand}; |
197 | |
198 | static constexpr TypePattern OperandUnsigned{UnsignedType, KindCode::operand}; |
199 | |
200 | // For ASSOCIATED, the first argument is a typeless pointer |
201 | static constexpr TypePattern AnyPointer{AnyType, KindCode::nullPointerType}; |
202 | |
203 | // For DOT_PRODUCT and MATMUL, the result type depends on the arguments |
204 | static constexpr TypePattern ResultLogical{LogicalType, KindCode::likeMultiply}; |
205 | static constexpr TypePattern ResultNumeric{NumericType, KindCode::likeMultiply}; |
206 | |
207 | // Result types with known category and KIND= |
208 | static constexpr TypePattern KINDInt{IntType, KindCode::effectiveKind}; |
209 | static constexpr TypePattern KINDUnsigned{ |
210 | UnsignedType, KindCode::effectiveKind}; |
211 | static constexpr TypePattern KINDReal{RealType, KindCode::effectiveKind}; |
212 | static constexpr TypePattern KINDComplex{ComplexType, KindCode::effectiveKind}; |
213 | static constexpr TypePattern KINDChar{CharType, KindCode::effectiveKind}; |
214 | static constexpr TypePattern KINDLogical{LogicalType, KindCode::effectiveKind}; |
215 | |
216 | static constexpr TypePattern AtomicInt{IntType, KindCode::atomicIntKind}; |
217 | static constexpr TypePattern AtomicIntOrLogical{ |
218 | IntOrLogicalType, KindCode::atomicIntOrLogicalKind}; |
219 | static constexpr TypePattern SameAtom{IntOrLogicalType, KindCode::sameAtom}; |
220 | |
221 | // The default rank pattern for dummy arguments and function results is |
222 | // "elemental". |
223 | ENUM_CLASS(Rank, |
224 | elemental, // scalar, or array that conforms with other array arguments |
225 | elementalOrBOZ, // elemental, or typeless BOZ literal scalar |
226 | scalar, vector, |
227 | shape, // INTEGER vector of known length and no negative element |
228 | matrix, |
229 | array, // not scalar, rank is known and greater than zero |
230 | coarray, // rank is known and can be scalar; has nonzero corank |
231 | atom, // is scalar and has nonzero corank or is coindexed |
232 | known, // rank is known and can be scalar |
233 | anyOrAssumedRank, // any rank, or assumed; assumed-type TYPE(*) allowed |
234 | arrayOrAssumedRank, // rank >= 1 or assumed; assumed-type TYPE(*) allowed |
235 | conformable, // scalar, or array of same rank & shape as "array" argument |
236 | reduceOperation, // a pure function with constraints for REDUCE |
237 | dimReduced, // scalar if no DIM= argument, else rank(array)-1 |
238 | dimRemovedOrScalar, // rank(array)-1 (less DIM) or scalar |
239 | scalarIfDim, // scalar if DIM= argument is present, else rank one array |
240 | locReduced, // vector(1:rank) if no DIM= argument, else rank(array)-1 |
241 | rankPlus1, // rank(known)+1 |
242 | shaped, // rank is length of SHAPE vector |
243 | ) |
244 | |
245 | ENUM_CLASS(Optionality, required, |
246 | optional, // unless DIM= for SIZE(assumedSize) |
247 | missing, // for DIM= cases like FINDLOC |
248 | repeats, // for MAX/MIN and their several variants |
249 | ) |
250 | |
251 | ENUM_CLASS(ArgFlag, none, |
252 | canBeNullPointer, // actual argument can be NULL(with or without |
253 | // MOLD=pointer) |
254 | canBeMoldNull, // actual argument can be NULL(MOLD=any) |
255 | canBeNullAllocatable, // actual argument can be NULL(MOLD=allocatable) |
256 | defaultsToSameKind, // for MatchingDefaultKIND |
257 | defaultsToSizeKind, // for SizeDefaultKIND |
258 | defaultsToDefaultForResult, // for DefaultingKIND |
259 | notAssumedSize, |
260 | onlyConstantInquiry) // e.g., PRECISION(X) |
261 | |
262 | struct IntrinsicDummyArgument { |
263 | const char *keyword{nullptr}; |
264 | TypePattern typePattern; |
265 | Rank rank{Rank::elemental}; |
266 | Optionality optionality{Optionality::required}; |
267 | common::Intent intent{common::Intent::In}; |
268 | common::EnumSet<ArgFlag, 32> flags{}; |
269 | llvm::raw_ostream &Dump(llvm::raw_ostream &) const; |
270 | }; |
271 | |
272 | // constexpr abbreviations for popular arguments: |
273 | // DefaultingKIND is a KIND= argument whose default value is the appropriate |
274 | // KIND(0), KIND(0.0), KIND(''), &c. value for the function result. |
275 | static constexpr IntrinsicDummyArgument DefaultingKIND{"kind", |
276 | {IntType, KindCode::kindArg}, Rank::scalar, Optionality::optional, |
277 | common::Intent::In, {ArgFlag::defaultsToDefaultForResult}}; |
278 | // MatchingDefaultKIND is a KIND= argument whose default value is the |
279 | // kind of any "Same" function argument (viz., the one whose kind pattern is |
280 | // "same"). |
281 | static constexpr IntrinsicDummyArgument MatchingDefaultKIND{"kind", |
282 | {IntType, KindCode::kindArg}, Rank::scalar, Optionality::optional, |
283 | common::Intent::In, {ArgFlag::defaultsToSameKind}}; |
284 | // SizeDefaultKind is a KIND= argument whose default value should be |
285 | // the kind of INTEGER used for address calculations, and can be |
286 | // set so with a compiler flag; but the standard mandates the |
287 | // kind of default INTEGER. |
288 | static constexpr IntrinsicDummyArgument SizeDefaultKIND{"kind", |
289 | {IntType, KindCode::kindArg}, Rank::scalar, Optionality::optional, |
290 | common::Intent::In, {ArgFlag::defaultsToSizeKind}}; |
291 | static constexpr IntrinsicDummyArgument RequiredDIM{"dim", |
292 | {IntType, KindCode::dimArg}, Rank::scalar, Optionality::required, |
293 | common::Intent::In}; |
294 | static constexpr IntrinsicDummyArgument OptionalDIM{"dim", |
295 | {IntType, KindCode::dimArg}, Rank::scalar, Optionality::optional, |
296 | common::Intent::In}; |
297 | static constexpr IntrinsicDummyArgument MissingDIM{"dim", |
298 | {IntType, KindCode::dimArg}, Rank::scalar, Optionality::missing, |
299 | common::Intent::In}; |
300 | static constexpr IntrinsicDummyArgument OptionalMASK{"mask", AnyLogical, |
301 | Rank::conformable, Optionality::optional, common::Intent::In}; |
302 | static constexpr IntrinsicDummyArgument OptionalTEAM{ |
303 | "team", TeamType, Rank::scalar, Optionality::optional, common::Intent::In}; |
304 | |
305 | struct IntrinsicInterface { |
306 | static constexpr int maxArguments{7}; // if not a MAX/MIN(...) |
307 | const char *name{nullptr}; |
308 | IntrinsicDummyArgument dummy[maxArguments]; |
309 | TypePattern result; |
310 | Rank rank{Rank::elemental}; |
311 | IntrinsicClass intrinsicClass{IntrinsicClass::elementalFunction}; |
312 | std::optional<SpecificCall> Match(const CallCharacteristics &, |
313 | const common::IntrinsicTypeDefaultKinds &, ActualArguments &, |
314 | FoldingContext &context, const semantics::Scope *builtins) const; |
315 | int CountArguments() const; |
316 | llvm::raw_ostream &Dump(llvm::raw_ostream &) const; |
317 | }; |
318 | |
319 | int IntrinsicInterface::CountArguments() const { |
320 | int n{0}; |
321 | while (n < maxArguments && dummy[n].keyword) { |
322 | ++n; |
323 | } |
324 | return n; |
325 | } |
326 | |
327 | // GENERIC INTRINSIC FUNCTION INTERFACES |
328 | // Each entry in this table defines a pattern. Some intrinsic |
329 | // functions have more than one such pattern. Besides the name |
330 | // of the intrinsic function, each pattern has specifications for |
331 | // the dummy arguments and for the result of the function. |
332 | // The dummy argument patterns each have a name (these are from the |
333 | // standard, but rarely appear in actual code), a type and kind |
334 | // pattern, allowable ranks, and optionality indicators. |
335 | // Be advised, the default rank pattern is "elemental". |
336 | static const IntrinsicInterface genericIntrinsicFunction[]{ |
337 | {"abs", {{ "a", SameIntOrReal}}, SameIntOrReal}, |
338 | {"abs", {{ "a", SameComplex}}, SameReal}, |
339 | {"achar", {{ "i", AnyInt, Rank::elementalOrBOZ}, DefaultingKIND}, KINDChar}, |
340 | {"acos", {{ "x", SameFloating}}, SameFloating}, |
341 | {"acosd", {{ "x", SameFloating}}, SameFloating}, |
342 | {"acosh", {{ "x", SameFloating}}, SameFloating}, |
343 | {"adjustl", {{ "string", SameChar}}, SameChar}, |
344 | {"adjustr", {{ "string", SameChar}}, SameChar}, |
345 | {"aimag", {{ "z", SameComplex}}, SameReal}, |
346 | {"aint", {{ "a", SameReal}, MatchingDefaultKIND}, KINDReal}, |
347 | {"all", {{ "mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical, |
348 | Rank::dimReduced, IntrinsicClass::transformationalFunction}, |
349 | {"allocated", {{ "scalar", AnyData, Rank::scalar}}, DefaultLogical, |
350 | Rank::elemental, IntrinsicClass::inquiryFunction}, |
351 | {"allocated", |
352 | {{"array", AnyData, Rank::anyOrAssumedRank, Optionality::required, |
353 | common::Intent::In, {ArgFlag::canBeNullAllocatable}}}, |
354 | DefaultLogical, Rank::elemental, IntrinsicClass::inquiryFunction}, |
355 | {"anint", {{ "a", SameReal}, MatchingDefaultKIND}, KINDReal}, |
356 | {"any", {{ "mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical, |
357 | Rank::dimReduced, IntrinsicClass::transformationalFunction}, |
358 | {"asin", {{ "x", SameFloating}}, SameFloating}, |
359 | {"asind", {{ "x", SameFloating}}, SameFloating}, |
360 | {"asinh", {{ "x", SameFloating}}, SameFloating}, |
361 | {"associated", |
362 | {{"pointer", AnyPointer, Rank::anyOrAssumedRank, Optionality::required, |
363 | common::Intent::In, {ArgFlag::canBeNullPointer}}, |
364 | {"target", Addressable, Rank::anyOrAssumedRank, |
365 | Optionality::optional, common::Intent::In, |
366 | {ArgFlag::canBeNullPointer}}}, |
367 | DefaultLogical, Rank::elemental, IntrinsicClass::inquiryFunction}, |
368 | {"atan", {{ "x", SameFloating}}, SameFloating}, |
369 | {"atan", {{ "y", OperandReal}, { "x", OperandReal}}, OperandReal}, |
370 | {"atand", {{ "x", SameFloating}}, SameFloating}, |
371 | {"atand", {{ "y", OperandReal}, { "x", OperandReal}}, OperandReal}, |
372 | {"atan2", {{ "y", OperandReal}, { "x", OperandReal}}, OperandReal}, |
373 | {"atan2d", {{ "y", OperandReal}, { "x", OperandReal}}, OperandReal}, |
374 | {"atanpi", {{ "x", SameFloating}}, SameFloating}, |
375 | {"atanpi", {{ "y", OperandReal}, { "x", OperandReal}}, OperandReal}, |
376 | {"atan2pi", {{ "y", OperandReal}, { "x", OperandReal}}, OperandReal}, |
377 | {"atanh", {{ "x", SameFloating}}, SameFloating}, |
378 | {"bessel_j0", {{ "x", SameReal}}, SameReal}, |
379 | {"bessel_j1", {{ "x", SameReal}}, SameReal}, |
380 | {"bessel_jn", {{ "n", AnyInt}, { "x", SameReal}}, SameReal}, |
381 | {"bessel_jn", |
382 | {{"n1", AnyInt, Rank::scalar}, { "n2", AnyInt, Rank::scalar}, |
383 | {"x", SameReal, Rank::scalar}}, |
384 | SameReal, Rank::vector, IntrinsicClass::transformationalFunction}, |
385 | {"bessel_y0", {{ "x", SameReal}}, SameReal}, |
386 | {"bessel_y1", {{ "x", SameReal}}, SameReal}, |
387 | {"bessel_yn", {{ "n", AnyInt}, { "x", SameReal}}, SameReal}, |
388 | {"bessel_yn", |
389 | {{"n1", AnyInt, Rank::scalar}, { "n2", AnyInt, Rank::scalar}, |
390 | {"x", SameReal, Rank::scalar}}, |
391 | SameReal, Rank::vector, IntrinsicClass::transformationalFunction}, |
392 | {"bge", |
393 | {{"i", AnyIntOrUnsigned, Rank::elementalOrBOZ}, |
394 | {"j", AnyIntOrUnsigned, Rank::elementalOrBOZ}}, |
395 | DefaultLogical}, |
396 | {"bgt", |
397 | {{"i", AnyIntOrUnsigned, Rank::elementalOrBOZ}, |
398 | {"j", AnyIntOrUnsigned, Rank::elementalOrBOZ}}, |
399 | DefaultLogical}, |
400 | {"bit_size", |
401 | {{"i", SameIntOrUnsigned, Rank::anyOrAssumedRank, Optionality::required, |
402 | common::Intent::In, |
403 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
404 | SameInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
405 | {"ble", |
406 | {{"i", AnyIntOrUnsigned, Rank::elementalOrBOZ}, |
407 | {"j", AnyIntOrUnsigned, Rank::elementalOrBOZ}}, |
408 | DefaultLogical}, |
409 | {"blt", |
410 | {{"i", AnyIntOrUnsigned, Rank::elementalOrBOZ}, |
411 | {"j", AnyIntOrUnsigned, Rank::elementalOrBOZ}}, |
412 | DefaultLogical}, |
413 | {"btest", {{ "i", AnyIntOrUnsigned, Rank::elementalOrBOZ}, { "pos", AnyInt}}, |
414 | DefaultLogical}, |
415 | {"ceiling", {{ "a", AnyReal}, DefaultingKIND}, KINDInt}, |
416 | {"char", {{ "i", AnyInt, Rank::elementalOrBOZ}, DefaultingKIND}, KINDChar}, |
417 | {"chdir", {{ "name", DefaultChar, Rank::scalar, Optionality::required}}, |
418 | DefaultInt}, |
419 | {"cmplx", {{ "x", AnyComplex}, DefaultingKIND}, KINDComplex}, |
420 | {"cmplx", |
421 | {{"x", AnyIntUnsignedOrReal, Rank::elementalOrBOZ}, |
422 | {"y", AnyIntUnsignedOrReal, Rank::elementalOrBOZ, |
423 | Optionality::optional}, |
424 | DefaultingKIND}, |
425 | KINDComplex}, |
426 | {"command_argument_count", {}, DefaultInt, Rank::scalar, |
427 | IntrinsicClass::transformationalFunction}, |
428 | {"conjg", {{ "z", SameComplex}}, SameComplex}, |
429 | {"cos", {{ "x", SameFloating}}, SameFloating}, |
430 | {"cosd", {{ "x", SameFloating}}, SameFloating}, |
431 | {"cosh", {{ "x", SameFloating}}, SameFloating}, |
432 | {"coshape", {{ "coarray", AnyData, Rank::coarray}, SizeDefaultKIND}, KINDInt, |
433 | Rank::vector, IntrinsicClass::inquiryFunction}, |
434 | {"count", {{ "mask", AnyLogical, Rank::array}, OptionalDIM, DefaultingKIND}, |
435 | KINDInt, Rank::dimReduced, IntrinsicClass::transformationalFunction}, |
436 | {"cshift", |
437 | {{"array", SameType, Rank::array}, |
438 | {"shift", AnyInt, Rank::dimRemovedOrScalar}, OptionalDIM}, |
439 | SameType, Rank::conformable, IntrinsicClass::transformationalFunction}, |
440 | {"dble", {{ "a", AnyNumeric, Rank::elementalOrBOZ}}, DoublePrecision}, |
441 | {"digits", |
442 | {{"x", AnyIntUnsignedOrReal, Rank::anyOrAssumedRank, |
443 | Optionality::required, common::Intent::In, |
444 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
445 | DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
446 | {"dim", {{ "x", OperandIntOrReal}, { "y", OperandIntOrReal}}, |
447 | OperandIntOrReal}, |
448 | {"dot_product", |
449 | {{"vector_a", AnyLogical, Rank::vector}, |
450 | {"vector_b", AnyLogical, Rank::vector}}, |
451 | ResultLogical, Rank::scalar, IntrinsicClass::transformationalFunction}, |
452 | {"dot_product", |
453 | {{"vector_a", AnyComplex, Rank::vector}, |
454 | {"vector_b", AnyNumeric, Rank::vector}}, |
455 | ResultNumeric, Rank::scalar, // conjugates vector_a |
456 | IntrinsicClass::transformationalFunction}, |
457 | {"dot_product", |
458 | {{"vector_a", AnyIntUnsignedOrReal, Rank::vector}, |
459 | {"vector_b", AnyNumeric, Rank::vector}}, |
460 | ResultNumeric, Rank::scalar, IntrinsicClass::transformationalFunction}, |
461 | {"dprod", {{ "x", DefaultReal}, { "y", DefaultReal}}, DoublePrecision}, |
462 | {"dshiftl", |
463 | {{"i", SameIntOrUnsigned}, |
464 | {"j", SameIntOrUnsigned, Rank::elementalOrBOZ}, { "shift", AnyInt}}, |
465 | SameIntOrUnsigned}, |
466 | {"dshiftl", {{ "i", BOZ}, { "j", SameIntOrUnsigned}, { "shift", AnyInt}}, |
467 | SameIntOrUnsigned}, |
468 | {"dshiftr", |
469 | {{"i", SameIntOrUnsigned}, |
470 | {"j", SameIntOrUnsigned, Rank::elementalOrBOZ}, { "shift", AnyInt}}, |
471 | SameIntOrUnsigned}, |
472 | {"dshiftr", {{ "i", BOZ}, { "j", SameIntOrUnsigned}, { "shift", AnyInt}}, |
473 | SameIntOrUnsigned}, |
474 | {"eoshift", |
475 | {{"array", SameType, Rank::array}, |
476 | {"shift", AnyInt, Rank::dimRemovedOrScalar}, |
477 | // BOUNDARY= is not optional for non-intrinsic types |
478 | {"boundary", SameType, Rank::dimRemovedOrScalar}, OptionalDIM}, |
479 | SameType, Rank::conformable, IntrinsicClass::transformationalFunction}, |
480 | {"eoshift", |
481 | {{"array", SameIntrinsic, Rank::array}, |
482 | {"shift", AnyInt, Rank::dimRemovedOrScalar}, |
483 | {"boundary", SameIntrinsic, Rank::dimRemovedOrScalar, |
484 | Optionality::optional}, |
485 | OptionalDIM}, |
486 | SameIntrinsic, Rank::conformable, |
487 | IntrinsicClass::transformationalFunction}, |
488 | {"epsilon", |
489 | {{"x", SameReal, Rank::anyOrAssumedRank, Optionality::required, |
490 | common::Intent::In, |
491 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
492 | SameReal, Rank::scalar, IntrinsicClass::inquiryFunction}, |
493 | {"erf", {{ "x", SameReal}}, SameReal}, |
494 | {"erfc", {{ "x", SameReal}}, SameReal}, |
495 | {"erfc_scaled", {{ "x", SameReal}}, SameReal}, |
496 | {"etime", |
497 | {{"values", TypePattern{RealType, KindCode::exactKind, 4}, Rank::vector, |
498 | Optionality::required, common::Intent::Out}}, |
499 | TypePattern{RealType, KindCode::exactKind, 4}}, |
500 | {"exp", {{ "x", SameFloating}}, SameFloating}, |
501 | {"exp", {{ "x", SameFloating}}, SameFloating}, |
502 | {"exponent", {{ "x", AnyReal}}, DefaultInt}, |
503 | {"exp", {{ "x", SameFloating}}, SameFloating}, |
504 | {"extends_type_of", |
505 | {{"a", ExtensibleDerived, Rank::anyOrAssumedRank, Optionality::required, |
506 | common::Intent::In, {ArgFlag::canBeMoldNull}}, |
507 | {"mold", ExtensibleDerived, Rank::anyOrAssumedRank, |
508 | Optionality::required, common::Intent::In, |
509 | {ArgFlag::canBeMoldNull}}}, |
510 | DefaultLogical, Rank::scalar, IntrinsicClass::inquiryFunction}, |
511 | {"failed_images", {OptionalTEAM, SizeDefaultKIND}, KINDInt, Rank::vector, |
512 | IntrinsicClass::transformationalFunction}, |
513 | {"findloc", |
514 | {{"array", AnyNumeric, Rank::array}, |
515 | {"value", AnyNumeric, Rank::scalar}, RequiredDIM, OptionalMASK, |
516 | SizeDefaultKIND, |
517 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
518 | KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction}, |
519 | {"findloc", |
520 | {{"array", AnyNumeric, Rank::array}, |
521 | {"value", AnyNumeric, Rank::scalar}, MissingDIM, OptionalMASK, |
522 | SizeDefaultKIND, |
523 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
524 | KINDInt, Rank::vector, IntrinsicClass::transformationalFunction}, |
525 | {"findloc", |
526 | {{"array", SameCharNoLen, Rank::array}, |
527 | {"value", SameCharNoLen, Rank::scalar}, RequiredDIM, OptionalMASK, |
528 | SizeDefaultKIND, |
529 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
530 | KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction}, |
531 | {"findloc", |
532 | {{"array", SameCharNoLen, Rank::array}, |
533 | {"value", SameCharNoLen, Rank::scalar}, MissingDIM, OptionalMASK, |
534 | SizeDefaultKIND, |
535 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
536 | KINDInt, Rank::vector, IntrinsicClass::transformationalFunction}, |
537 | {"findloc", |
538 | {{"array", AnyLogical, Rank::array}, |
539 | {"value", AnyLogical, Rank::scalar}, RequiredDIM, OptionalMASK, |
540 | SizeDefaultKIND, |
541 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
542 | KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction}, |
543 | {"findloc", |
544 | {{"array", AnyLogical, Rank::array}, |
545 | {"value", AnyLogical, Rank::scalar}, MissingDIM, OptionalMASK, |
546 | SizeDefaultKIND, |
547 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
548 | KINDInt, Rank::vector, IntrinsicClass::transformationalFunction}, |
549 | {"floor", {{ "a", AnyReal}, DefaultingKIND}, KINDInt}, |
550 | {"fraction", {{ "x", SameReal}}, SameReal}, |
551 | {"fseek", |
552 | {{"unit", AnyInt, Rank::scalar}, { "offset", AnyInt, Rank::scalar}, |
553 | {"whence", AnyInt, Rank::scalar}}, |
554 | DefaultInt, Rank::scalar}, |
555 | {"ftell", {{ "unit", AnyInt, Rank::scalar}}, |
556 | TypePattern{IntType, KindCode::exactKind, 8}, Rank::scalar}, |
557 | {"gamma", {{ "x", SameReal}}, SameReal}, |
558 | {"get_team", {{ "level", DefaultInt, Rank::scalar, Optionality::optional}}, |
559 | TeamType, Rank::scalar, IntrinsicClass::transformationalFunction}, |
560 | {"getcwd", |
561 | {{"c", DefaultChar, Rank::scalar, Optionality::required, |
562 | common::Intent::Out}}, |
563 | TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}}, |
564 | {"getgid", {}, DefaultInt}, |
565 | {"getpid", {}, DefaultInt}, |
566 | {"getuid", {}, DefaultInt}, |
567 | {"hostnm", |
568 | {{"c", DefaultChar, Rank::scalar, Optionality::required, |
569 | common::Intent::Out}}, |
570 | TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}}, |
571 | {"huge", |
572 | {{"x", SameIntUnsignedOrReal, Rank::anyOrAssumedRank, |
573 | Optionality::required, common::Intent::In, |
574 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
575 | SameIntUnsignedOrReal, Rank::scalar, IntrinsicClass::inquiryFunction}, |
576 | {"hypot", {{ "x", OperandReal}, { "y", OperandReal}}, OperandReal}, |
577 | {"iachar", {{ "c", AnyChar}, DefaultingKIND}, KINDInt}, |
578 | {"iall", |
579 | {{"array", SameIntOrUnsigned, Rank::array}, RequiredDIM, OptionalMASK}, |
580 | SameIntOrUnsigned, Rank::dimReduced, |
581 | IntrinsicClass::transformationalFunction}, |
582 | {"iall", |
583 | {{"array", SameIntOrUnsigned, Rank::array}, MissingDIM, OptionalMASK}, |
584 | SameIntOrUnsigned, Rank::scalar, |
585 | IntrinsicClass::transformationalFunction}, |
586 | {"iany", |
587 | {{"array", SameIntOrUnsigned, Rank::array}, RequiredDIM, OptionalMASK}, |
588 | SameIntOrUnsigned, Rank::dimReduced, |
589 | IntrinsicClass::transformationalFunction}, |
590 | {"iany", |
591 | {{"array", SameIntOrUnsigned, Rank::array}, MissingDIM, OptionalMASK}, |
592 | SameIntOrUnsigned, Rank::scalar, |
593 | IntrinsicClass::transformationalFunction}, |
594 | {"iparity", |
595 | {{"array", SameIntOrUnsigned, Rank::array}, RequiredDIM, OptionalMASK}, |
596 | SameIntOrUnsigned, Rank::dimReduced, |
597 | IntrinsicClass::transformationalFunction}, |
598 | {"iparity", |
599 | {{"array", SameIntOrUnsigned, Rank::array}, MissingDIM, OptionalMASK}, |
600 | SameIntOrUnsigned, Rank::scalar, |
601 | IntrinsicClass::transformationalFunction}, |
602 | {"iand", {{ "i", OperandInt}, { "j", OperandInt, Rank::elementalOrBOZ}}, |
603 | OperandInt}, |
604 | {"iand", |
605 | {{"i", OperandUnsigned}, { "j", OperandUnsigned, Rank::elementalOrBOZ}}, |
606 | OperandUnsigned}, |
607 | {"iand", {{ "i", BOZ}, { "j", SameIntOrUnsigned}}, SameIntOrUnsigned}, |
608 | {"ibclr", {{ "i", SameIntOrUnsigned}, { "pos", AnyInt}}, SameIntOrUnsigned}, |
609 | {"ibits", {{ "i", SameIntOrUnsigned}, { "pos", AnyInt}, { "len", AnyInt}}, |
610 | SameIntOrUnsigned}, |
611 | {"ibset", {{ "i", SameIntOrUnsigned}, { "pos", AnyInt}}, SameIntOrUnsigned}, |
612 | {"ichar", {{ "c", AnyChar}, DefaultingKIND}, KINDInt}, |
613 | {"ieor", {{ "i", OperandInt}, { "j", OperandInt, Rank::elementalOrBOZ}}, |
614 | OperandInt}, |
615 | {"ieor", |
616 | {{"i", OperandUnsigned}, { "j", OperandUnsigned, Rank::elementalOrBOZ}}, |
617 | OperandUnsigned}, |
618 | {"ieor", {{ "i", BOZ}, { "j", SameIntOrUnsigned}}, SameIntOrUnsigned}, |
619 | {"image_index", |
620 | {{"coarray", AnyData, Rank::coarray}, { "sub", AnyInt, Rank::vector}}, |
621 | DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction}, |
622 | {"image_index", |
623 | {{"coarray", AnyData, Rank::coarray}, { "sub", AnyInt, Rank::vector}, |
624 | {"team", TeamType, Rank::scalar}}, |
625 | DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction}, |
626 | {"image_index", |
627 | {{"coarray", AnyData, Rank::coarray}, { "sub", AnyInt, Rank::vector}, |
628 | {"team_number", AnyInt, Rank::scalar}}, |
629 | DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction}, |
630 | {"image_status", {{ "image", SameInt}, OptionalTEAM}, DefaultInt}, |
631 | {"index", |
632 | {{"string", SameCharNoLen}, { "substring", SameCharNoLen}, |
633 | {"back", AnyLogical, Rank::elemental, Optionality::optional}, |
634 | DefaultingKIND}, |
635 | KINDInt}, |
636 | {"int", {{ "a", AnyNumeric, Rank::elementalOrBOZ}, DefaultingKIND}, KINDInt}, |
637 | {"int2", {{ "a", AnyNumeric, Rank::elementalOrBOZ}}, |
638 | TypePattern{IntType, KindCode::exactKind, 2}}, |
639 | {"int8", {{ "a", AnyNumeric, Rank::elementalOrBOZ}}, |
640 | TypePattern{IntType, KindCode::exactKind, 8}}, |
641 | {"int_ptr_kind", {}, DefaultInt, Rank::scalar}, |
642 | {"ior", {{ "i", OperandInt}, { "j", OperandInt, Rank::elementalOrBOZ}}, |
643 | OperandInt}, |
644 | {"ior", |
645 | {{"i", OperandUnsigned}, { "j", OperandUnsigned, Rank::elementalOrBOZ}}, |
646 | OperandUnsigned}, |
647 | {"ior", {{ "i", BOZ}, { "j", SameIntOrUnsigned}}, SameIntOrUnsigned}, |
648 | {"ishft", {{ "i", SameIntOrUnsigned}, { "shift", AnyInt}}, SameIntOrUnsigned}, |
649 | {"ishftc", |
650 | {{"i", SameIntOrUnsigned}, { "shift", AnyInt}, |
651 | {"size", AnyInt, Rank::elemental, Optionality::optional}}, |
652 | SameIntOrUnsigned}, |
653 | {"isnan", {{ "a", AnyFloating}}, DefaultLogical}, |
654 | {"is_contiguous", {{ "array", Addressable, Rank::anyOrAssumedRank}}, |
655 | DefaultLogical, Rank::elemental, IntrinsicClass::inquiryFunction}, |
656 | {"is_iostat_end", {{ "i", AnyInt}}, DefaultLogical}, |
657 | {"is_iostat_eor", {{ "i", AnyInt}}, DefaultLogical}, |
658 | {"izext", {{ "i", AnyInt}}, TypePattern{IntType, KindCode::exactKind, 2}}, |
659 | {"jzext", {{ "i", AnyInt}}, DefaultInt}, |
660 | {"kind", |
661 | {{"x", AnyIntrinsic, Rank::anyOrAssumedRank, Optionality::required, |
662 | common::Intent::In, |
663 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
664 | DefaultInt, Rank::elemental, IntrinsicClass::inquiryFunction}, |
665 | {"lbound", |
666 | {{"array", AnyData, Rank::anyOrAssumedRank}, RequiredDIM, |
667 | SizeDefaultKIND}, |
668 | KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
669 | {"lbound", {{ "array", AnyData, Rank::arrayOrAssumedRank}, SizeDefaultKIND}, |
670 | KINDInt, Rank::vector, IntrinsicClass::inquiryFunction}, |
671 | {"lcobound", |
672 | {{"coarray", AnyData, Rank::coarray}, OptionalDIM, SizeDefaultKIND}, |
673 | KINDInt, Rank::scalarIfDim, IntrinsicClass::inquiryFunction}, |
674 | {"leadz", {{ "i", AnyInt}}, DefaultInt}, |
675 | {"len", |
676 | {{"string", AnyChar, Rank::anyOrAssumedRank, Optionality::required, |
677 | common::Intent::In, {ArgFlag::canBeMoldNull}}, |
678 | DefaultingKIND}, |
679 | KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
680 | {"len_trim", {{ "string", AnyChar}, DefaultingKIND}, KINDInt}, |
681 | {"lge", {{ "string_a", SameCharNoLen}, { "string_b", SameCharNoLen}}, |
682 | DefaultLogical}, |
683 | {"lgt", {{ "string_a", SameCharNoLen}, { "string_b", SameCharNoLen}}, |
684 | DefaultLogical}, |
685 | {"lle", {{ "string_a", SameCharNoLen}, { "string_b", SameCharNoLen}}, |
686 | DefaultLogical}, |
687 | {"llt", {{ "string_a", SameCharNoLen}, { "string_b", SameCharNoLen}}, |
688 | DefaultLogical}, |
689 | {"lnblnk", {{ "string", AnyChar}}, DefaultInt}, |
690 | {"loc", {{ "x", Addressable, Rank::anyOrAssumedRank}}, SubscriptInt, |
691 | Rank::scalar}, |
692 | {"log", {{ "x", SameFloating}}, SameFloating}, |
693 | {"log10", {{ "x", SameReal}}, SameReal}, |
694 | {"logical", {{ "l", AnyLogical}, DefaultingKIND}, KINDLogical}, |
695 | {"log_gamma", {{ "x", SameReal}}, SameReal}, |
696 | {"malloc", {{ "size", AnyInt}}, SubscriptInt}, |
697 | {"matmul", |
698 | {{"matrix_a", AnyLogical, Rank::vector}, |
699 | {"matrix_b", AnyLogical, Rank::matrix}}, |
700 | ResultLogical, Rank::vector, IntrinsicClass::transformationalFunction}, |
701 | {"matmul", |
702 | {{"matrix_a", AnyLogical, Rank::matrix}, |
703 | {"matrix_b", AnyLogical, Rank::vector}}, |
704 | ResultLogical, Rank::vector, IntrinsicClass::transformationalFunction}, |
705 | {"matmul", |
706 | {{"matrix_a", AnyLogical, Rank::matrix}, |
707 | {"matrix_b", AnyLogical, Rank::matrix}}, |
708 | ResultLogical, Rank::matrix, IntrinsicClass::transformationalFunction}, |
709 | {"matmul", |
710 | {{"matrix_a", AnyNumeric, Rank::vector}, |
711 | {"matrix_b", AnyNumeric, Rank::matrix}}, |
712 | ResultNumeric, Rank::vector, IntrinsicClass::transformationalFunction}, |
713 | {"matmul", |
714 | {{"matrix_a", AnyNumeric, Rank::matrix}, |
715 | {"matrix_b", AnyNumeric, Rank::vector}}, |
716 | ResultNumeric, Rank::vector, IntrinsicClass::transformationalFunction}, |
717 | {"matmul", |
718 | {{"matrix_a", AnyNumeric, Rank::matrix}, |
719 | {"matrix_b", AnyNumeric, Rank::matrix}}, |
720 | ResultNumeric, Rank::matrix, IntrinsicClass::transformationalFunction}, |
721 | {"maskl", {{ "i", AnyInt}, DefaultingKIND}, KINDInt}, |
722 | {"maskr", {{ "i", AnyInt}, DefaultingKIND}, KINDInt}, |
723 | {"max", |
724 | {{"a1", OperandIntOrReal}, { "a2", OperandIntOrReal}, |
725 | {"a3", OperandIntOrReal, Rank::elemental, Optionality::repeats}}, |
726 | OperandIntOrReal}, |
727 | {"max", |
728 | {{"a1", OperandUnsigned}, { "a2", OperandUnsigned}, |
729 | {"a3", OperandUnsigned, Rank::elemental, Optionality::repeats}}, |
730 | OperandUnsigned}, |
731 | {"max", |
732 | {{"a1", SameCharNoLen}, { "a2", SameCharNoLen}, |
733 | {"a3", SameCharNoLen, Rank::elemental, Optionality::repeats}}, |
734 | SameCharNoLen}, |
735 | {"maxexponent", |
736 | {{"x", AnyReal, Rank::anyOrAssumedRank, Optionality::required, |
737 | common::Intent::In, |
738 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
739 | DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
740 | {"maxloc", |
741 | {{"array", AnyRelatable, Rank::array}, RequiredDIM, OptionalMASK, |
742 | SizeDefaultKIND, |
743 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
744 | KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction}, |
745 | {"maxloc", |
746 | {{"array", AnyRelatable, Rank::array}, MissingDIM, OptionalMASK, |
747 | SizeDefaultKIND, |
748 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
749 | KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction}, |
750 | {"maxval", |
751 | {{"array", SameRelatable, Rank::array}, RequiredDIM, OptionalMASK}, |
752 | SameRelatable, Rank::dimReduced, |
753 | IntrinsicClass::transformationalFunction}, |
754 | {"maxval", |
755 | {{"array", SameRelatable, Rank::array}, MissingDIM, OptionalMASK}, |
756 | SameRelatable, Rank::scalar, IntrinsicClass::transformationalFunction}, |
757 | {"merge", |
758 | {{"tsource", SameType}, { "fsource", SameType}, { "mask", AnyLogical}}, |
759 | SameType}, |
760 | {"merge_bits", |
761 | {{"i", SameIntOrUnsigned}, |
762 | {"j", SameIntOrUnsigned, Rank::elementalOrBOZ}, |
763 | {"mask", SameIntOrUnsigned, Rank::elementalOrBOZ}}, |
764 | SameIntOrUnsigned}, |
765 | {"merge_bits", |
766 | {{"i", BOZ}, { "j", SameIntOrUnsigned}, |
767 | {"mask", SameIntOrUnsigned, Rank::elementalOrBOZ}}, |
768 | SameIntOrUnsigned}, |
769 | {"min", |
770 | {{"a1", OperandIntOrReal}, { "a2", OperandIntOrReal}, |
771 | {"a3", OperandIntOrReal, Rank::elemental, Optionality::repeats}}, |
772 | OperandIntOrReal}, |
773 | {"min", |
774 | {{"a1", OperandUnsigned}, { "a2", OperandUnsigned}, |
775 | {"a3", OperandUnsigned, Rank::elemental, Optionality::repeats}}, |
776 | OperandUnsigned}, |
777 | {"min", |
778 | {{"a1", SameCharNoLen}, { "a2", SameCharNoLen}, |
779 | {"a3", SameCharNoLen, Rank::elemental, Optionality::repeats}}, |
780 | SameCharNoLen}, |
781 | {"minexponent", |
782 | {{"x", AnyReal, Rank::anyOrAssumedRank, Optionality::required, |
783 | common::Intent::In, |
784 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
785 | DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
786 | {"minloc", |
787 | {{"array", AnyRelatable, Rank::array}, RequiredDIM, OptionalMASK, |
788 | SizeDefaultKIND, |
789 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
790 | KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction}, |
791 | {"minloc", |
792 | {{"array", AnyRelatable, Rank::array}, MissingDIM, OptionalMASK, |
793 | SizeDefaultKIND, |
794 | {"back", AnyLogical, Rank::scalar, Optionality::optional}}, |
795 | KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction}, |
796 | {"minval", |
797 | {{"array", SameRelatable, Rank::array}, RequiredDIM, OptionalMASK}, |
798 | SameRelatable, Rank::dimReduced, |
799 | IntrinsicClass::transformationalFunction}, |
800 | {"minval", |
801 | {{"array", SameRelatable, Rank::array}, MissingDIM, OptionalMASK}, |
802 | SameRelatable, Rank::scalar, IntrinsicClass::transformationalFunction}, |
803 | {"mod", {{ "a", OperandIntOrReal}, { "p", OperandIntOrReal}}, |
804 | OperandIntOrReal}, |
805 | {"mod", {{ "a", OperandUnsigned}, { "p", OperandUnsigned}}, OperandUnsigned}, |
806 | {"modulo", {{ "a", OperandIntOrReal}, { "p", OperandIntOrReal}}, |
807 | OperandIntOrReal}, |
808 | {"modulo", {{ "a", OperandUnsigned}, { "p", OperandUnsigned}}, |
809 | OperandUnsigned}, |
810 | {"nearest", {{ "x", SameReal}, { "s", AnyReal}}, SameReal}, |
811 | {"new_line", |
812 | {{"a", SameCharNoLen, Rank::anyOrAssumedRank, Optionality::required, |
813 | common::Intent::In, |
814 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
815 | SameCharNoLen, Rank::scalar, IntrinsicClass::inquiryFunction}, |
816 | {"nint", {{ "a", AnyReal}, DefaultingKIND}, KINDInt}, |
817 | {"norm2", {{ "x", SameReal, Rank::array}, RequiredDIM}, SameReal, |
818 | Rank::dimReduced, IntrinsicClass::transformationalFunction}, |
819 | {"norm2", {{ "x", SameReal, Rank::array}, MissingDIM}, SameReal, |
820 | Rank::scalar, IntrinsicClass::transformationalFunction}, |
821 | {"not", {{ "i", SameIntOrUnsigned}}, SameIntOrUnsigned}, |
822 | // NULL() is a special case handled in Probe() below |
823 | {"num_images", {}, DefaultInt, Rank::scalar, |
824 | IntrinsicClass::transformationalFunction}, |
825 | {"num_images", {{ "team", TeamType, Rank::scalar}}, DefaultInt, Rank::scalar, |
826 | IntrinsicClass::transformationalFunction}, |
827 | {"num_images", {{ "team_number", AnyInt, Rank::scalar}}, DefaultInt, |
828 | Rank::scalar, IntrinsicClass::transformationalFunction}, |
829 | {"out_of_range", |
830 | {{"x", AnyIntOrReal}, { "mold", AnyIntOrReal, Rank::scalar}}, |
831 | DefaultLogical}, |
832 | {"out_of_range", |
833 | {{"x", AnyReal}, { "mold", AnyInt, Rank::scalar}, |
834 | {"round", AnyLogical, Rank::scalar, Optionality::optional}}, |
835 | DefaultLogical}, |
836 | {"out_of_range", {{ "x", AnyReal}, { "mold", AnyReal}}, DefaultLogical}, |
837 | {"pack", |
838 | {{"array", SameType, Rank::array}, |
839 | {"mask", AnyLogical, Rank::conformable}, |
840 | {"vector", SameType, Rank::vector, Optionality::optional}}, |
841 | SameType, Rank::vector, IntrinsicClass::transformationalFunction}, |
842 | {"parity", {{ "mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical, |
843 | Rank::dimReduced, IntrinsicClass::transformationalFunction}, |
844 | {"popcnt", {{ "i", AnyInt}}, DefaultInt}, |
845 | {"poppar", {{ "i", AnyInt}}, DefaultInt}, |
846 | {"product", |
847 | {{"array", SameNumeric, Rank::array}, RequiredDIM, OptionalMASK}, |
848 | SameNumeric, Rank::dimReduced, |
849 | IntrinsicClass::transformationalFunction}, |
850 | {"product", {{ "array", SameNumeric, Rank::array}, MissingDIM, OptionalMASK}, |
851 | SameNumeric, Rank::scalar, IntrinsicClass::transformationalFunction}, |
852 | {"precision", |
853 | {{"x", AnyFloating, Rank::anyOrAssumedRank, Optionality::required, |
854 | common::Intent::In, |
855 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
856 | DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
857 | {"present", {{ "a", Addressable, Rank::anyOrAssumedRank}}, DefaultLogical, |
858 | Rank::scalar, IntrinsicClass::inquiryFunction}, |
859 | {"putenv", {{ "str", DefaultChar, Rank::scalar}}, DefaultInt, Rank::scalar, |
860 | IntrinsicClass::transformationalFunction}, |
861 | {"radix", |
862 | {{"x", AnyIntOrReal, Rank::anyOrAssumedRank, Optionality::required, |
863 | common::Intent::In, |
864 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
865 | DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
866 | {"range", |
867 | {{"x", AnyNumeric, Rank::anyOrAssumedRank, Optionality::required, |
868 | common::Intent::In, |
869 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
870 | DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
871 | {"rank", |
872 | {{"a", AnyData, Rank::anyOrAssumedRank, Optionality::required, |
873 | common::Intent::In, |
874 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
875 | DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
876 | {"real", {{ "a", SameComplex, Rank::elemental}}, |
877 | SameReal}, // 16.9.160(4)(ii) |
878 | {"real", {{ "a", AnyNumeric, Rank::elementalOrBOZ}, DefaultingKIND}, |
879 | KINDReal}, |
880 | {"reduce", |
881 | {{"array", SameType, Rank::array}, |
882 | {"operation", SameType, Rank::reduceOperation}, RequiredDIM, |
883 | OptionalMASK, |
884 | {"identity", SameType, Rank::scalar, Optionality::optional}, |
885 | {"ordered", AnyLogical, Rank::scalar, Optionality::optional}}, |
886 | SameType, Rank::dimReduced, IntrinsicClass::transformationalFunction}, |
887 | {"reduce", |
888 | {{"array", SameType, Rank::array}, |
889 | {"operation", SameType, Rank::reduceOperation}, MissingDIM, |
890 | OptionalMASK, |
891 | {"identity", SameType, Rank::scalar, Optionality::optional}, |
892 | {"ordered", AnyLogical, Rank::scalar, Optionality::optional}}, |
893 | SameType, Rank::scalar, IntrinsicClass::transformationalFunction}, |
894 | {"rename", |
895 | {{"path1", DefaultChar, Rank::scalar}, |
896 | {"path2", DefaultChar, Rank::scalar}}, |
897 | DefaultInt, Rank::scalar}, |
898 | {"repeat", |
899 | {{"string", SameCharNoLen, Rank::scalar}, |
900 | {"ncopies", AnyInt, Rank::scalar}}, |
901 | SameCharNoLen, Rank::scalar, IntrinsicClass::transformationalFunction}, |
902 | {"reshape", |
903 | {{"source", SameType, Rank::array}, { "shape", AnyInt, Rank::shape}, |
904 | {"pad", SameType, Rank::array, Optionality::optional}, |
905 | {"order", AnyInt, Rank::vector, Optionality::optional}}, |
906 | SameType, Rank::shaped, IntrinsicClass::transformationalFunction}, |
907 | {"rrspacing", {{ "x", SameReal}}, SameReal}, |
908 | {"same_type_as", |
909 | {{"a", ExtensibleDerived, Rank::anyOrAssumedRank, Optionality::required, |
910 | common::Intent::In, {ArgFlag::canBeMoldNull}}, |
911 | {"b", ExtensibleDerived, Rank::anyOrAssumedRank, |
912 | Optionality::required, common::Intent::In, |
913 | {ArgFlag::canBeMoldNull}}}, |
914 | DefaultLogical, Rank::scalar, IntrinsicClass::inquiryFunction}, |
915 | {"scale", {{ "x", SameReal}, { "i", AnyInt}}, SameReal}, // == IEEE_SCALB() |
916 | {"scan", |
917 | {{"string", SameCharNoLen}, { "set", SameCharNoLen}, |
918 | {"back", AnyLogical, Rank::elemental, Optionality::optional}, |
919 | DefaultingKIND}, |
920 | KINDInt}, |
921 | {"second", {}, DefaultReal, Rank::scalar}, |
922 | {"selected_char_kind", {{ "name", DefaultChar, Rank::scalar}}, DefaultInt, |
923 | Rank::scalar, IntrinsicClass::transformationalFunction}, |
924 | {"selected_int_kind", {{ "r", AnyInt, Rank::scalar}}, DefaultInt, |
925 | Rank::scalar, IntrinsicClass::transformationalFunction}, |
926 | {"selected_logical_kind", {{ "bits", AnyInt, Rank::scalar}}, DefaultInt, |
927 | Rank::scalar, IntrinsicClass::transformationalFunction}, |
928 | {"selected_real_kind", |
929 | {{"p", AnyInt, Rank::scalar}, |
930 | {"r", AnyInt, Rank::scalar, Optionality::optional}, |
931 | {"radix", AnyInt, Rank::scalar, Optionality::optional}}, |
932 | DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction}, |
933 | {"selected_real_kind", |
934 | {{"p", AnyInt, Rank::scalar, Optionality::optional}, |
935 | {"r", AnyInt, Rank::scalar}, |
936 | {"radix", AnyInt, Rank::scalar, Optionality::optional}}, |
937 | DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction}, |
938 | {"selected_real_kind", |
939 | {{"p", AnyInt, Rank::scalar, Optionality::optional}, |
940 | {"r", AnyInt, Rank::scalar, Optionality::optional}, |
941 | {"radix", AnyInt, Rank::scalar}}, |
942 | DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction}, |
943 | {"selected_unsigned_kind", {{ "r", AnyInt, Rank::scalar}}, DefaultInt, |
944 | Rank::scalar, IntrinsicClass::transformationalFunction}, |
945 | {"set_exponent", {{ "x", SameReal}, { "i", AnyInt}}, SameReal}, |
946 | {"shape", {{ "source", AnyData, Rank::anyOrAssumedRank}, SizeDefaultKIND}, |
947 | KINDInt, Rank::vector, IntrinsicClass::inquiryFunction}, |
948 | {"shifta", {{ "i", SameIntOrUnsigned}, { "shift", AnyInt}}, |
949 | SameIntOrUnsigned}, |
950 | {"shiftl", {{ "i", SameIntOrUnsigned}, { "shift", AnyInt}}, |
951 | SameIntOrUnsigned}, |
952 | {"shiftr", {{ "i", SameIntOrUnsigned}, { "shift", AnyInt}}, |
953 | SameIntOrUnsigned}, |
954 | {"sign", {{ "a", SameInt}, { "b", AnyInt}}, SameInt}, |
955 | {"sign", {{ "a", SameReal}, { "b", AnyReal}}, SameReal}, |
956 | {"sin", {{ "x", SameFloating}}, SameFloating}, |
957 | {"sind", {{ "x", SameFloating}}, SameFloating}, |
958 | {"sinh", {{ "x", SameFloating}}, SameFloating}, |
959 | {"size", |
960 | {{"array", AnyData, Rank::arrayOrAssumedRank}, |
961 | OptionalDIM, // unless array is assumed-size |
962 | SizeDefaultKIND}, |
963 | KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
964 | {"sizeof", {{ "x", AnyData, Rank::anyOrAssumedRank}}, SubscriptInt, |
965 | Rank::scalar, IntrinsicClass::inquiryFunction}, |
966 | {"spacing", {{ "x", SameReal}}, SameReal}, |
967 | {"spread", |
968 | {{"source", SameType, Rank::known, Optionality::required, |
969 | common::Intent::In, {ArgFlag::notAssumedSize}}, |
970 | RequiredDIM, {"ncopies", AnyInt, Rank::scalar}}, |
971 | SameType, Rank::rankPlus1, IntrinsicClass::transformationalFunction}, |
972 | {"sqrt", {{ "x", SameFloating}}, SameFloating}, |
973 | {"stopped_images", {OptionalTEAM, SizeDefaultKIND}, KINDInt, Rank::vector, |
974 | IntrinsicClass::transformationalFunction}, |
975 | {"storage_size", |
976 | {{"a", AnyData, Rank::anyOrAssumedRank, Optionality::required, |
977 | common::Intent::In, {ArgFlag::canBeMoldNull}}, |
978 | SizeDefaultKIND}, |
979 | KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
980 | {"sum", {{ "array", SameNumeric, Rank::array}, RequiredDIM, OptionalMASK}, |
981 | SameNumeric, Rank::dimReduced, |
982 | IntrinsicClass::transformationalFunction}, |
983 | {"sum", {{ "array", SameNumeric, Rank::array}, MissingDIM, OptionalMASK}, |
984 | SameNumeric, Rank::scalar, IntrinsicClass::transformationalFunction}, |
985 | {"system", {{ "command", DefaultChar, Rank::scalar}}, DefaultInt, |
986 | Rank::scalar}, |
987 | {"tan", {{ "x", SameFloating}}, SameFloating}, |
988 | {"tand", {{ "x", SameFloating}}, SameFloating}, |
989 | {"tanh", {{ "x", SameFloating}}, SameFloating}, |
990 | {"team_number", {OptionalTEAM}, DefaultInt, Rank::scalar, |
991 | IntrinsicClass::transformationalFunction}, |
992 | {"this_image", |
993 | {{"coarray", AnyData, Rank::coarray}, RequiredDIM, OptionalTEAM}, |
994 | DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction}, |
995 | {"this_image", {{ "coarray", AnyData, Rank::coarray}, OptionalTEAM}, |
996 | DefaultInt, Rank::vector, IntrinsicClass::transformationalFunction}, |
997 | {"this_image", {OptionalTEAM}, DefaultInt, Rank::scalar, |
998 | IntrinsicClass::transformationalFunction}, |
999 | {"time", {}, TypePattern{IntType, KindCode::exactKind, 8}, Rank::scalar, |
1000 | IntrinsicClass::transformationalFunction}, |
1001 | {"tiny", |
1002 | {{"x", SameReal, Rank::anyOrAssumedRank, Optionality::required, |
1003 | common::Intent::In, |
1004 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1005 | SameReal, Rank::scalar, IntrinsicClass::inquiryFunction}, |
1006 | {"trailz", {{ "i", AnyInt}}, DefaultInt}, |
1007 | {"transfer", |
1008 | {{"source", AnyData, Rank::known}, { "mold", SameType, Rank::scalar}}, |
1009 | SameType, Rank::scalar, IntrinsicClass::transformationalFunction}, |
1010 | {"transfer", |
1011 | {{"source", AnyData, Rank::known}, { "mold", SameType, Rank::array}}, |
1012 | SameType, Rank::vector, IntrinsicClass::transformationalFunction}, |
1013 | {"transfer", |
1014 | {{"source", AnyData, Rank::anyOrAssumedRank}, |
1015 | {"mold", SameType, Rank::anyOrAssumedRank}, |
1016 | {"size", AnyInt, Rank::scalar}}, |
1017 | SameType, Rank::vector, IntrinsicClass::transformationalFunction}, |
1018 | {"transpose", {{ "matrix", SameType, Rank::matrix}}, SameType, Rank::matrix, |
1019 | IntrinsicClass::transformationalFunction}, |
1020 | {"trim", {{ "string", SameCharNoLen, Rank::scalar}}, SameCharNoLen, |
1021 | Rank::scalar, IntrinsicClass::transformationalFunction}, |
1022 | {"ubound", |
1023 | {{"array", AnyData, Rank::anyOrAssumedRank}, RequiredDIM, |
1024 | SizeDefaultKIND}, |
1025 | KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction}, |
1026 | {"ubound", {{ "array", AnyData, Rank::arrayOrAssumedRank}, SizeDefaultKIND}, |
1027 | KINDInt, Rank::vector, IntrinsicClass::inquiryFunction}, |
1028 | {"ucobound", |
1029 | {{"coarray", AnyData, Rank::coarray}, OptionalDIM, SizeDefaultKIND}, |
1030 | KINDInt, Rank::scalarIfDim, IntrinsicClass::inquiryFunction}, |
1031 | {"uint", {{ "a", AnyNumeric, Rank::elementalOrBOZ}, DefaultingKIND}, |
1032 | KINDUnsigned}, |
1033 | {"umaskl", {{ "i", AnyInt}, DefaultingKIND}, KINDUnsigned}, |
1034 | {"umaskr", {{ "i", AnyInt}, DefaultingKIND}, KINDUnsigned}, |
1035 | {"unlink", {{ "path", DefaultChar, Rank::scalar}}, DefaultInt, Rank::scalar, |
1036 | IntrinsicClass::transformationalFunction}, |
1037 | {"unpack", |
1038 | {{"vector", SameType, Rank::vector}, { "mask", AnyLogical, Rank::array}, |
1039 | {"field", SameType, Rank::conformable}}, |
1040 | SameType, Rank::conformable, IntrinsicClass::transformationalFunction}, |
1041 | {"verify", |
1042 | {{"string", SameCharNoLen}, { "set", SameCharNoLen}, |
1043 | {"back", AnyLogical, Rank::elemental, Optionality::optional}, |
1044 | DefaultingKIND}, |
1045 | KINDInt}, |
1046 | {"__builtin_compiler_options", {}, DefaultChar}, |
1047 | {"__builtin_compiler_version", {}, DefaultChar}, |
1048 | {"__builtin_fma", {{ "f1", SameReal}, { "f2", SameReal}, { "f3", SameReal}}, |
1049 | SameReal}, |
1050 | {"__builtin_ieee_int", |
1051 | {{"a", AnyFloating}, { "round", IeeeRoundType}, DefaultingKIND}, |
1052 | KINDInt}, |
1053 | {"__builtin_ieee_is_nan", {{ "a", AnyFloating}}, DefaultLogical}, |
1054 | {"__builtin_ieee_is_negative", {{ "a", AnyFloating}}, DefaultLogical}, |
1055 | {"__builtin_ieee_is_normal", {{ "a", AnyFloating}}, DefaultLogical}, |
1056 | {"__builtin_ieee_next_after", {{ "x", SameReal}, { "y", AnyReal}}, SameReal}, |
1057 | {"__builtin_ieee_next_down", {{ "x", SameReal}}, SameReal}, |
1058 | {"__builtin_ieee_next_up", {{ "x", SameReal}}, SameReal}, |
1059 | {"__builtin_ieee_real", {{ "a", AnyIntOrReal}, DefaultingKIND}, KINDReal}, |
1060 | {"__builtin_ieee_support_datatype", |
1061 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1062 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1063 | DefaultLogical}, |
1064 | {"__builtin_ieee_support_denormal", |
1065 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1066 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1067 | DefaultLogical}, |
1068 | {"__builtin_ieee_support_divide", |
1069 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1070 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1071 | DefaultLogical}, |
1072 | {"__builtin_ieee_support_flag", |
1073 | {{"flag", IeeeFlagType, Rank::scalar}, |
1074 | {"x", AnyReal, Rank::known, Optionality::optional, |
1075 | common::Intent::In, |
1076 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1077 | DefaultLogical}, |
1078 | {"__builtin_ieee_support_halting", {{ "flag", IeeeFlagType, Rank::scalar}}, |
1079 | DefaultLogical}, |
1080 | {"__builtin_ieee_support_inf", |
1081 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1082 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1083 | DefaultLogical}, |
1084 | {"__builtin_ieee_support_io", |
1085 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1086 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1087 | DefaultLogical}, |
1088 | {"__builtin_ieee_support_nan", |
1089 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1090 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1091 | DefaultLogical}, |
1092 | {"__builtin_ieee_support_rounding", |
1093 | {{"round_value", IeeeRoundType, Rank::scalar}, |
1094 | {"x", AnyReal, Rank::known, Optionality::optional, |
1095 | common::Intent::In, |
1096 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1097 | DefaultLogical}, |
1098 | {"__builtin_ieee_support_sqrt", |
1099 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1100 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1101 | DefaultLogical}, |
1102 | {"__builtin_ieee_support_standard", |
1103 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1104 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1105 | DefaultLogical}, |
1106 | {"__builtin_ieee_support_subnormal", |
1107 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1108 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1109 | DefaultLogical}, |
1110 | {"__builtin_ieee_support_underflow_control", |
1111 | {{"x", AnyReal, Rank::known, Optionality::optional, common::Intent::In, |
1112 | {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, |
1113 | DefaultLogical}, |
1114 | {"__builtin_numeric_storage_size", {}, DefaultInt}, |
1115 | }; |
1116 | |
1117 | // TODO: Non-standard intrinsic functions |
1118 | // SHIFT, |
1119 | // COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT, |
1120 | // QCMPLX, QEXT, QFLOAT, QREAL, DNUM, |
1121 | // INUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, |
1122 | // MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR |
1123 | // IARG, IARGC, NARGS, NUMARG, BADDRESS, IADDR, CACHESIZE, |
1124 | // EOF, FP_CLASS, INT_PTR_KIND, MALLOC |
1125 | // probably more (these are PGI + Intel, possibly incomplete) |
1126 | // TODO: Optionally warn on use of non-standard intrinsics: |
1127 | // LOC, probably others |
1128 | // TODO: Optionally warn on operand promotion extension |
1129 | |
1130 | // Aliases for a few generic procedures for legacy compatibility and builtins. |
1131 | static const std::pair<const char *, const char *> genericAlias[]{ |
1132 | {"and", "iand"}, |
1133 | {"getenv", "get_environment_variable"}, |
1134 | {"fseek64", "fseek"}, |
1135 | {"fseeko64", "fseek"}, // SUN |
1136 | {"fseeki8", "fseek"}, // Intel |
1137 | {"ftell64", "ftell"}, |
1138 | {"ftello64", "ftell"}, // SUN |
1139 | {"ftelli8", "ftell"}, // Intel |
1140 | {"imag", "aimag"}, |
1141 | {"lshift", "shiftl"}, |
1142 | {"or", "ior"}, |
1143 | {"rshift", "shifta"}, |
1144 | {"unsigned", "uint"}, // Sun vs gfortran names |
1145 | {"xor", "ieor"}, |
1146 | {"__builtin_ieee_selected_real_kind", "selected_real_kind"}, |
1147 | }; |
1148 | |
1149 | // The following table contains the intrinsic functions listed in |
1150 | // Tables 16.2 and 16.3 in Fortran 2018. The "unrestricted" functions |
1151 | // in Table 16.2 can be used as actual arguments, PROCEDURE() interfaces, |
1152 | // and procedure pointer targets. |
1153 | // Note that the restricted conversion functions dcmplx, dreal, float, idint, |
1154 | // ifix, and sngl are extended to accept any argument kind because this is a |
1155 | // common Fortran compilers behavior, and as far as we can tell, is safe and |
1156 | // useful. |
1157 | struct SpecificIntrinsicInterface : public IntrinsicInterface { |
1158 | const char *generic{nullptr}; |
1159 | bool isRestrictedSpecific{false}; |
1160 | // Exact actual/dummy type matching is required by default for specific |
1161 | // intrinsics. If useGenericAndForceResultType is set, then the probing will |
1162 | // also attempt to use the related generic intrinsic and to convert the result |
1163 | // to the specific intrinsic result type if needed. This also prevents |
1164 | // using the generic name so that folding can insert the conversion on the |
1165 | // result and not the arguments. |
1166 | // |
1167 | // This is not enabled on all specific intrinsics because an alternative |
1168 | // is to convert the actual arguments to the required dummy types and this is |
1169 | // not numerically equivalent. |
1170 | // e.g. IABS(INT(i, 4)) not equiv to INT(ABS(i), 4). |
1171 | // This is allowed for restricted min/max specific functions because |
1172 | // the expected behavior is clear from their definitions. A warning is though |
1173 | // always emitted because other compilers' behavior is not ubiquitous here and |
1174 | // the results in case of conversion overflow might not be equivalent. |
1175 | // e.g for MIN0: INT(MIN(2147483647_8, 2*2147483647_8), 4) = 2147483647_4 |
1176 | // but: MIN(INT(2147483647_8, 4), INT(2*2147483647_8, 4)) = -2_4 |
1177 | // xlf and ifort return the first, and pgfortran the later. f18 will return |
1178 | // the first because this matches more closely the MIN0 definition in |
1179 | // Fortran 2018 table 16.3 (although it is still an extension to allow |
1180 | // non default integer argument in MIN0). |
1181 | bool useGenericAndForceResultType{false}; |
1182 | }; |
1183 | |
1184 | static const SpecificIntrinsicInterface specificIntrinsicFunction[]{ |
1185 | {{"abs", {{ "a", DefaultReal}}, DefaultReal}}, |
1186 | {{"acos", {{ "x", DefaultReal}}, DefaultReal}}, |
1187 | {{"aimag", {{ "z", DefaultComplex}}, DefaultReal}}, |
1188 | {{"aint", {{ "a", DefaultReal}}, DefaultReal}}, |
1189 | {{"alog", {{ "x", DefaultReal}}, DefaultReal}, "log"}, |
1190 | {{"alog10", {{ "x", DefaultReal}}, DefaultReal}, "log10"}, |
1191 | {{"amax0", |
1192 | {{"a1", DefaultInt}, { "a2", DefaultInt}, |
1193 | {"a3", DefaultInt, Rank::elemental, Optionality::repeats}}, |
1194 | DefaultReal}, |
1195 | "max", true, true}, |
1196 | {{"amax1", |
1197 | {{"a1", DefaultReal}, { "a2", DefaultReal}, |
1198 | {"a3", DefaultReal, Rank::elemental, Optionality::repeats}}, |
1199 | DefaultReal}, |
1200 | "max", true, true}, |
1201 | {{"amin0", |
1202 | {{"a1", DefaultInt}, { "a2", DefaultInt}, |
1203 | {"a3", DefaultInt, Rank::elemental, Optionality::repeats}}, |
1204 | DefaultReal}, |
1205 | "min", true, true}, |
1206 | {{"amin1", |
1207 | {{"a1", DefaultReal}, { "a2", DefaultReal}, |
1208 | {"a3", DefaultReal, Rank::elemental, Optionality::repeats}}, |
1209 | DefaultReal}, |
1210 | "min", true, true}, |
1211 | {{"amod", {{ "a", DefaultReal}, { "p", DefaultReal}}, DefaultReal}, "mod"}, |
1212 | {{"anint", {{ "a", DefaultReal}}, DefaultReal}}, |
1213 | {{"asin", {{ "x", DefaultReal}}, DefaultReal}}, |
1214 | {{"atan", {{ "x", DefaultReal}}, DefaultReal}}, |
1215 | {{"atan2", {{ "y", DefaultReal}, { "x", DefaultReal}}, DefaultReal}}, |
1216 | {{"babs", {{ "a", TypePattern{IntType, KindCode::exactKind, 1}}}, |
1217 | TypePattern{IntType, KindCode::exactKind, 1}}, |
1218 | "abs"}, |
1219 | {{"cabs", {{ "a", DefaultComplex}}, DefaultReal}, "abs"}, |
1220 | {{"ccos", {{ "x", DefaultComplex}}, DefaultComplex}, "cos"}, |
1221 | {{"cdabs", {{ "a", DoublePrecisionComplex}}, DoublePrecision}, "abs"}, |
1222 | {{"cdcos", {{ "x", DoublePrecisionComplex}}, DoublePrecisionComplex}, "cos"}, |
1223 | {{"cdexp", {{ "x", DoublePrecisionComplex}}, DoublePrecisionComplex}, "exp"}, |
1224 | {{"cdlog", {{ "x", DoublePrecisionComplex}}, DoublePrecisionComplex}, "log"}, |
1225 | {{"cdsin", {{ "x", DoublePrecisionComplex}}, DoublePrecisionComplex}, "sin"}, |
1226 | {{"cdsqrt", {{ "x", DoublePrecisionComplex}}, DoublePrecisionComplex}, |
1227 | "sqrt"}, |
1228 | {{"cexp", {{ "x", DefaultComplex}}, DefaultComplex}, "exp"}, |
1229 | {{"clog", {{ "x", DefaultComplex}}, DefaultComplex}, "log"}, |
1230 | {{"conjg", {{ "z", DefaultComplex}}, DefaultComplex}}, |
1231 | {{"cos", {{ "x", DefaultReal}}, DefaultReal}}, |
1232 | {{"cosh", {{ "x", DefaultReal}}, DefaultReal}}, |
1233 | {{"csin", {{ "x", DefaultComplex}}, DefaultComplex}, "sin"}, |
1234 | {{"csqrt", {{ "x", DefaultComplex}}, DefaultComplex}, "sqrt"}, |
1235 | {{"ctan", {{ "x", DefaultComplex}}, DefaultComplex}, "tan"}, |
1236 | {{"dabs", {{ "a", DoublePrecision}}, DoublePrecision}, "abs"}, |
1237 | {{"dacos", {{ "x", DoublePrecision}}, DoublePrecision}, "acos"}, |
1238 | {{"dasin", {{ "x", DoublePrecision}}, DoublePrecision}, "asin"}, |
1239 | {{"datan", {{ "x", DoublePrecision}}, DoublePrecision}, "atan"}, |
1240 | {{"datan2", {{ "y", DoublePrecision}, { "x", DoublePrecision}}, |
1241 | DoublePrecision}, |
1242 | "atan2"}, |
1243 | {{"dcmplx", {{ "x", AnyComplex}}, DoublePrecisionComplex}, "cmplx", true}, |
1244 | {{"dcmplx", |
1245 | {{"x", AnyIntOrReal, Rank::elementalOrBOZ}, |
1246 | {"y", AnyIntOrReal, Rank::elementalOrBOZ, Optionality::optional}}, |
1247 | DoublePrecisionComplex}, |
1248 | "cmplx", true}, |
1249 | {{"dconjg", {{ "z", DoublePrecisionComplex}}, DoublePrecisionComplex}, |
1250 | "conjg"}, |
1251 | {{"dcos", {{ "x", DoublePrecision}}, DoublePrecision}, "cos"}, |
1252 | {{"dcosh", {{ "x", DoublePrecision}}, DoublePrecision}, "cosh"}, |
1253 | {{"ddim", {{ "x", DoublePrecision}, { "y", DoublePrecision}}, |
1254 | DoublePrecision}, |
1255 | "dim"}, |
1256 | {{"derf", {{ "x", DoublePrecision}}, DoublePrecision}, "erf"}, |
1257 | {{"derfc", {{ "x", DoublePrecision}}, DoublePrecision}, "erfc"}, |
1258 | {{"derfc_scaled", {{ "x", DoublePrecision}}, DoublePrecision}, |
1259 | "erfc_scaled"}, |
1260 | {{"dexp", {{ "x", DoublePrecision}}, DoublePrecision}, "exp"}, |
1261 | {{"dfloat", {{ "a", AnyInt}}, DoublePrecision}, "real", true}, |
1262 | {{"dim", {{ "x", DefaultReal}, { "y", DefaultReal}}, DefaultReal}}, |
1263 | {{"dimag", {{ "z", DoublePrecisionComplex}}, DoublePrecision}, "aimag"}, |
1264 | {{"dint", {{ "a", DoublePrecision}}, DoublePrecision}, "aint"}, |
1265 | {{"dlog", {{ "x", DoublePrecision}}, DoublePrecision}, "log"}, |
1266 | {{"dlog10", {{ "x", DoublePrecision}}, DoublePrecision}, "log10"}, |
1267 | {{"dmax1", |
1268 | {{"a1", DoublePrecision}, { "a2", DoublePrecision}, |
1269 | {"a3", DoublePrecision, Rank::elemental, Optionality::repeats}}, |
1270 | DoublePrecision}, |
1271 | "max", true, true}, |
1272 | {{"dmin1", |
1273 | {{"a1", DoublePrecision}, { "a2", DoublePrecision}, |
1274 | {"a3", DoublePrecision, Rank::elemental, Optionality::repeats}}, |
1275 | DoublePrecision}, |
1276 | "min", true, true}, |
1277 | {{"dmod", {{ "a", DoublePrecision}, { "p", DoublePrecision}}, |
1278 | DoublePrecision}, |
1279 | "mod"}, |
1280 | {{"dnint", {{ "a", DoublePrecision}}, DoublePrecision}, "anint"}, |
1281 | {{"dprod", {{ "x", DefaultReal}, { "y", DefaultReal}}, DoublePrecision}}, |
1282 | {{"dreal", {{ "a", AnyComplex}}, DoublePrecision}, "real", true}, |
1283 | {{"dsign", {{ "a", DoublePrecision}, { "b", DoublePrecision}}, |
1284 | DoublePrecision}, |
1285 | "sign"}, |
1286 | {{"dsin", {{ "x", DoublePrecision}}, DoublePrecision}, "sin"}, |
1287 | {{"dsinh", {{ "x", DoublePrecision}}, DoublePrecision}, "sinh"}, |
1288 | {{"dsqrt", {{ "x", DoublePrecision}}, DoublePrecision}, "sqrt"}, |
1289 | {{"dtan", {{ "x", DoublePrecision}}, DoublePrecision}, "tan"}, |
1290 | {{"dtanh", {{ "x", DoublePrecision}}, DoublePrecision}, "tanh"}, |
1291 | {{"exp", {{ "x", DefaultReal}}, DefaultReal}}, |
1292 | {{"float", {{ "a", AnyInt}}, DefaultReal}, "real", true}, |
1293 | {{"iabs", {{ "a", DefaultInt}}, DefaultInt}, "abs"}, |
1294 | {{"idim", {{ "x", DefaultInt}, { "y", DefaultInt}}, DefaultInt}, "dim"}, |
1295 | {{"idint", {{ "a", AnyReal}}, DefaultInt}, "int", true}, |
1296 | {{"idnint", {{ "a", DoublePrecision}}, DefaultInt}, "nint"}, |
1297 | {{"ifix", {{ "a", AnyReal}}, DefaultInt}, "int", true}, |
1298 | {{"iiabs", {{ "a", TypePattern{IntType, KindCode::exactKind, 2}}}, |
1299 | TypePattern{IntType, KindCode::exactKind, 2}}, |
1300 | "abs"}, |
1301 | // The definition of the unrestricted specific intrinsic function INDEX |
1302 | // in F'77 and F'90 has only two arguments; later standards omit the |
1303 | // argument information for all unrestricted specific intrinsic |
1304 | // procedures. No compiler supports an implementation that allows |
1305 | // INDEX with BACK= to work when associated as an actual procedure or |
1306 | // procedure pointer target. |
1307 | {{"index", {{ "string", DefaultChar}, { "substring", DefaultChar}}, |
1308 | DefaultInt}}, |
1309 | {{"isign", {{ "a", DefaultInt}, { "b", DefaultInt}}, DefaultInt}, "sign"}, |
1310 | {{"jiabs", {{ "a", TypePattern{IntType, KindCode::exactKind, 4}}}, |
1311 | TypePattern{IntType, KindCode::exactKind, 4}}, |
1312 | "abs"}, |
1313 | {{"kiabs", {{ "a", TypePattern{IntType, KindCode::exactKind, 8}}}, |
1314 | TypePattern{IntType, KindCode::exactKind, 8}}, |
1315 | "abs"}, |
1316 | {{"kidnnt", {{ "a", DoublePrecision}}, |
1317 | TypePattern{IntType, KindCode::exactKind, 8}}, |
1318 | "nint"}, |
1319 | {{"knint", {{ "a", DefaultReal}}, |
1320 | TypePattern{IntType, KindCode::exactKind, 8}}, |
1321 | "nint"}, |
1322 | {{"len", {{ "string", DefaultChar, Rank::anyOrAssumedRank}}, DefaultInt, |
1323 | Rank::scalar, IntrinsicClass::inquiryFunction}}, |
1324 | {{"lge", {{ "string_a", DefaultChar}, { "string_b", DefaultChar}}, |
1325 | DefaultLogical}, |
1326 | "lge", true}, |
1327 | {{"lgt", {{ "string_a", DefaultChar}, { "string_b", DefaultChar}}, |
1328 | DefaultLogical}, |
1329 | "lgt", true}, |
1330 | {{"lle", {{ "string_a", DefaultChar}, { "string_b", DefaultChar}}, |
1331 | DefaultLogical}, |
1332 | "lle", true}, |
1333 | {{"llt", {{ "string_a", DefaultChar}, { "string_b", DefaultChar}}, |
1334 | DefaultLogical}, |
1335 | "llt", true}, |
1336 | {{"log", {{ "x", DefaultReal}}, DefaultReal}}, |
1337 | {{"log10", {{ "x", DefaultReal}}, DefaultReal}}, |
1338 | {{"max0", |
1339 | {{"a1", DefaultInt}, { "a2", DefaultInt}, |
1340 | {"a3", DefaultInt, Rank::elemental, Optionality::repeats}}, |
1341 | DefaultInt}, |
1342 | "max", true, true}, |
1343 | {{"max1", |
1344 | {{"a1", DefaultReal}, { "a2", DefaultReal}, |
1345 | {"a3", DefaultReal, Rank::elemental, Optionality::repeats}}, |
1346 | DefaultInt}, |
1347 | "max", true, true}, |
1348 | {{"min0", |
1349 | {{"a1", DefaultInt}, { "a2", DefaultInt}, |
1350 | {"a3", DefaultInt, Rank::elemental, Optionality::repeats}}, |
1351 | DefaultInt}, |
1352 | "min", true, true}, |
1353 | {{"min1", |
1354 | {{"a1", DefaultReal}, { "a2", DefaultReal}, |
1355 | {"a3", DefaultReal, Rank::elemental, Optionality::repeats}}, |
1356 | DefaultInt}, |
1357 | "min", true, true}, |
1358 | {{"mod", {{ "a", DefaultInt}, { "p", DefaultInt}}, DefaultInt}}, |
1359 | {{"nint", {{ "a", DefaultReal}}, DefaultInt}}, |
1360 | {{"qerf", {{ "x", QuadPrecision}}, QuadPrecision}, "erf"}, |
1361 | {{"qerfc", {{ "x", QuadPrecision}}, QuadPrecision}, "erfc"}, |
1362 | {{"qerfc_scaled", {{ "x", QuadPrecision}}, QuadPrecision}, "erfc_scaled"}, |
1363 | {{"sign", {{ "a", DefaultReal}, { "b", DefaultReal}}, DefaultReal}}, |
1364 | {{"sin", {{ "x", DefaultReal}}, DefaultReal}}, |
1365 | {{"sinh", {{ "x", DefaultReal}}, DefaultReal}}, |
1366 | {{"sngl", {{ "a", AnyReal}}, DefaultReal}, "real", true}, |
1367 | {{"sqrt", {{ "x", DefaultReal}}, DefaultReal}}, |
1368 | {{"tan", {{ "x", DefaultReal}}, DefaultReal}}, |
1369 | {{"tanh", {{ "x", DefaultReal}}, DefaultReal}}, |
1370 | {{"zabs", {{ "a", TypePattern{ComplexType, KindCode::exactKind, 8}}}, |
1371 | TypePattern{RealType, KindCode::exactKind, 8}}, |
1372 | "abs"}, |
1373 | }; |
1374 | |
1375 | // Must be sorted by name. The rank of the return value is ignored since |
1376 | // subroutines are do not have a return value. |
1377 | static const IntrinsicInterface intrinsicSubroutine[]{ |
1378 | {"abort", {}, {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1379 | {"atomic_add", |
1380 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1381 | common::Intent::InOut}, |
1382 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1383 | common::Intent::In}, |
1384 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1385 | common::Intent::Out}}, |
1386 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1387 | {"atomic_and", |
1388 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1389 | common::Intent::InOut}, |
1390 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1391 | common::Intent::In}, |
1392 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1393 | common::Intent::Out}}, |
1394 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1395 | {"atomic_cas", |
1396 | {{"atom", SameAtom, Rank::atom, Optionality::required, |
1397 | common::Intent::InOut}, |
1398 | {"old", SameAtom, Rank::scalar, Optionality::required, |
1399 | common::Intent::Out}, |
1400 | {"compare", SameAtom, Rank::scalar, Optionality::required, |
1401 | common::Intent::In}, |
1402 | {"new", SameAtom, Rank::scalar, Optionality::required, |
1403 | common::Intent::In}, |
1404 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1405 | common::Intent::Out}}, |
1406 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1407 | {"atomic_define", |
1408 | {{"atom", AtomicIntOrLogical, Rank::atom, Optionality::required, |
1409 | common::Intent::Out}, |
1410 | {"value", AnyIntOrLogical, Rank::scalar, Optionality::required, |
1411 | common::Intent::In}, |
1412 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1413 | common::Intent::Out}}, |
1414 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1415 | {"atomic_fetch_add", |
1416 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1417 | common::Intent::InOut}, |
1418 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1419 | common::Intent::In}, |
1420 | {"old", AtomicInt, Rank::scalar, Optionality::required, |
1421 | common::Intent::Out}, |
1422 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1423 | common::Intent::Out}}, |
1424 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1425 | {"atomic_fetch_and", |
1426 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1427 | common::Intent::InOut}, |
1428 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1429 | common::Intent::In}, |
1430 | {"old", AtomicInt, Rank::scalar, Optionality::required, |
1431 | common::Intent::Out}, |
1432 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1433 | common::Intent::Out}}, |
1434 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1435 | {"atomic_fetch_or", |
1436 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1437 | common::Intent::InOut}, |
1438 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1439 | common::Intent::In}, |
1440 | {"old", AtomicInt, Rank::scalar, Optionality::required, |
1441 | common::Intent::Out}, |
1442 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1443 | common::Intent::Out}}, |
1444 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1445 | {"atomic_fetch_xor", |
1446 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1447 | common::Intent::InOut}, |
1448 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1449 | common::Intent::In}, |
1450 | {"old", AtomicInt, Rank::scalar, Optionality::required, |
1451 | common::Intent::Out}, |
1452 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1453 | common::Intent::Out}}, |
1454 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1455 | {"atomic_or", |
1456 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1457 | common::Intent::InOut}, |
1458 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1459 | common::Intent::In}, |
1460 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1461 | common::Intent::Out}}, |
1462 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1463 | {"atomic_ref", |
1464 | {{"value", AnyIntOrLogical, Rank::scalar, Optionality::required, |
1465 | common::Intent::Out}, |
1466 | {"atom", AtomicIntOrLogical, Rank::atom, Optionality::required, |
1467 | common::Intent::In}, |
1468 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1469 | common::Intent::Out}}, |
1470 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1471 | {"atomic_xor", |
1472 | {{"atom", AtomicInt, Rank::atom, Optionality::required, |
1473 | common::Intent::InOut}, |
1474 | {"value", AnyInt, Rank::scalar, Optionality::required, |
1475 | common::Intent::In}, |
1476 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1477 | common::Intent::Out}}, |
1478 | {}, Rank::elemental, IntrinsicClass::atomicSubroutine}, |
1479 | {"chdir", |
1480 | {{"name", DefaultChar, Rank::scalar, Optionality::required}, |
1481 | {"status", AnyInt, Rank::scalar, Optionality::optional, |
1482 | common::Intent::Out}}, |
1483 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1484 | {"co_broadcast", |
1485 | {{"a", AnyData, Rank::anyOrAssumedRank, Optionality::required, |
1486 | common::Intent::InOut}, |
1487 | {"source_image", AnyInt, Rank::scalar, Optionality::required, |
1488 | common::Intent::In}, |
1489 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1490 | common::Intent::Out}, |
1491 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1492 | common::Intent::InOut}}, |
1493 | {}, Rank::elemental, IntrinsicClass::collectiveSubroutine}, |
1494 | {"co_max", |
1495 | {{"a", AnyIntOrRealOrChar, Rank::anyOrAssumedRank, |
1496 | Optionality::required, common::Intent::InOut}, |
1497 | {"result_image", AnyInt, Rank::scalar, Optionality::optional, |
1498 | common::Intent::In}, |
1499 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1500 | common::Intent::Out}, |
1501 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1502 | common::Intent::InOut}}, |
1503 | {}, Rank::elemental, IntrinsicClass::collectiveSubroutine}, |
1504 | {"co_min", |
1505 | {{"a", AnyIntOrRealOrChar, Rank::anyOrAssumedRank, |
1506 | Optionality::required, common::Intent::InOut}, |
1507 | {"result_image", AnyInt, Rank::scalar, Optionality::optional, |
1508 | common::Intent::In}, |
1509 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1510 | common::Intent::Out}, |
1511 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1512 | common::Intent::InOut}}, |
1513 | {}, Rank::elemental, IntrinsicClass::collectiveSubroutine}, |
1514 | {"co_reduce", |
1515 | {{"a", AnyData, Rank::known, Optionality::required, |
1516 | common::Intent::InOut}, |
1517 | {"operation", SameType, Rank::reduceOperation}, |
1518 | {"result_image", AnyInt, Rank::scalar, Optionality::optional, |
1519 | common::Intent::In}, |
1520 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1521 | common::Intent::Out}, |
1522 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1523 | common::Intent::InOut}}, |
1524 | {}, Rank::elemental, IntrinsicClass::collectiveSubroutine}, |
1525 | {"co_sum", |
1526 | {{"a", AnyNumeric, Rank::anyOrAssumedRank, Optionality::required, |
1527 | common::Intent::InOut}, |
1528 | {"result_image", AnyInt, Rank::scalar, Optionality::optional, |
1529 | common::Intent::In}, |
1530 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1531 | common::Intent::Out}, |
1532 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1533 | common::Intent::InOut}}, |
1534 | {}, Rank::elemental, IntrinsicClass::collectiveSubroutine}, |
1535 | {"cpu_time", |
1536 | {{"time", AnyReal, Rank::scalar, Optionality::required, |
1537 | common::Intent::Out}}, |
1538 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1539 | {"date_and_time", |
1540 | {{"date", DefaultChar, Rank::scalar, Optionality::optional, |
1541 | common::Intent::Out}, |
1542 | {"time", DefaultChar, Rank::scalar, Optionality::optional, |
1543 | common::Intent::Out}, |
1544 | {"zone", DefaultChar, Rank::scalar, Optionality::optional, |
1545 | common::Intent::Out}, |
1546 | {"values", AnyInt, Rank::vector, Optionality::optional, |
1547 | common::Intent::Out}}, |
1548 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1549 | {"etime", |
1550 | {{"values", TypePattern{RealType, KindCode::exactKind, 4}, Rank::vector, |
1551 | Optionality::required, common::Intent::Out}, |
1552 | {"time", TypePattern{RealType, KindCode::exactKind, 4}, |
1553 | Rank::scalar, Optionality::required, common::Intent::Out}}, |
1554 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1555 | {"event_query", |
1556 | {{"event", EventType, Rank::scalar}, |
1557 | {"count", AnyInt, Rank::scalar, Optionality::required, |
1558 | common::Intent::Out}, |
1559 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1560 | common::Intent::Out}}, |
1561 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1562 | {"execute_command_line", |
1563 | {{"command", DefaultChar, Rank::scalar}, |
1564 | {"wait", AnyLogical, Rank::scalar, Optionality::optional}, |
1565 | {"exitstat", |
1566 | TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}, |
1567 | Rank::scalar, Optionality::optional, common::Intent::InOut}, |
1568 | {"cmdstat", TypePattern{IntType, KindCode::greaterOrEqualToKind, 2}, |
1569 | Rank::scalar, Optionality::optional, common::Intent::Out}, |
1570 | {"cmdmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1571 | common::Intent::InOut}}, |
1572 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1573 | {"exit", {{ "status", DefaultInt, Rank::scalar, Optionality::optional}}, {}, |
1574 | Rank::elemental, IntrinsicClass::impureSubroutine}, |
1575 | {"free", {{ "ptr", Addressable}}, {}}, |
1576 | {"fseek", |
1577 | {{"unit", AnyInt, Rank::scalar}, { "offset", AnyInt, Rank::scalar}, |
1578 | {"whence", AnyInt, Rank::scalar}, |
1579 | {"status", AnyInt, Rank::scalar, Optionality::optional, |
1580 | common::Intent::InOut}}, |
1581 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1582 | {"ftell", |
1583 | {{"unit", AnyInt, Rank::scalar}, |
1584 | {"offset", AnyInt, Rank::scalar, Optionality::required, |
1585 | common::Intent::Out}}, |
1586 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1587 | {"get_command", |
1588 | {{"command", DefaultChar, Rank::scalar, Optionality::optional, |
1589 | common::Intent::Out}, |
1590 | {"length", TypePattern{IntType, KindCode::greaterOrEqualToKind, 2}, |
1591 | Rank::scalar, Optionality::optional, common::Intent::Out}, |
1592 | {"status", AnyInt, Rank::scalar, Optionality::optional, |
1593 | common::Intent::Out}, |
1594 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1595 | common::Intent::InOut}}, |
1596 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1597 | {"get_command_argument", |
1598 | {{"number", AnyInt, Rank::scalar}, |
1599 | {"value", DefaultChar, Rank::scalar, Optionality::optional, |
1600 | common::Intent::Out}, |
1601 | {"length", TypePattern{IntType, KindCode::greaterOrEqualToKind, 2}, |
1602 | Rank::scalar, Optionality::optional, common::Intent::Out}, |
1603 | {"status", AnyInt, Rank::scalar, Optionality::optional, |
1604 | common::Intent::Out}, |
1605 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1606 | common::Intent::InOut}}, |
1607 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1608 | {"get_environment_variable", |
1609 | {{"name", DefaultChar, Rank::scalar}, |
1610 | {"value", DefaultChar, Rank::scalar, Optionality::optional, |
1611 | common::Intent::Out}, |
1612 | {"length", AnyInt, Rank::scalar, Optionality::optional, |
1613 | common::Intent::Out}, |
1614 | {"status", AnyInt, Rank::scalar, Optionality::optional, |
1615 | common::Intent::Out}, |
1616 | {"trim_name", AnyLogical, Rank::scalar, Optionality::optional}, |
1617 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1618 | common::Intent::InOut}}, |
1619 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1620 | {"getcwd", |
1621 | {{"c", DefaultChar, Rank::scalar, Optionality::required, |
1622 | common::Intent::Out}, |
1623 | {"status", TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}, |
1624 | Rank::scalar, Optionality::optional, common::Intent::Out}}, |
1625 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1626 | {"hostnm", |
1627 | {{"c", DefaultChar, Rank::scalar, Optionality::required, |
1628 | common::Intent::Out}, |
1629 | {"status", TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}, |
1630 | Rank::scalar, Optionality::optional, common::Intent::Out}}, |
1631 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1632 | {"move_alloc", |
1633 | {{"from", SameType, Rank::known, Optionality::required, |
1634 | common::Intent::InOut}, |
1635 | {"to", SameType, Rank::known, Optionality::required, |
1636 | common::Intent::Out}, |
1637 | {"stat", AnyInt, Rank::scalar, Optionality::optional, |
1638 | common::Intent::Out}, |
1639 | {"errmsg", DefaultChar, Rank::scalar, Optionality::optional, |
1640 | common::Intent::InOut}}, |
1641 | {}, Rank::elemental, IntrinsicClass::pureSubroutine}, |
1642 | {"perror", {{ "string", DefaultChar, Rank::scalar}}, {}, Rank::elemental, |
1643 | IntrinsicClass::impureSubroutine}, |
1644 | {"putenv", |
1645 | {{"str", DefaultChar, Rank::scalar, Optionality::required, |
1646 | common::Intent::In}, |
1647 | {"status", DefaultInt, Rank::scalar, Optionality::optional, |
1648 | common::Intent::Out}}, |
1649 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1650 | {"mvbits", |
1651 | {{"from", SameIntOrUnsigned}, { "frompos", AnyInt}, { "len", AnyInt}, |
1652 | {"to", SameIntOrUnsigned, Rank::elemental, Optionality::required, |
1653 | common::Intent::Out}, |
1654 | {"topos", AnyInt}}, |
1655 | {}, Rank::elemental, IntrinsicClass::elementalSubroutine}, // elemental |
1656 | {"random_init", |
1657 | {{"repeatable", AnyLogical, Rank::scalar}, |
1658 | {"image_distinct", AnyLogical, Rank::scalar}}, |
1659 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1660 | {"random_number", |
1661 | {{"harvest", {RealType | UnsignedType, KindCode::any}, Rank::known, |
1662 | Optionality::required, common::Intent::Out, |
1663 | {ArgFlag::notAssumedSize}}}, |
1664 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1665 | {"random_seed", |
1666 | {{"size", DefaultInt, Rank::scalar, Optionality::optional, |
1667 | common::Intent::Out}, |
1668 | {"put", DefaultInt, Rank::vector, Optionality::optional}, |
1669 | {"get", DefaultInt, Rank::vector, Optionality::optional, |
1670 | common::Intent::Out}}, |
1671 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1672 | {"rename", |
1673 | {{"path1", DefaultChar, Rank::scalar}, |
1674 | {"path2", DefaultChar, Rank::scalar}, |
1675 | {"status", DefaultInt, Rank::scalar, Optionality::optional, |
1676 | common::Intent::Out}}, |
1677 | {}, Rank::scalar, IntrinsicClass::impureSubroutine}, |
1678 | {"second", {{ "time", DefaultReal, Rank::scalar}}, {}, Rank::scalar, |
1679 | IntrinsicClass::impureSubroutine}, |
1680 | {"system", |
1681 | {{"command", DefaultChar, Rank::scalar}, |
1682 | {"exitstat", DefaultInt, Rank::scalar, Optionality::optional, |
1683 | common::Intent::Out}}, |
1684 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1685 | {"system_clock", |
1686 | {{"count", AnyInt, Rank::scalar, Optionality::optional, |
1687 | common::Intent::Out}, |
1688 | {"count_rate", AnyIntOrReal, Rank::scalar, Optionality::optional, |
1689 | common::Intent::Out}, |
1690 | {"count_max", AnyInt, Rank::scalar, Optionality::optional, |
1691 | common::Intent::Out}}, |
1692 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1693 | {"signal", |
1694 | {{"number", AnyInt, Rank::scalar, Optionality::required, |
1695 | common::Intent::In}, |
1696 | // note: any pointer also accepts AnyInt |
1697 | {"handler", AnyPointer, Rank::scalar, Optionality::required, |
1698 | common::Intent::In}, |
1699 | {"status", AnyInt, Rank::scalar, Optionality::optional, |
1700 | common::Intent::Out}}, |
1701 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1702 | {"sleep", |
1703 | {{"seconds", AnyInt, Rank::scalar, Optionality::required, |
1704 | common::Intent::In}}, |
1705 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1706 | {"unlink", |
1707 | {{"path", DefaultChar, Rank::scalar, Optionality::required, |
1708 | common::Intent::In}, |
1709 | {"status", DefaultInt, Rank::scalar, Optionality::optional, |
1710 | common::Intent::Out}}, |
1711 | {}, Rank::elemental, IntrinsicClass::impureSubroutine}, |
1712 | }; |
1713 | |
1714 | // Finds a built-in derived type and returns it as a DynamicType. |
1715 | static DynamicType GetBuiltinDerivedType( |
1716 | const semantics::Scope *builtinsScope, const char *which) { |
1717 | if (!builtinsScope) { |
1718 | common::die("INTERNAL: The __fortran_builtins module was not found, and " |
1719 | "the type '%s' was required", |
1720 | which); |
1721 | } |
1722 | auto iter{ |
1723 | builtinsScope->find(semantics::SourceName{which, std::strlen(which)})}; |
1724 | if (iter == builtinsScope->cend()) { |
1725 | // keep the string all together |
1726 | // clang-format off |
1727 | common::die( |
1728 | "INTERNAL: The __fortran_builtins module does not define the type '%s'", |
1729 | which); |
1730 | // clang-format on |
1731 | } |
1732 | const semantics::Symbol &symbol{*iter->second}; |
1733 | const semantics::Scope &scope{DEREF(symbol.scope())}; |
1734 | const semantics::DerivedTypeSpec &derived{DEREF(scope.derivedTypeSpec())}; |
1735 | return DynamicType{derived}; |
1736 | } |
1737 | |
1738 | static std::int64_t GetBuiltinKind( |
1739 | const semantics::Scope *builtinsScope, const char *which) { |
1740 | if (!builtinsScope) { |
1741 | common::die("INTERNAL: The __fortran_builtins module was not found, and " |
1742 | "the kind '%s' was required", |
1743 | which); |
1744 | } |
1745 | auto iter{ |
1746 | builtinsScope->find(semantics::SourceName{which, std::strlen(which)})}; |
1747 | if (iter == builtinsScope->cend()) { |
1748 | common::die( |
1749 | "INTERNAL: The __fortran_builtins module does not define the kind '%s'", |
1750 | which); |
1751 | } |
1752 | const semantics::Symbol &symbol{*iter->second}; |
1753 | const auto &details{ |
1754 | DEREF(symbol.detailsIf<semantics::ObjectEntityDetails>())}; |
1755 | if (const auto kind{ToInt64(details.init())}) { |
1756 | return *kind; |
1757 | } else { |
1758 | common::die( |
1759 | "INTERNAL: The __fortran_builtins module does not define the kind '%s'", |
1760 | which); |
1761 | return -1; |
1762 | } |
1763 | } |
1764 | |
1765 | // Ensure that the keywords of arguments to MAX/MIN and their variants |
1766 | // are of the form A123 with no duplicates or leading zeroes. |
1767 | static bool CheckMaxMinArgument(parser::CharBlock keyword, |
1768 | std::set<parser::CharBlock> &set, const char *intrinsicName, |
1769 | parser::ContextualMessages &messages) { |
1770 | std::size_t j{1}; |
1771 | for (; j < keyword.size(); ++j) { |
1772 | char ch{(keyword)[j]}; |
1773 | if (ch < (j == 1 ? '1' : '0') || ch > '9') { |
1774 | break; |
1775 | } |
1776 | } |
1777 | if (keyword.size() < 2 || (keyword)[0] != 'a' || j < keyword.size()) { |
1778 | messages.Say(keyword, |
1779 | "argument keyword '%s=' is not known in call to '%s'"_err_en_US, |
1780 | keyword, intrinsicName); |
1781 | return false; |
1782 | } |
1783 | if (!set.insert(keyword).second) { |
1784 | messages.Say(keyword, |
1785 | "argument keyword '%s=' was repeated in call to '%s'"_err_en_US, |
1786 | keyword, intrinsicName); |
1787 | return false; |
1788 | } |
1789 | return true; |
1790 | } |
1791 | |
1792 | // Validate the keyword, if any, and ensure that A1 and A2 are always placed in |
1793 | // first and second position in actualForDummy. A1 and A2 are special since they |
1794 | // are not optional. The rest of the arguments are not sorted, there are no |
1795 | // differences between them. |
1796 | static bool CheckAndPushMinMaxArgument(ActualArgument &arg, |
1797 | std::vector<ActualArgument *> &actualForDummy, |
1798 | std::set<parser::CharBlock> &set, const char *intrinsicName, |
1799 | parser::ContextualMessages &messages) { |
1800 | if (std::optional<parser::CharBlock> keyword{arg.keyword()}) { |
1801 | if (!CheckMaxMinArgument(*keyword, set, intrinsicName, messages)) { |
1802 | return false; |
1803 | } |
1804 | const bool isA1{*keyword == parser::CharBlock{"a1", 2}}; |
1805 | if (isA1 && !actualForDummy[0]) { |
1806 | actualForDummy[0] = &arg; |
1807 | return true; |
1808 | } |
1809 | const bool isA2{*keyword == parser::CharBlock{"a2", 2}}; |
1810 | if (isA2 && !actualForDummy[1]) { |
1811 | actualForDummy[1] = &arg; |
1812 | return true; |
1813 | } |
1814 | if (isA1 || isA2) { |
1815 | // Note that for arguments other than a1 and a2, this error will be caught |
1816 | // later in check-call.cpp. |
1817 | messages.Say(*keyword, |
1818 | "keyword argument '%s=' to intrinsic '%s' was supplied " |
1819 | "positionally by an earlier actual argument"_err_en_US, |
1820 | *keyword, intrinsicName); |
1821 | return false; |
1822 | } |
1823 | } else { |
1824 | if (actualForDummy.size() == 2) { |
1825 | if (!actualForDummy[0] && !actualForDummy[1]) { |
1826 | actualForDummy[0] = &arg; |
1827 | return true; |
1828 | } else if (!actualForDummy[1]) { |
1829 | actualForDummy[1] = &arg; |
1830 | return true; |
1831 | } |
1832 | } |
1833 | } |
1834 | actualForDummy.push_back(&arg); |
1835 | return true; |
1836 | } |
1837 | |
1838 | static bool CheckAtomicKind(const ActualArgument &arg, |
1839 | const semantics::Scope *builtinsScope, parser::ContextualMessages &messages, |
1840 | const char *keyword) { |
1841 | std::string atomicKindStr; |
1842 | std::optional<DynamicType> type{arg.GetType()}; |
1843 | |
1844 | if (type->category() == TypeCategory::Integer) { |
1845 | atomicKindStr = "atomic_int_kind"; |
1846 | } else if (type->category() == TypeCategory::Logical) { |
1847 | atomicKindStr = "atomic_logical_kind"; |
1848 | } else { |
1849 | common::die("atomic_int_kind or atomic_logical_kind from iso_fortran_env " |
1850 | "must be used with IntType or LogicalType"); |
1851 | } |
1852 | |
1853 | bool argOk{type->kind() == |
1854 | GetBuiltinKind(builtinsScope, ("__builtin_"+ atomicKindStr).c_str())}; |
1855 | if (!argOk) { |
1856 | messages.Say(arg.sourceLocation(), |
1857 | "Actual argument for '%s=' must have kind=atomic_%s_kind, but is '%s'"_err_en_US, |
1858 | keyword, type->category() == TypeCategory::Integer ? "int": "logical", |
1859 | type->AsFortran()); |
1860 | } |
1861 | return argOk; |
1862 | } |
1863 | |
1864 | // Intrinsic interface matching against the arguments of a particular |
1865 | // procedure reference. |
1866 | std::optional<SpecificCall> IntrinsicInterface::Match( |
1867 | const CallCharacteristics &call, |
1868 | const common::IntrinsicTypeDefaultKinds &defaults, |
1869 | ActualArguments &arguments, FoldingContext &context, |
1870 | const semantics::Scope *builtinsScope) const { |
1871 | auto &messages{context.messages()}; |
1872 | // Attempt to construct a 1-1 correspondence between the dummy arguments in |
1873 | // a particular intrinsic procedure's generic interface and the actual |
1874 | // arguments in a procedure reference. |
1875 | std::size_t dummyArgPatterns{0}; |
1876 | for (; dummyArgPatterns < maxArguments && dummy[dummyArgPatterns].keyword; |
1877 | ++dummyArgPatterns) { |
1878 | } |
1879 | // MAX and MIN (and others that map to them) allow their last argument to |
1880 | // be repeated indefinitely. The actualForDummy vector is sized |
1881 | // and null-initialized to the non-repeated dummy argument count |
1882 | // for other intrinsics. |
1883 | bool isMaxMin{dummyArgPatterns > 0 && |
1884 | dummy[dummyArgPatterns - 1].optionality == Optionality::repeats}; |
1885 | std::vector<ActualArgument *> actualForDummy( |
1886 | isMaxMin ? 2 : dummyArgPatterns, nullptr); |
1887 | bool anyMissingActualArgument{false}; |
1888 | std::set<parser::CharBlock> maxMinKeywords; |
1889 | bool anyKeyword{false}; |
1890 | int which{0}; |
1891 | for (std::optional<ActualArgument> &arg : arguments) { |
1892 | ++which; |
1893 | if (arg) { |
1894 | if (arg->isAlternateReturn()) { |
1895 | messages.Say(arg->sourceLocation(), |
1896 | "alternate return specifier not acceptable on call to intrinsic '%s'"_err_en_US, |
1897 | name); |
1898 | return std::nullopt; |
1899 | } |
1900 | if (arg->keyword()) { |
1901 | anyKeyword = true; |
1902 | } else if (anyKeyword) { |
1903 | messages.Say(arg ? arg->sourceLocation() : std::nullopt, |
1904 | "actual argument #%d without a keyword may not follow an actual argument with a keyword"_err_en_US, |
1905 | which); |
1906 | return std::nullopt; |
1907 | } |
1908 | } else { |
1909 | anyMissingActualArgument = true; |
1910 | continue; |
1911 | } |
1912 | if (isMaxMin) { |
1913 | if (!CheckAndPushMinMaxArgument( |
1914 | *arg, actualForDummy, maxMinKeywords, name, messages)) { |
1915 | return std::nullopt; |
1916 | } |
1917 | } else { |
1918 | bool found{false}; |
1919 | for (std::size_t j{0}; j < dummyArgPatterns && !found; ++j) { |
1920 | if (dummy[j].optionality == Optionality::missing) { |
1921 | continue; |
1922 | } |
1923 | if (arg->keyword()) { |
1924 | found = *arg->keyword() == dummy[j].keyword; |
1925 | if (found) { |
1926 | if (const auto *previous{actualForDummy[j]}) { |
1927 | if (previous->keyword()) { |
1928 | messages.Say(*arg->keyword(), |
1929 | "repeated keyword argument to intrinsic '%s'"_err_en_US, |
1930 | name); |
1931 | } else { |
1932 | messages.Say(*arg->keyword(), |
1933 | "keyword argument to intrinsic '%s' was supplied " |
1934 | "positionally by an earlier actual argument"_err_en_US, |
1935 | name); |
1936 | } |
1937 | return std::nullopt; |
1938 | } |
1939 | } |
1940 | } else { |
1941 | found = !actualForDummy[j] && !anyMissingActualArgument; |
1942 | } |
1943 | if (found) { |
1944 | actualForDummy[j] = &*arg; |
1945 | } |
1946 | } |
1947 | if (!found) { |
1948 | if (arg->keyword()) { |
1949 | messages.Say(*arg->keyword(), |
1950 | "unknown keyword argument to intrinsic '%s'"_err_en_US, name); |
1951 | } else { |
1952 | messages.Say( |
1953 | "too many actual arguments for intrinsic '%s'"_err_en_US, name); |
1954 | } |
1955 | return std::nullopt; |
1956 | } |
1957 | } |
1958 | } |
1959 | |
1960 | std::size_t dummies{actualForDummy.size()}; |
1961 | |
1962 | // Check types and kinds of the actual arguments against the intrinsic's |
1963 | // interface. Ensure that two or more arguments that have to have the same |
1964 | // (or compatible) type and kind do so. Check for missing non-optional |
1965 | // arguments now, too. |
1966 | const ActualArgument *sameArg{nullptr}; |
1967 | const ActualArgument *operandArg{nullptr}; |
1968 | const IntrinsicDummyArgument *kindDummyArg{nullptr}; |
1969 | const ActualArgument *kindArg{nullptr}; |
1970 | std::optional<int> dimArg; |
1971 | for (std::size_t j{0}; j < dummies; ++j) { |
1972 | const IntrinsicDummyArgument &d{dummy[std::min(j, dummyArgPatterns - 1)]}; |
1973 | if (d.typePattern.kindCode == KindCode::kindArg) { |
1974 | CHECK(!kindDummyArg); |
1975 | kindDummyArg = &d; |
1976 | } |
1977 | const ActualArgument *arg{actualForDummy[j]}; |
1978 | if (!arg) { |
1979 | if (d.optionality == Optionality::required) { |
1980 | std::string kw{d.keyword}; |
1981 | if (isMaxMin && !actualForDummy[0] && !actualForDummy[1]) { |
1982 | messages.Say("missing mandatory 'a1=' and 'a2=' arguments"_err_en_US); |
1983 | } else { |
1984 | messages.Say( |
1985 | "missing mandatory '%s=' argument"_err_en_US, kw.c_str()); |
1986 | } |
1987 | return std::nullopt; // missing non-OPTIONAL argument |
1988 | } else { |
1989 | continue; |
1990 | } |
1991 | } |
1992 | if (d.optionality == Optionality::missing) { |
1993 | messages.Say(arg->sourceLocation(), "unexpected '%s=' argument"_err_en_US, |
1994 | d.keyword); |
1995 | return std::nullopt; |
1996 | } |
1997 | if (!d.flags.test(ArgFlag::canBeNullPointer)) { |
1998 | if (const auto *expr{arg->UnwrapExpr()}; IsNullPointer(expr)) { |
1999 | if (!IsBareNullPointer(expr) && IsNullObjectPointer(expr) && |
2000 | d.flags.test(ArgFlag::canBeMoldNull)) { |
2001 | // ok |
2002 | } else { |
2003 | messages.Say(arg->sourceLocation(), |
2004 | "A NULL() pointer is not allowed for '%s=' intrinsic argument"_err_en_US, |
2005 | d.keyword); |
2006 | return std::nullopt; |
2007 | } |
2008 | } |
2009 | } |
2010 | if (!d.flags.test(ArgFlag::canBeNullAllocatable) && |
2011 | IsNullAllocatable(arg->UnwrapExpr()) && |
2012 | !d.flags.test(ArgFlag::canBeMoldNull)) { |
2013 | messages.Say(arg->sourceLocation(), |
2014 | "A NULL() allocatable is not allowed for '%s=' intrinsic argument"_err_en_US, |
2015 | d.keyword); |
2016 | return std::nullopt; |
2017 | } |
2018 | if (d.flags.test(ArgFlag::notAssumedSize)) { |
2019 | if (auto named{ExtractNamedEntity(*arg)}) { |
2020 | if (semantics::IsAssumedSizeArray(named->GetLastSymbol())) { |
2021 | messages.Say(arg->sourceLocation(), |
2022 | "The '%s=' argument to the intrinsic procedure '%s' may not be assumed-size"_err_en_US, |
2023 | d.keyword, name); |
2024 | return std::nullopt; |
2025 | } |
2026 | } |
2027 | } |
2028 | if (arg->GetAssumedTypeDummy()) { |
2029 | // TYPE(*) assumed-type dummy argument forwarded to intrinsic |
2030 | if (d.typePattern.categorySet == AnyType && |
2031 | (d.rank == Rank::anyOrAssumedRank || |
2032 | d.rank == Rank::arrayOrAssumedRank) && |
2033 | (d.typePattern.kindCode == KindCode::any || |
2034 | d.typePattern.kindCode == KindCode::addressable)) { |
2035 | continue; |
2036 | } else { |
2037 | messages.Say(arg->sourceLocation(), |
2038 | "Assumed type TYPE(*) dummy argument not allowed for '%s=' intrinsic argument"_err_en_US, |
2039 | d.keyword); |
2040 | return std::nullopt; |
2041 | } |
2042 | } |
2043 | std::optional<DynamicType> type{arg->GetType()}; |
2044 | if (!type) { |
2045 | CHECK(arg->Rank() == 0); |
2046 | const Expr<SomeType> &expr{DEREF(arg->UnwrapExpr())}; |
2047 | if (IsBOZLiteral(expr)) { |
2048 | if (d.typePattern.kindCode == KindCode::typeless || |
2049 | d.rank == Rank::elementalOrBOZ) { |
2050 | continue; |
2051 | } else { |
2052 | const IntrinsicDummyArgument *nextParam{ |
2053 | j + 1 < dummies ? &dummy[j + 1] : nullptr}; |
2054 | if (nextParam && nextParam->rank == Rank::elementalOrBOZ) { |
2055 | messages.Say(arg->sourceLocation(), |
2056 | "Typeless (BOZ) not allowed for both '%s=' & '%s=' arguments"_err_en_US, // C7109 |
2057 | d.keyword, nextParam->keyword); |
2058 | } else { |
2059 | messages.Say(arg->sourceLocation(), |
2060 | "Typeless (BOZ) not allowed for '%s=' argument"_err_en_US, |
2061 | d.keyword); |
2062 | } |
2063 | } |
2064 | } else { |
2065 | // NULL(no MOLD=), procedure, or procedure pointer |
2066 | CHECK(IsProcedurePointerTarget(expr)); |
2067 | if (d.typePattern.kindCode == KindCode::addressable || |
2068 | d.rank == Rank::reduceOperation) { |
2069 | continue; |
2070 | } else if (d.typePattern.kindCode == KindCode::nullPointerType) { |
2071 | continue; |
2072 | } else if (IsBareNullPointer(&expr)) { |
2073 | // checked elsewhere |
2074 | continue; |
2075 | } else { |
2076 | CHECK(IsProcedure(expr) || IsProcedurePointer(expr)); |
2077 | messages.Say(arg->sourceLocation(), |
2078 | "Actual argument for '%s=' may not be a procedure"_err_en_US, |
2079 | d.keyword); |
2080 | } |
2081 | } |
2082 | return std::nullopt; |
2083 | } else if (!d.typePattern.categorySet.test(type->category())) { |
2084 | messages.Say(arg->sourceLocation(), |
2085 | "Actual argument for '%s=' has bad type '%s'"_err_en_US, d.keyword, |
2086 | type->AsFortran()); |
2087 | return std::nullopt; // argument has invalid type category |
2088 | } |
2089 | bool argOk{false}; |
2090 | switch (d.typePattern.kindCode) { |
2091 | case KindCode::none: |
2092 | case KindCode::typeless: |
2093 | argOk = false; |
2094 | break; |
2095 | case KindCode::eventType: |
2096 | argOk = !type->IsUnlimitedPolymorphic() && |
2097 | type->category() == TypeCategory::Derived && |
2098 | semantics::IsEventType(&type->GetDerivedTypeSpec()); |
2099 | break; |
2100 | case KindCode::ieeeFlagType: |
2101 | argOk = !type->IsUnlimitedPolymorphic() && |
2102 | type->category() == TypeCategory::Derived && |
2103 | semantics::IsIeeeFlagType(&type->GetDerivedTypeSpec()); |
2104 | break; |
2105 | case KindCode::ieeeRoundType: |
2106 | argOk = !type->IsUnlimitedPolymorphic() && |
2107 | type->category() == TypeCategory::Derived && |
2108 | semantics::IsIeeeRoundType(&type->GetDerivedTypeSpec()); |
2109 | break; |
2110 | case KindCode::teamType: |
2111 | argOk = !type->IsUnlimitedPolymorphic() && |
2112 | type->category() == TypeCategory::Derived && |
2113 | semantics::IsTeamType(&type->GetDerivedTypeSpec()); |
2114 | break; |
2115 | case KindCode::defaultIntegerKind: |
2116 | argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Integer); |
2117 | break; |
2118 | case KindCode::defaultRealKind: |
2119 | argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Real); |
2120 | break; |
2121 | case KindCode::doublePrecision: |
2122 | argOk = type->kind() == defaults.doublePrecisionKind(); |
2123 | break; |
2124 | case KindCode::quadPrecision: |
2125 | argOk = type->kind() == defaults.quadPrecisionKind(); |
2126 | break; |
2127 | case KindCode::defaultCharKind: |
2128 | argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Character); |
2129 | break; |
2130 | case KindCode::defaultLogicalKind: |
2131 | argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Logical); |
2132 | break; |
2133 | case KindCode::any: |
2134 | argOk = true; |
2135 | break; |
2136 | case KindCode::kindArg: |
2137 | CHECK(type->category() == TypeCategory::Integer); |
2138 | CHECK(!kindArg); |
2139 | kindArg = arg; |
2140 | argOk = true; |
2141 | break; |
2142 | case KindCode::dimArg: |
2143 | CHECK(type->category() == TypeCategory::Integer); |
2144 | dimArg = j; |
2145 | argOk = true; |
2146 | break; |
2147 | case KindCode::same: { |
2148 | if (!sameArg) { |
2149 | sameArg = arg; |
2150 | } |
2151 | auto sameType{sameArg->GetType().value()}; |
2152 | if (name == "move_alloc"s) { |
2153 | // second argument can be more general |
2154 | argOk = type->IsTkLenCompatibleWith(sameType); |
2155 | } else if (name == "merge"s) { |
2156 | argOk = type->IsTkLenCompatibleWith(sameType) && |
2157 | sameType.IsTkLenCompatibleWith(*type); |
2158 | } else { |
2159 | argOk = sameType.IsTkLenCompatibleWith(*type); |
2160 | } |
2161 | } break; |
2162 | case KindCode::sameKind: |
2163 | if (!sameArg) { |
2164 | sameArg = arg; |
2165 | } |
2166 | argOk = type->IsTkCompatibleWith(sameArg->GetType().value()); |
2167 | break; |
2168 | case KindCode::operand: |
2169 | if (!operandArg) { |
2170 | operandArg = arg; |
2171 | } else if (auto prev{operandArg->GetType()}) { |
2172 | if (type->category() == prev->category()) { |
2173 | if (type->kind() > prev->kind()) { |
2174 | operandArg = arg; |
2175 | } |
2176 | } else if (prev->category() == TypeCategory::Integer) { |
2177 | operandArg = arg; |
2178 | } |
2179 | } |
2180 | argOk = true; |
2181 | break; |
2182 | case KindCode::effectiveKind: |
2183 | common::die("INTERNAL: KindCode::effectiveKind appears on argument '%s' " |
2184 | "for intrinsic '%s'", |
2185 | d.keyword, name); |
2186 | break; |
2187 | case KindCode::addressable: |
2188 | case KindCode::nullPointerType: |
2189 | argOk = true; |
2190 | break; |
2191 | case KindCode::exactKind: |
2192 | argOk = type->kind() == d.typePattern.kindValue; |
2193 | break; |
2194 | case KindCode::greaterOrEqualToKind: |
2195 | argOk = type->kind() >= d.typePattern.kindValue; |
2196 | break; |
2197 | case KindCode::sameAtom: |
2198 | if (!sameArg) { |
2199 | sameArg = arg; |
2200 | argOk = CheckAtomicKind(DEREF(arg), builtinsScope, messages, d.keyword); |
2201 | } else { |
2202 | argOk = type->IsTkCompatibleWith(sameArg->GetType().value()); |
2203 | if (!argOk) { |
2204 | messages.Say(arg->sourceLocation(), |
2205 | "Actual argument for '%s=' must have same type and kind as 'atom=', but is '%s'"_err_en_US, |
2206 | d.keyword, type->AsFortran()); |
2207 | } |
2208 | } |
2209 | if (!argOk) { |
2210 | return std::nullopt; |
2211 | } |
2212 | break; |
2213 | case KindCode::atomicIntKind: |
2214 | argOk = CheckAtomicKind(DEREF(arg), builtinsScope, messages, d.keyword); |
2215 | if (!argOk) { |
2216 | return std::nullopt; |
2217 | } |
2218 | break; |
2219 | case KindCode::atomicIntOrLogicalKind: |
2220 | argOk = CheckAtomicKind(DEREF(arg), builtinsScope, messages, d.keyword); |
2221 | if (!argOk) { |
2222 | return std::nullopt; |
2223 | } |
2224 | break; |
2225 | default: |
2226 | CRASH_NO_CASE; |
2227 | } |
2228 | if (!argOk) { |
2229 | messages.Say(arg->sourceLocation(), |
2230 | "Actual argument for '%s=' has bad type or kind '%s'"_err_en_US, |
2231 | d.keyword, type->AsFortran()); |
2232 | return std::nullopt; |
2233 | } |
2234 | } |
2235 | |
2236 | // Check the ranks of the arguments against the intrinsic's interface. |
2237 | const ActualArgument *arrayArg{nullptr}; |
2238 | const char *arrayArgName{nullptr}; |
2239 | const ActualArgument *knownArg{nullptr}; |
2240 | std::optional<std::int64_t> shapeArgSize; |
2241 | int elementalRank{0}; |
2242 | for (std::size_t j{0}; j < dummies; ++j) { |
2243 | const IntrinsicDummyArgument &d{dummy[std::min(j, dummyArgPatterns - 1)]}; |
2244 | if (const ActualArgument *arg{actualForDummy[j]}) { |
2245 | bool isAssumedRank{IsAssumedRank(*arg)}; |
2246 | if (isAssumedRank && d.rank != Rank::anyOrAssumedRank && |
2247 | d.rank != Rank::arrayOrAssumedRank) { |
2248 | messages.Say(arg->sourceLocation(), |
2249 | "Assumed-rank array cannot be forwarded to '%s=' argument"_err_en_US, |
2250 | d.keyword); |
2251 | return std::nullopt; |
2252 | } |
2253 | int rank{arg->Rank()}; |
2254 | bool argOk{false}; |
2255 | switch (d.rank) { |
2256 | case Rank::elemental: |
2257 | case Rank::elementalOrBOZ: |
2258 | if (elementalRank == 0) { |
2259 | elementalRank = rank; |
2260 | } |
2261 | argOk = rank == 0 || rank == elementalRank; |
2262 | break; |
2263 | case Rank::scalar: |
2264 | argOk = rank == 0; |
2265 | break; |
2266 | case Rank::vector: |
2267 | argOk = rank == 1; |
2268 | break; |
2269 | case Rank::shape: |
2270 | CHECK(!shapeArgSize); |
2271 | if (rank != 1) { |
2272 | messages.Say(arg->sourceLocation(), |
2273 | "'shape=' argument must be an array of rank 1"_err_en_US); |
2274 | return std::nullopt; |
2275 | } else { |
2276 | if (auto shape{GetShape(context, *arg)}) { |
2277 | if (auto constShape{AsConstantShape(context, *shape)}) { |
2278 | shapeArgSize = constShape->At(ConstantSubscripts{1}).ToInt64(); |
2279 | CHECK(shapeArgSize.value() >= 0); |
2280 | argOk = *shapeArgSize <= common::maxRank; |
2281 | } |
2282 | } |
2283 | } |
2284 | if (!argOk) { |
2285 | if (shapeArgSize.value_or(0) > common::maxRank) { |
2286 | messages.Say(arg->sourceLocation(), |
2287 | "'shape=' argument must be a vector of at most %d elements (has %jd)"_err_en_US, |
2288 | common::maxRank, std::intmax_t{*shapeArgSize}); |
2289 | } else { |
2290 | messages.Say(arg->sourceLocation(), |
2291 | "'shape=' argument must be a vector of known size"_err_en_US); |
2292 | } |
2293 | return std::nullopt; |
2294 | } |
2295 | break; |
2296 | case Rank::matrix: |
2297 | argOk = rank == 2; |
2298 | break; |
2299 | case Rank::array: |
2300 | argOk = rank > 0; |
2301 | if (!arrayArg) { |
2302 | arrayArg = arg; |
2303 | arrayArgName = d.keyword; |
2304 | } |
2305 | break; |
2306 | case Rank::coarray: |
2307 | argOk = IsCoarray(*arg); |
2308 | if (!argOk) { |
2309 | messages.Say(arg->sourceLocation(), |
2310 | "'coarray=' argument must have corank > 0 for intrinsic '%s'"_err_en_US, |
2311 | name); |
2312 | return std::nullopt; |
2313 | } |
2314 | break; |
2315 | case Rank::atom: |
2316 | argOk = rank == 0 && (IsCoarray(*arg) || ExtractCoarrayRef(*arg)); |
2317 | if (!argOk) { |
2318 | messages.Say(arg->sourceLocation(), |
2319 | "'%s=' argument must be a scalar coarray or coindexed object for intrinsic '%s'"_err_en_US, |
2320 | d.keyword, name); |
2321 | return std::nullopt; |
2322 | } |
2323 | break; |
2324 | case Rank::known: |
2325 | if (!knownArg) { |
2326 | knownArg = arg; |
2327 | } |
2328 | argOk = !isAssumedRank && rank == knownArg->Rank(); |
2329 | break; |
2330 | case Rank::anyOrAssumedRank: |
2331 | case Rank::arrayOrAssumedRank: |
2332 | if (isAssumedRank) { |
2333 | argOk = true; |
2334 | break; |
2335 | } |
2336 | if (d.rank == Rank::arrayOrAssumedRank && rank == 0) { |
2337 | argOk = false; |
2338 | break; |
2339 | } |
2340 | if (!knownArg) { |
2341 | knownArg = arg; |
2342 | } |
2343 | if (rank > 0 && |
2344 | (std::strcmp(s1: name, s2: "shape") == 0 || |
2345 | std::strcmp(s1: name, s2: "size") == 0 || |
2346 | std::strcmp(s1: name, s2: "ubound") == 0)) { |
2347 | // Check for a whole assumed-size array argument. |
2348 | // These are disallowed for SHAPE, and require DIM= for |
2349 | // SIZE and UBOUND. |
2350 | // (A previous error message for UBOUND will take precedence |
2351 | // over this one, as this error is caught by the second entry |
2352 | // for UBOUND.) |
2353 | if (auto named{ExtractNamedEntity(*arg)}) { |
2354 | if (semantics::IsAssumedSizeArray(ResolveAssociations( |
2355 | named->GetLastSymbol().GetUltimate()))) { |
2356 | if (strcmp(s1: name, s2: "shape") == 0) { |
2357 | messages.Say(arg->sourceLocation(), |
2358 | "The 'source=' argument to the intrinsic function 'shape' may not be assumed-size"_err_en_US); |
2359 | return std::nullopt; |
2360 | } else if (!dimArg) { |
2361 | messages.Say(arg->sourceLocation(), |
2362 | "A dim= argument is required for '%s' when the array is assumed-size"_err_en_US, |
2363 | name); |
2364 | return std::nullopt; |
2365 | } |
2366 | } |
2367 | } |
2368 | } |
2369 | argOk = true; |
2370 | break; |
2371 | case Rank::conformable: // arg must be conformable with previous arrayArg |
2372 | CHECK(arrayArg); |
2373 | CHECK(arrayArgName); |
2374 | if (const std::optional<Shape> &arrayArgShape{ |
2375 | GetShape(context, *arrayArg)}) { |
2376 | if (std::optional<Shape> argShape{GetShape(context, *arg)}) { |
2377 | std::string arrayArgMsg{"'"}; |
2378 | arrayArgMsg = arrayArgMsg + arrayArgName + "='"+ " argument"; |
2379 | std::string argMsg{"'"}; |
2380 | argMsg = argMsg + d.keyword + "='"+ " argument"; |
2381 | CheckConformance(context.messages(), *arrayArgShape, *argShape, |
2382 | CheckConformanceFlags::RightScalarExpandable, |
2383 | arrayArgMsg.c_str(), argMsg.c_str()); |
2384 | } |
2385 | } |
2386 | argOk = true; // Avoid an additional error message |
2387 | break; |
2388 | case Rank::dimReduced: |
2389 | case Rank::dimRemovedOrScalar: |
2390 | CHECK(arrayArg); |
2391 | argOk = rank == 0 || rank + 1 == arrayArg->Rank(); |
2392 | break; |
2393 | case Rank::reduceOperation: |
2394 | // The reduction function is validated in ApplySpecificChecks(). |
2395 | argOk = true; |
2396 | break; |
2397 | case Rank::scalarIfDim: |
2398 | case Rank::locReduced: |
2399 | case Rank::rankPlus1: |
2400 | case Rank::shaped: |
2401 | common::die("INTERNAL: result-only rank code appears on argument '%s' " |
2402 | "for intrinsic '%s'", |
2403 | d.keyword, name); |
2404 | } |
2405 | if (!argOk) { |
2406 | messages.Say(arg->sourceLocation(), |
2407 | "'%s=' argument has unacceptable rank %d"_err_en_US, d.keyword, |
2408 | rank); |
2409 | return std::nullopt; |
2410 | } |
2411 | } |
2412 | } |
2413 | |
2414 | // Calculate the characteristics of the function result, if any |
2415 | std::optional<DynamicType> resultType; |
2416 | if (auto category{result.categorySet.LeastElement()}) { |
2417 | // The intrinsic is not a subroutine. |
2418 | if (call.isSubroutineCall) { |
2419 | return std::nullopt; |
2420 | } |
2421 | switch (result.kindCode) { |
2422 | case KindCode::defaultIntegerKind: |
2423 | CHECK(result.categorySet == IntType); |
2424 | CHECK(*category == TypeCategory::Integer); |
2425 | resultType = DynamicType{TypeCategory::Integer, |
2426 | defaults.GetDefaultKind(TypeCategory::Integer)}; |
2427 | break; |
2428 | case KindCode::defaultRealKind: |
2429 | CHECK(result.categorySet == CategorySet{*category}); |
2430 | CHECK(FloatingType.test(*category)); |
2431 | resultType = |
2432 | DynamicType{*category, defaults.GetDefaultKind(TypeCategory::Real)}; |
2433 | break; |
2434 | case KindCode::doublePrecision: |
2435 | CHECK(result.categorySet == CategorySet{*category}); |
2436 | CHECK(FloatingType.test(*category)); |
2437 | resultType = DynamicType{*category, defaults.doublePrecisionKind()}; |
2438 | break; |
2439 | case KindCode::quadPrecision: |
2440 | CHECK(result.categorySet == CategorySet{*category}); |
2441 | CHECK(FloatingType.test(*category)); |
2442 | resultType = DynamicType{*category, defaults.quadPrecisionKind()}; |
2443 | if (!context.targetCharacteristics().CanSupportType( |
2444 | *category, defaults.quadPrecisionKind())) { |
2445 | messages.Say( |
2446 | "%s(KIND=%jd) type not supported on this target."_err_en_US, |
2447 | parser::ToUpperCaseLetters(EnumToString(*category)), |
2448 | defaults.quadPrecisionKind()); |
2449 | } |
2450 | break; |
2451 | case KindCode::defaultLogicalKind: |
2452 | CHECK(result.categorySet == LogicalType); |
2453 | CHECK(*category == TypeCategory::Logical); |
2454 | resultType = DynamicType{TypeCategory::Logical, |
2455 | defaults.GetDefaultKind(TypeCategory::Logical)}; |
2456 | break; |
2457 | case KindCode::defaultCharKind: |
2458 | CHECK(result.categorySet == CharType); |
2459 | CHECK(*category == TypeCategory::Character); |
2460 | resultType = DynamicType{TypeCategory::Character, |
2461 | defaults.GetDefaultKind(TypeCategory::Character)}; |
2462 | break; |
2463 | case KindCode::same: |
2464 | CHECK(sameArg); |
2465 | if (std::optional<DynamicType> aType{sameArg->GetType()}) { |
2466 | if (result.categorySet.test(aType->category())) { |
2467 | if (const auto *sameChar{UnwrapExpr<Expr<SomeCharacter>>(*sameArg)}) { |
2468 | if (auto len{ToInt64(Fold(context, sameChar->LEN()))}) { |
2469 | resultType = DynamicType{aType->kind(), *len}; |
2470 | } else { |
2471 | resultType = *aType; |
2472 | } |
2473 | } else { |
2474 | resultType = *aType; |
2475 | } |
2476 | } else { |
2477 | resultType = DynamicType{*category, aType->kind()}; |
2478 | } |
2479 | } |
2480 | break; |
2481 | case KindCode::sameKind: |
2482 | CHECK(sameArg); |
2483 | if (std::optional<DynamicType> aType{sameArg->GetType()}) { |
2484 | resultType = DynamicType{*category, aType->kind()}; |
2485 | } |
2486 | break; |
2487 | case KindCode::operand: |
2488 | CHECK(operandArg); |
2489 | resultType = operandArg->GetType(); |
2490 | CHECK(!resultType || result.categorySet.test(resultType->category())); |
2491 | break; |
2492 | case KindCode::effectiveKind: |
2493 | CHECK(kindDummyArg); |
2494 | CHECK(result.categorySet == CategorySet{*category}); |
2495 | if (kindArg) { |
2496 | if (auto *expr{kindArg->UnwrapExpr()}) { |
2497 | CHECK(expr->Rank() == 0); |
2498 | if (auto code{ToInt64(Fold(context, common::Clone(*expr)))}) { |
2499 | if (context.targetCharacteristics().IsTypeEnabled( |
2500 | *category, *code)) { |
2501 | if (*category == TypeCategory::Character) { // ACHAR & CHAR |
2502 | resultType = DynamicType{static_cast<int>(*code), 1}; |
2503 | } else { |
2504 | resultType = DynamicType{*category, static_cast<int>(*code)}; |
2505 | } |
2506 | break; |
2507 | } |
2508 | } |
2509 | } |
2510 | messages.Say( |
2511 | "'kind=' argument must be a constant scalar integer whose value is a supported kind for the intrinsic result type"_err_en_US); |
2512 | // use default kind below for error recovery |
2513 | } else if (kindDummyArg->flags.test(ArgFlag::defaultsToSameKind)) { |
2514 | CHECK(sameArg); |
2515 | resultType = *sameArg->GetType(); |
2516 | } else if (kindDummyArg->flags.test(ArgFlag::defaultsToSizeKind)) { |
2517 | CHECK(*category == TypeCategory::Integer); |
2518 | resultType = |
2519 | DynamicType{TypeCategory::Integer, defaults.sizeIntegerKind()}; |
2520 | } else { |
2521 | CHECK(kindDummyArg->flags.test(ArgFlag::defaultsToDefaultForResult)); |
2522 | } |
2523 | if (!resultType) { |
2524 | int kind{defaults.GetDefaultKind(*category)}; |
2525 | if (*category == TypeCategory::Character) { // ACHAR & CHAR |
2526 | resultType = DynamicType{kind, 1}; |
2527 | } else { |
2528 | resultType = DynamicType{*category, kind}; |
2529 | } |
2530 | } |
2531 | break; |
2532 | case KindCode::likeMultiply: |
2533 | CHECK(dummies >= 2); |
2534 | CHECK(actualForDummy[0]); |
2535 | CHECK(actualForDummy[1]); |
2536 | resultType = actualForDummy[0]->GetType()->ResultTypeForMultiply( |
2537 | *actualForDummy[1]->GetType()); |
2538 | break; |
2539 | case KindCode::subscript: |
2540 | CHECK(result.categorySet == IntType); |
2541 | CHECK(*category == TypeCategory::Integer); |
2542 | resultType = |
2543 | DynamicType{TypeCategory::Integer, defaults.subscriptIntegerKind()}; |
2544 | break; |
2545 | case KindCode::size: |
2546 | CHECK(result.categorySet == IntType); |
2547 | CHECK(*category == TypeCategory::Integer); |
2548 | resultType = |
2549 | DynamicType{TypeCategory::Integer, defaults.sizeIntegerKind()}; |
2550 | break; |
2551 | case KindCode::teamType: |
2552 | CHECK(result.categorySet == DerivedType); |
2553 | CHECK(*category == TypeCategory::Derived); |
2554 | resultType = DynamicType{ |
2555 | GetBuiltinDerivedType(builtinsScope, "__builtin_team_type")}; |
2556 | break; |
2557 | case KindCode::greaterOrEqualToKind: |
2558 | case KindCode::exactKind: |
2559 | resultType = DynamicType{*category, result.kindValue}; |
2560 | break; |
2561 | case KindCode::typeless: |
2562 | case KindCode::any: |
2563 | case KindCode::kindArg: |
2564 | case KindCode::dimArg: |
2565 | common::die( |
2566 | "INTERNAL: bad KindCode appears on intrinsic '%s' result", name); |
2567 | break; |
2568 | default: |
2569 | CRASH_NO_CASE; |
2570 | } |
2571 | } else { |
2572 | if (!call.isSubroutineCall) { |
2573 | return std::nullopt; |
2574 | } |
2575 | CHECK(result.kindCode == KindCode::none); |
2576 | } |
2577 | |
2578 | // Emit warnings when the syntactic presence of a DIM= argument determines |
2579 | // the semantics of the call but the associated actual argument may not be |
2580 | // present at execution time. |
2581 | if (dimArg) { |
2582 | std::optional<int> arrayRank; |
2583 | if (arrayArg) { |
2584 | arrayRank = arrayArg->Rank(); |
2585 | if (auto dimVal{ToInt64(actualForDummy[*dimArg])}) { |
2586 | if (*dimVal < 1) { |
2587 | messages.Say( |
2588 | "The value of DIM= (%jd) may not be less than 1"_err_en_US, |
2589 | static_cast<std::intmax_t>(*dimVal)); |
2590 | } else if (*dimVal > *arrayRank) { |
2591 | messages.Say( |
2592 | "The value of DIM= (%jd) may not be greater than %d"_err_en_US, |
2593 | static_cast<std::intmax_t>(*dimVal), *arrayRank); |
2594 | } |
2595 | } |
2596 | } |
2597 | switch (rank) { |
2598 | case Rank::dimReduced: |
2599 | case Rank::dimRemovedOrScalar: |
2600 | case Rank::locReduced: |
2601 | case Rank::scalarIfDim: |
2602 | if (dummy[*dimArg].optionality == Optionality::required) { |
2603 | if (const Symbol *whole{ |
2604 | UnwrapWholeSymbolOrComponentDataRef(actualForDummy[*dimArg])}) { |
2605 | if (IsOptional(*whole) || IsAllocatableOrObjectPointer(whole)) { |
2606 | if (context.languageFeatures().ShouldWarn( |
2607 | common::UsageWarning::OptionalMustBePresent)) { |
2608 | if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) { |
2609 | messages.Say(common::UsageWarning::OptionalMustBePresent, |
2610 | "The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time"_warn_en_US); |
2611 | } else { |
2612 | messages.Say(common::UsageWarning::OptionalMustBePresent, |
2613 | "The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US); |
2614 | } |
2615 | } |
2616 | } |
2617 | } |
2618 | } |
2619 | break; |
2620 | default:; |
2621 | } |
2622 | } |
2623 | |
2624 | // At this point, the call is acceptable. |
2625 | // Determine the rank of the function result. |
2626 | int resultRank{0}; |
2627 | switch (rank) { |
2628 | case Rank::elemental: |
2629 | resultRank = elementalRank; |
2630 | break; |
2631 | case Rank::scalar: |
2632 | resultRank = 0; |
2633 | break; |
2634 | case Rank::vector: |
2635 | resultRank = 1; |
2636 | break; |
2637 | case Rank::matrix: |
2638 | resultRank = 2; |
2639 | break; |
2640 | case Rank::conformable: |
2641 | CHECK(arrayArg); |
2642 | resultRank = arrayArg->Rank(); |
2643 | break; |
2644 | case Rank::dimReduced: |
2645 | CHECK(arrayArg); |
2646 | resultRank = dimArg ? arrayArg->Rank() - 1 : 0; |
2647 | break; |
2648 | case Rank::locReduced: |
2649 | CHECK(arrayArg); |
2650 | resultRank = dimArg ? arrayArg->Rank() - 1 : 1; |
2651 | break; |
2652 | case Rank::rankPlus1: |
2653 | CHECK(knownArg); |
2654 | resultRank = knownArg->Rank() + 1; |
2655 | break; |
2656 | case Rank::shaped: |
2657 | CHECK(shapeArgSize); |
2658 | resultRank = *shapeArgSize; |
2659 | break; |
2660 | case Rank::scalarIfDim: |
2661 | resultRank = dimArg ? 0 : 1; |
2662 | break; |
2663 | case Rank::elementalOrBOZ: |
2664 | case Rank::shape: |
2665 | case Rank::array: |
2666 | case Rank::coarray: |
2667 | case Rank::atom: |
2668 | case Rank::known: |
2669 | case Rank::anyOrAssumedRank: |
2670 | case Rank::arrayOrAssumedRank: |
2671 | case Rank::reduceOperation: |
2672 | case Rank::dimRemovedOrScalar: |
2673 | common::die("INTERNAL: bad Rank code on intrinsic '%s' result", name); |
2674 | break; |
2675 | } |
2676 | CHECK(resultRank >= 0); |
2677 | |
2678 | // Rearrange the actual arguments into dummy argument order. |
2679 | ActualArguments rearranged(dummies); |
2680 | for (std::size_t j{0}; j < dummies; ++j) { |
2681 | if (ActualArgument *arg{actualForDummy[j]}) { |
2682 | rearranged[j] = std::move(*arg); |
2683 | } |
2684 | } |
2685 | |
2686 | // Characterize the specific intrinsic procedure. |
2687 | characteristics::DummyArguments dummyArgs; |
2688 | std::optional<int> sameDummyArg; |
2689 | |
2690 | for (std::size_t j{0}; j < dummies; ++j) { |
2691 | const IntrinsicDummyArgument &d{dummy[std::min(j, dummyArgPatterns - 1)]}; |
2692 | if (const auto &arg{rearranged[j]}) { |
2693 | if (const Expr<SomeType> *expr{arg->UnwrapExpr()}) { |
2694 | std::string kw{d.keyword}; |
2695 | if (arg->keyword()) { |
2696 | kw = arg->keyword()->ToString(); |
2697 | } else if (isMaxMin) { |
2698 | for (std::size_t k{j + 1};; ++k) { |
2699 | kw = "a"s+ std::to_string(k); |
2700 | auto iter{std::find_if(dummyArgs.begin(), dummyArgs.end(), |
2701 | [&kw](const characteristics::DummyArgument &prev) { |
2702 | return prev.name == kw; |
2703 | })}; |
2704 | if (iter == dummyArgs.end()) { |
2705 | break; |
2706 | } |
2707 | } |
2708 | } |
2709 | if (auto dc{characteristics::DummyArgument::FromActual(std::move(kw), |
2710 | *expr, context, /*forImplicitInterface=*/false)}) { |
2711 | if (auto *dummyProc{ |
2712 | std::get_if<characteristics::DummyProcedure>(&dc->u)}) { |
2713 | // Dummy procedures are never elemental. |
2714 | dummyProc->procedure.value().attrs.reset( |
2715 | characteristics::Procedure::Attr::Elemental); |
2716 | } else if (auto *dummyObject{ |
2717 | std::get_if<characteristics::DummyDataObject>( |
2718 | &dc->u)}) { |
2719 | dummyObject->type.set_corank(0); |
2720 | if (d.flags.test(ArgFlag::onlyConstantInquiry)) { |
2721 | dummyObject->attrs.set( |
2722 | characteristics::DummyDataObject::Attr::OnlyIntrinsicInquiry); |
2723 | } |
2724 | } |
2725 | dummyArgs.emplace_back(std::move(*dc)); |
2726 | if (d.typePattern.kindCode == KindCode::same && !sameDummyArg) { |
2727 | sameDummyArg = j; |
2728 | } |
2729 | } else { // error recovery |
2730 | messages.Say( |
2731 | "Could not characterize intrinsic function actual argument '%s'"_err_en_US, |
2732 | expr->AsFortran().c_str()); |
2733 | return std::nullopt; |
2734 | } |
2735 | } else { |
2736 | CHECK(arg->GetAssumedTypeDummy()); |
2737 | dummyArgs.emplace_back(std::string{d.keyword}, |
2738 | characteristics::DummyDataObject{DynamicType::AssumedType()}); |
2739 | } |
2740 | } else { |
2741 | // optional argument is absent |
2742 | CHECK(d.optionality != Optionality::required); |
2743 | if (d.typePattern.kindCode == KindCode::same) { |
2744 | dummyArgs.emplace_back(dummyArgs[sameDummyArg.value()]); |
2745 | } else { |
2746 | auto category{d.typePattern.categorySet.LeastElement().value()}; |
2747 | if (category == TypeCategory::Derived) { |
2748 | // TODO: any other built-in derived types used as optional intrinsic |
2749 | // dummies? |
2750 | CHECK(d.typePattern.kindCode == KindCode::teamType); |
2751 | characteristics::TypeAndShape typeAndShape{ |
2752 | GetBuiltinDerivedType(builtinsScope, "__builtin_team_type")}; |
2753 | dummyArgs.emplace_back(std::string{d.keyword}, |
2754 | characteristics::DummyDataObject{std::move(typeAndShape)}); |
2755 | } else { |
2756 | characteristics::TypeAndShape typeAndShape{ |
2757 | DynamicType{category, defaults.GetDefaultKind(category)}}; |
2758 | dummyArgs.emplace_back(std::string{d.keyword}, |
2759 | characteristics::DummyDataObject{std::move(typeAndShape)}); |
2760 | } |
2761 | } |
2762 | dummyArgs.back().SetOptional(); |
2763 | } |
2764 | dummyArgs.back().SetIntent(d.intent); |
2765 | } |
2766 | characteristics::Procedure::Attrs attrs; |
2767 | if (elementalRank > 0) { |
2768 | attrs.set(characteristics::Procedure::Attr::Elemental); |
2769 | } |
2770 | if (call.isSubroutineCall) { |
2771 | if (intrinsicClass == IntrinsicClass::pureSubroutine /* MOVE_ALLOC */ || |
2772 | intrinsicClass == IntrinsicClass::elementalSubroutine /* MVBITS */) { |
2773 | attrs.set(characteristics::Procedure::Attr::Pure); |
2774 | } |
2775 | return SpecificCall{ |
2776 | SpecificIntrinsic{ |
2777 | name, characteristics::Procedure{std::move(dummyArgs), attrs}}, |
2778 | std::move(rearranged)}; |
2779 | } else { |
2780 | attrs.set(characteristics::Procedure::Attr::Pure); |
2781 | characteristics::TypeAndShape typeAndShape{resultType.value(), resultRank}; |
2782 | characteristics::FunctionResult funcResult{std::move(typeAndShape)}; |
2783 | characteristics::Procedure chars{ |
2784 | std::move(funcResult), std::move(dummyArgs), attrs}; |
2785 | return SpecificCall{ |
2786 | SpecificIntrinsic{name, std::move(chars)}, std::move(rearranged)}; |
2787 | } |
2788 | } |
2789 | |
2790 | class IntrinsicProcTable::Implementation { |
2791 | public: |
2792 | explicit Implementation(const common::IntrinsicTypeDefaultKinds &dfts) |
2793 | : defaults_{dfts} { |
2794 | for (const IntrinsicInterface &f : genericIntrinsicFunction) { |
2795 | genericFuncs_.insert(std::make_pair(std::string{f.name}, &f)); |
2796 | } |
2797 | for (const std::pair<const char *, const char *> &a : genericAlias) { |
2798 | aliases_.insert( |
2799 | std::make_pair(std::string{a.first}, std::string{a.second})); |
2800 | } |
2801 | for (const SpecificIntrinsicInterface &f : specificIntrinsicFunction) { |
2802 | specificFuncs_.insert(std::make_pair(std::string{f.name}, &f)); |
2803 | } |
2804 | for (const IntrinsicInterface &f : intrinsicSubroutine) { |
2805 | subroutines_.insert(std::make_pair(std::string{f.name}, &f)); |
2806 | } |
2807 | } |
2808 | |
2809 | void SupplyBuiltins(const semantics::Scope &builtins) { |
2810 | builtinsScope_ = &builtins; |
2811 | } |
2812 | |
2813 | bool IsIntrinsic(const std::string &) const; |
2814 | bool IsIntrinsicFunction(const std::string &) const; |
2815 | bool IsIntrinsicSubroutine(const std::string &) const; |
2816 | bool IsDualIntrinsic(const std::string &) const; |
2817 | |
2818 | IntrinsicClass GetIntrinsicClass(const std::string &) const; |
2819 | std::string GetGenericIntrinsicName(const std::string &) const; |
2820 | |
2821 | std::optional<SpecificCall> Probe( |
2822 | const CallCharacteristics &, ActualArguments &, FoldingContext &) const; |
2823 | |
2824 | std::optional<SpecificIntrinsicFunctionInterface> IsSpecificIntrinsicFunction( |
2825 | const std::string &) const; |
2826 | |
2827 | llvm::raw_ostream &Dump(llvm::raw_ostream &) const; |
2828 | |
2829 | private: |
2830 | DynamicType GetSpecificType(const TypePattern &) const; |
2831 | SpecificCall HandleNull(ActualArguments &, FoldingContext &) const; |
2832 | std::optional<SpecificCall> HandleC_F_Pointer( |
2833 | ActualArguments &, FoldingContext &) const; |
2834 | std::optional<SpecificCall> HandleC_Loc( |
2835 | ActualArguments &, FoldingContext &) const; |
2836 | std::optional<SpecificCall> HandleC_Devloc( |
2837 | ActualArguments &, FoldingContext &) const; |
2838 | const std::string &ResolveAlias(const std::string &name) const { |
2839 | auto iter{aliases_.find(name)}; |
2840 | return iter == aliases_.end() ? name : iter->second; |
2841 | } |
2842 | |
2843 | common::IntrinsicTypeDefaultKinds defaults_; |
2844 | std::multimap<std::string, const IntrinsicInterface *> genericFuncs_; |
2845 | std::multimap<std::string, const SpecificIntrinsicInterface *> specificFuncs_; |
2846 | std::multimap<std::string, const IntrinsicInterface *> subroutines_; |
2847 | const semantics::Scope *builtinsScope_{nullptr}; |
2848 | std::map<std::string, std::string> aliases_; |
2849 | semantics::ParamValue assumedLen_{ |
2850 | semantics::ParamValue::Assumed(common::TypeParamAttr::Len)}; |
2851 | }; |
2852 | |
2853 | bool IntrinsicProcTable::Implementation::IsIntrinsicFunction( |
2854 | const std::string &name0) const { |
2855 | const std::string &name{ResolveAlias(name0)}; |
2856 | auto specificRange{specificFuncs_.equal_range(name)}; |
2857 | if (specificRange.first != specificRange.second) { |
2858 | return true; |
2859 | } |
2860 | auto genericRange{genericFuncs_.equal_range(name)}; |
2861 | if (genericRange.first != genericRange.second) { |
2862 | return true; |
2863 | } |
2864 | // special cases |
2865 | return name == "__builtin_c_loc"|| name == "__builtin_c_devloc"|| |
2866 | name == "null"; |
2867 | } |
2868 | bool IntrinsicProcTable::Implementation::IsIntrinsicSubroutine( |
2869 | const std::string &name0) const { |
2870 | const std::string &name{ResolveAlias(name0)}; |
2871 | auto subrRange{subroutines_.equal_range(name)}; |
2872 | if (subrRange.first != subrRange.second) { |
2873 | return true; |
2874 | } |
2875 | // special cases |
2876 | return name == "__builtin_c_f_pointer"; |
2877 | } |
2878 | bool IntrinsicProcTable::Implementation::IsIntrinsic( |
2879 | const std::string &name) const { |
2880 | return IsIntrinsicFunction(name) || IsIntrinsicSubroutine(name); |
2881 | } |
2882 | bool IntrinsicProcTable::Implementation::IsDualIntrinsic( |
2883 | const std::string &name) const { |
2884 | // Collection for some intrinsics with function and subroutine form, |
2885 | // in order to pass the semantic check. |
2886 | static const std::string dualIntrinsic[]{{"chdir"}, { "etime"}, { "fseek"}, |
2887 | {"ftell"}, { "getcwd"}, { "hostnm"}, { "putenv"s}, { "rename"}, { "second"}, |
2888 | {"system"}, { "unlink"}}; |
2889 | return llvm::is_contained(dualIntrinsic, name); |
2890 | } |
2891 | |
2892 | IntrinsicClass IntrinsicProcTable::Implementation::GetIntrinsicClass( |
2893 | const std::string &name) const { |
2894 | auto specificIntrinsic{specificFuncs_.find(name)}; |
2895 | if (specificIntrinsic != specificFuncs_.end()) { |
2896 | return specificIntrinsic->second->intrinsicClass; |
2897 | } |
2898 | auto genericIntrinsic{genericFuncs_.find(name)}; |
2899 | if (genericIntrinsic != genericFuncs_.end()) { |
2900 | return genericIntrinsic->second->intrinsicClass; |
2901 | } |
2902 | auto subrIntrinsic{subroutines_.find(name)}; |
2903 | if (subrIntrinsic != subroutines_.end()) { |
2904 | return subrIntrinsic->second->intrinsicClass; |
2905 | } |
2906 | return IntrinsicClass::noClass; |
2907 | } |
2908 | |
2909 | std::string IntrinsicProcTable::Implementation::GetGenericIntrinsicName( |
2910 | const std::string &name) const { |
2911 | auto specificIntrinsic{specificFuncs_.find(name)}; |
2912 | if (specificIntrinsic != specificFuncs_.end()) { |
2913 | if (const char *genericName{specificIntrinsic->second->generic}) { |
2914 | return {genericName}; |
2915 | } |
2916 | } |
2917 | return name; |
2918 | } |
2919 | |
2920 | bool CheckAndRearrangeArguments(ActualArguments &arguments, |
2921 | parser::ContextualMessages &messages, const char *const dummyKeywords[], |
2922 | std::size_t trailingOptionals) { |
2923 | std::size_t numDummies{0}; |
2924 | while (dummyKeywords[numDummies]) { |
2925 | ++numDummies; |
2926 | } |
2927 | CHECK(trailingOptionals <= numDummies); |
2928 | if (arguments.size() > numDummies) { |
2929 | messages.Say("Too many actual arguments (%zd > %zd)"_err_en_US, |
2930 | arguments.size(), numDummies); |
2931 | return false; |
2932 | } |
2933 | ActualArguments rearranged(numDummies); |
2934 | bool anyKeywords{false}; |
2935 | std::size_t position{0}; |
2936 | for (std::optional<ActualArgument> &arg : arguments) { |
2937 | std::size_t dummyIndex{0}; |
2938 | if (arg && arg->keyword()) { |
2939 | anyKeywords = true; |
2940 | for (; dummyIndex < numDummies; ++dummyIndex) { |
2941 | if (*arg->keyword() == dummyKeywords[dummyIndex]) { |
2942 | break; |
2943 | } |
2944 | } |
2945 | if (dummyIndex >= numDummies) { |
2946 | messages.Say(*arg->keyword(), |
2947 | "Unknown argument keyword '%s='"_err_en_US, *arg->keyword()); |
2948 | return false; |
2949 | } |
2950 | } else if (anyKeywords) { |
2951 | messages.Say(arg ? arg->sourceLocation() : messages.at(), |
2952 | "A positional actual argument may not appear after any keyword arguments"_err_en_US); |
2953 | return false; |
2954 | } else { |
2955 | dummyIndex = position++; |
2956 | } |
2957 | if (rearranged[dummyIndex]) { |
2958 | messages.Say(arg ? arg->sourceLocation() : messages.at(), |
2959 | "Dummy argument '%s=' appears more than once"_err_en_US, |
2960 | dummyKeywords[dummyIndex]); |
2961 | return false; |
2962 | } |
2963 | rearranged[dummyIndex] = std::move(arg); |
2964 | arg.reset(); |
2965 | } |
2966 | bool anyMissing{false}; |
2967 | for (std::size_t j{0}; j < numDummies - trailingOptionals; ++j) { |
2968 | if (!rearranged[j]) { |
2969 | messages.Say("Dummy argument '%s=' is absent and not OPTIONAL"_err_en_US, |
2970 | dummyKeywords[j]); |
2971 | anyMissing = true; |
2972 | } |
2973 | } |
2974 | arguments = std::move(rearranged); |
2975 | return !anyMissing; |
2976 | } |
2977 | |
2978 | // The NULL() intrinsic is a special case. |
2979 | SpecificCall IntrinsicProcTable::Implementation::HandleNull( |
2980 | ActualArguments &arguments, FoldingContext &context) const { |
2981 | static const char *const keywords[]{"mold", nullptr}; |
2982 | if (CheckAndRearrangeArguments(arguments, context.messages(), keywords, 1) && |
2983 | arguments[0]) { |
2984 | Expr<SomeType> *mold{arguments[0]->UnwrapExpr()}; |
2985 | bool isBareNull{IsBareNullPointer(mold)}; |
2986 | if (isBareNull) { |
2987 | // NULL(NULL()), NULL(NULL(NULL())), &c. are all just NULL() |
2988 | mold = nullptr; |
2989 | } |
2990 | if (mold) { |
2991 | if (IsAssumedRank(*arguments[0])) { |
2992 | context.messages().Say(arguments[0]->sourceLocation(), |
2993 | "MOLD= argument to NULL() must not be assumed-rank"_err_en_US); |
2994 | } |
2995 | bool isProcPtrTarget{ |
2996 | IsProcedurePointerTarget(*mold) && !IsNullObjectPointer(mold)}; |
2997 | if (isProcPtrTarget || IsAllocatableOrPointerObject(*mold)) { |
2998 | characteristics::DummyArguments args; |
2999 | std::optional<characteristics::FunctionResult> fResult; |
3000 | bool isAllocatableMold{false}; |
3001 | if (isProcPtrTarget) { |
3002 | // MOLD= procedure pointer |
3003 | std::optional<characteristics::Procedure> procPointer; |
3004 | if (IsNullProcedurePointer(mold)) { |
3005 | procPointer = |
3006 | characteristics::Procedure::Characterize(*mold, context); |
3007 | } else { |
3008 | const Symbol *last{GetLastSymbol(*mold)}; |
3009 | procPointer = |
3010 | characteristics::Procedure::Characterize(DEREF(last), context); |
3011 | } |
3012 | // procPointer is vacant if there was an error with the analysis |
3013 | // associated with the procedure pointer |
3014 | if (procPointer) { |
3015 | args.emplace_back("mold"s, |
3016 | characteristics::DummyProcedure{common::Clone(*procPointer)}); |
3017 | fResult.emplace(std::move(*procPointer)); |
3018 | } |
3019 | } else if (auto type{mold->GetType()}) { |
3020 | // MOLD= object pointer or allocatable |
3021 | characteristics::TypeAndShape typeAndShape{ |
3022 | *type, GetShape(context, *mold)}; |
3023 | args.emplace_back( |
3024 | "mold"s, characteristics::DummyDataObject{typeAndShape}); |
3025 | fResult.emplace(std::move(typeAndShape)); |
3026 | isAllocatableMold = IsAllocatableDesignator(*mold); |
3027 | } else { |
3028 | context.messages().Say(arguments[0]->sourceLocation(), |
3029 | "MOLD= argument to NULL() lacks type"_err_en_US); |
3030 | } |
3031 | if (fResult) { |
3032 | fResult->attrs.set(characteristics::FunctionResult::Attr::Pointer); |
3033 | characteristics::Procedure::Attrs attrs; |
3034 | attrs.set(isAllocatableMold |
3035 | ? characteristics::Procedure::Attr::NullAllocatable |
3036 | : characteristics::Procedure::Attr::NullPointer); |
3037 | characteristics::Procedure chars{ |
3038 | std::move(*fResult), std::move(args), attrs}; |
3039 | return SpecificCall{SpecificIntrinsic{"null"s, std::move(chars)}, |
3040 | std::move(arguments)}; |
3041 | } |
3042 | } |
3043 | } |
3044 | if (!isBareNull) { |
3045 | context.messages().Say(arguments[0]->sourceLocation(), |
3046 | "MOLD= argument to NULL() must be a pointer or allocatable"_err_en_US); |
3047 | } |
3048 | } |
3049 | characteristics::Procedure::Attrs attrs; |
3050 | attrs.set(characteristics::Procedure::Attr::NullPointer); |
3051 | attrs.set(characteristics::Procedure::Attr::Pure); |
3052 | arguments.clear(); |
3053 | return SpecificCall{ |
3054 | SpecificIntrinsic{"null"s, |
3055 | characteristics::Procedure{characteristics::DummyArguments{}, attrs}}, |
3056 | std::move(arguments)}; |
3057 | } |
3058 | |
3059 | // Subroutine C_F_POINTER(CPTR=,FPTR=[,SHAPE=]) from |
3060 | // intrinsic module ISO_C_BINDING (18.2.3.3) |
3061 | std::optional<SpecificCall> |
3062 | IntrinsicProcTable::Implementation::HandleC_F_Pointer( |
3063 | ActualArguments &arguments, FoldingContext &context) const { |
3064 | characteristics::Procedure::Attrs attrs; |
3065 | attrs.set(characteristics::Procedure::Attr::Subroutine); |
3066 | static const char *const keywords[]{"cptr", "fptr", "shape", nullptr}; |
3067 | characteristics::DummyArguments dummies; |
3068 | if (CheckAndRearrangeArguments(arguments, context.messages(), keywords, 1)) { |
3069 | CHECK(arguments.size() == 3); |
3070 | if (const auto *expr{arguments[0].value().UnwrapExpr()}) { |
3071 | // General semantic checks will catch an actual argument that's not |
3072 | // scalar. |
3073 | if (auto type{expr->GetType()}) { |
3074 | if (type->category() != TypeCategory::Derived || |
3075 | type->IsPolymorphic() || |
3076 | (type->GetDerivedTypeSpec().typeSymbol().name() != |
3077 | "__builtin_c_ptr"&& |
3078 | type->GetDerivedTypeSpec().typeSymbol().name() != |
3079 | "__builtin_c_devptr")) { |
3080 | context.messages().Say(arguments[0]->sourceLocation(), |
3081 | "CPTR= argument to C_F_POINTER() must be a C_PTR"_err_en_US); |
3082 | } |
3083 | characteristics::DummyDataObject cptr{ |
3084 | characteristics::TypeAndShape{*type}}; |
3085 | cptr.intent = common::Intent::In; |
3086 | dummies.emplace_back("cptr"s, std::move(cptr)); |
3087 | } |
3088 | } |
3089 | if (const auto *expr{arguments[1].value().UnwrapExpr()}) { |
3090 | int fptrRank{expr->Rank()}; |
3091 | auto at{arguments[1]->sourceLocation()}; |
3092 | if (auto type{expr->GetType()}) { |
3093 | if (type->HasDeferredTypeParameter()) { |
3094 | context.messages().Say(at, |
3095 | "FPTR= argument to C_F_POINTER() may not have a deferred type parameter"_err_en_US); |
3096 | } else if (type->category() == TypeCategory::Derived) { |
3097 | if (context.languageFeatures().ShouldWarn( |
3098 | common::UsageWarning::Interoperability) && |
3099 | type->IsUnlimitedPolymorphic()) { |
3100 | context.messages().Say(common::UsageWarning::Interoperability, at, |
3101 | "FPTR= argument to C_F_POINTER() should not be unlimited polymorphic"_warn_en_US); |
3102 | } else if (!type->GetDerivedTypeSpec().typeSymbol().attrs().test( |
3103 | semantics::Attr::BIND_C) && |
3104 | context.languageFeatures().ShouldWarn( |
3105 | common::UsageWarning::Portability)) { |
3106 | context.messages().Say(common::UsageWarning::Portability, at, |
3107 | "FPTR= argument to C_F_POINTER() should not have a derived type that is not BIND(C)"_port_en_US); |
3108 | } |
3109 | } else if (!IsInteroperableIntrinsicType( |
3110 | *type, &context.languageFeatures()) |
3111 | .value_or(true)) { |
3112 | if (type->category() == TypeCategory::Character && |
3113 | type->kind() == 1) { |
3114 | if (context.languageFeatures().ShouldWarn( |
3115 | common::UsageWarning::CharacterInteroperability)) { |
3116 | context.messages().Say( |
3117 | common::UsageWarning::CharacterInteroperability, at, |
3118 | "FPTR= argument to C_F_POINTER() should not have the non-interoperable character length %s"_warn_en_US, |
3119 | type->AsFortran()); |
3120 | } |
3121 | } else if (context.languageFeatures().ShouldWarn( |
3122 | common::UsageWarning::Interoperability)) { |
3123 | context.messages().Say(common::UsageWarning::Interoperability, at, |
3124 | "FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type or kind %s"_warn_en_US, |
3125 | type->AsFortran()); |
3126 | } |
3127 | } |
3128 | if (ExtractCoarrayRef(*expr)) { |
3129 | context.messages().Say(at, |
3130 | "FPTR= argument to C_F_POINTER() may not be a coindexed object"_err_en_US); |
3131 | } |
3132 | characteristics::DummyDataObject fptr{ |
3133 | characteristics::TypeAndShape{*type, fptrRank}}; |
3134 | fptr.intent = common::Intent::Out; |
3135 | fptr.attrs.set(characteristics::DummyDataObject::Attr::Pointer); |
3136 | dummies.emplace_back("fptr"s, std::move(fptr)); |
3137 | } else { |
3138 | context.messages().Say( |
3139 | at, "FPTR= argument to C_F_POINTER() must have a type"_err_en_US); |
3140 | } |
3141 | if (arguments[2] && fptrRank == 0) { |
3142 | context.messages().Say(arguments[2]->sourceLocation(), |
3143 | "SHAPE= argument to C_F_POINTER() may not appear when FPTR= is scalar"_err_en_US); |
3144 | } else if (!arguments[2] && fptrRank > 0) { |
3145 | context.messages().Say( |
3146 | "SHAPE= argument to C_F_POINTER() must appear when FPTR= is an array"_err_en_US); |
3147 | } else if (arguments[2]) { |
3148 | if (const auto *argExpr{arguments[2].value().UnwrapExpr()}) { |
3149 | if (argExpr->Rank() > 1) { |
3150 | context.messages().Say(arguments[2]->sourceLocation(), |
3151 | "SHAPE= argument to C_F_POINTER() must be a rank-one array."_err_en_US); |
3152 | } else if (argExpr->Rank() == 1) { |
3153 | if (auto constShape{GetConstantShape(context, *argExpr)}) { |
3154 | if (constShape->At(ConstantSubscripts{1}).ToInt64() != fptrRank) { |
3155 | context.messages().Say(arguments[2]->sourceLocation(), |
3156 | "SHAPE= argument to C_F_POINTER() must have size equal to the rank of FPTR="_err_en_US); |
3157 | } |
3158 | } |
3159 | } |
3160 | } |
3161 | } |
3162 | } |
3163 | } |
3164 | if (dummies.size() == 2) { |
3165 | DynamicType shapeType{TypeCategory::Integer, defaults_.sizeIntegerKind()}; |
3166 | if (arguments[2]) { |
3167 | if (auto type{arguments[2]->GetType()}) { |
3168 | if (type->category() == TypeCategory::Integer) { |
3169 | shapeType = *type; |
3170 | } |
3171 | } |
3172 | } |
3173 | characteristics::DummyDataObject shape{ |
3174 | characteristics::TypeAndShape{shapeType, 1}}; |
3175 | shape.intent = common::Intent::In; |
3176 | shape.attrs.set(characteristics::DummyDataObject::Attr::Optional); |
3177 | dummies.emplace_back("shape"s, std::move(shape)); |
3178 | return SpecificCall{ |
3179 | SpecificIntrinsic{"__builtin_c_f_pointer"s, |
3180 | characteristics::Procedure{std::move(dummies), attrs}}, |
3181 | std::move(arguments)}; |
3182 | } else { |
3183 | return std::nullopt; |
3184 | } |
3185 | } |
3186 | |
3187 | // Function C_LOC(X) from intrinsic module ISO_C_BINDING (18.2.3.6) |
3188 | std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc( |
3189 | ActualArguments &arguments, FoldingContext &context) const { |
3190 | static const char *const keywords[]{"x", nullptr}; |
3191 | if (CheckAndRearrangeArguments(arguments, context.messages(), keywords)) { |
3192 | CHECK(arguments.size() == 1); |
3193 | CheckForCoindexedObject(context.messages(), arguments[0], "c_loc", "x"); |
3194 | const auto *expr{arguments[0].value().UnwrapExpr()}; |
3195 | if (expr && |
3196 | !(IsObjectPointer(*expr) || |
3197 | (IsVariable(*expr) && GetLastTarget(GetSymbolVector(*expr))))) { |
3198 | context.messages().Say(arguments[0]->sourceLocation(), |
3199 | "C_LOC() argument must be a data pointer or target"_err_en_US); |
3200 | } |
3201 | if (auto typeAndShape{characteristics::TypeAndShape::Characterize( |
3202 | arguments[0], context)}) { |
3203 | if (expr && !IsContiguous(*expr, context).value_or(true)) { |
3204 | context.messages().Say(arguments[0]->sourceLocation(), |
3205 | "C_LOC() argument must be contiguous"_err_en_US); |
3206 | } |
3207 | if (auto constExtents{AsConstantExtents(context, typeAndShape->shape())}; |
3208 | constExtents && GetSize(*constExtents) == 0) { |
3209 | context.messages().Say(arguments[0]->sourceLocation(), |
3210 | "C_LOC() argument may not be a zero-sized array"_err_en_US); |
3211 | } |
3212 | if (!(typeAndShape->type().category() != TypeCategory::Derived || |
3213 | typeAndShape->type().IsAssumedType() || |
3214 | (!typeAndShape->type().IsPolymorphic() && |
3215 | CountNonConstantLenParameters( |
3216 | typeAndShape->type().GetDerivedTypeSpec()) == 0))) { |
3217 | context.messages().Say(arguments[0]->sourceLocation(), |
3218 | "C_LOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter"_err_en_US); |
3219 | } else if (typeAndShape->type().knownLength().value_or(1) == 0) { |
3220 | context.messages().Say(arguments[0]->sourceLocation(), |
3221 | "C_LOC() argument may not be zero-length character"_err_en_US); |
3222 | } else if (typeAndShape->type().category() != TypeCategory::Derived && |
3223 | !IsInteroperableIntrinsicType(typeAndShape->type()).value_or(true)) { |
3224 | if (typeAndShape->type().category() == TypeCategory::Character && |
3225 | typeAndShape->type().kind() == 1) { |
3226 | // Default character kind, but length is not known to be 1 |
3227 | if (context.languageFeatures().ShouldWarn( |
3228 | common::UsageWarning::CharacterInteroperability)) { |
3229 | context.messages().Say( |
3230 | common::UsageWarning::CharacterInteroperability, |
3231 | arguments[0]->sourceLocation(), |
3232 | "C_LOC() argument has non-interoperable character length"_warn_en_US); |
3233 | } |
3234 | } else if (context.languageFeatures().ShouldWarn( |
3235 | common::UsageWarning::Interoperability)) { |
3236 | context.messages().Say(common::UsageWarning::Interoperability, |
3237 | arguments[0]->sourceLocation(), |
3238 | "C_LOC() argument has non-interoperable intrinsic type or kind"_warn_en_US); |
3239 | } |
3240 | } |
3241 | |
3242 | characteristics::DummyDataObject ddo{std::move(*typeAndShape)}; |
3243 | ddo.intent = common::Intent::In; |
3244 | return SpecificCall{ |
3245 | SpecificIntrinsic{"__builtin_c_loc"s, |
3246 | characteristics::Procedure{ |
3247 | characteristics::FunctionResult{ |
3248 | DynamicType{GetBuiltinDerivedType( |
3249 | builtinsScope_, "__builtin_c_ptr")}}, |
3250 | characteristics::DummyArguments{ |
3251 | characteristics::DummyArgument{"x"s, std::move(ddo)}}, |
3252 | characteristics::Procedure::Attrs{ |
3253 | characteristics::Procedure::Attr::Pure}}}, |
3254 | std::move(arguments)}; |
3255 | } |
3256 | } |
3257 | return std::nullopt; |
3258 | } |
3259 | |
3260 | // CUDA Fortran C_DEVLOC(x) |
3261 | std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Devloc( |
3262 | ActualArguments &arguments, FoldingContext &context) const { |
3263 | static const char *const keywords[]{"cptr", nullptr}; |
3264 | |
3265 | if (CheckAndRearrangeArguments(arguments, context.messages(), keywords)) { |
3266 | CHECK(arguments.size() == 1); |
3267 | const auto *expr{arguments[0].value().UnwrapExpr()}; |
3268 | if (auto typeAndShape{characteristics::TypeAndShape::Characterize( |
3269 | arguments[0], context)}) { |
3270 | if (expr && !IsContiguous(*expr, context).value_or(true)) { |
3271 | context.messages().Say(arguments[0]->sourceLocation(), |
3272 | "C_DEVLOC() argument must be contiguous"_err_en_US); |
3273 | } |
3274 | if (auto constExtents{AsConstantExtents(context, typeAndShape->shape())}; |
3275 | constExtents && GetSize(*constExtents) == 0) { |
3276 | context.messages().Say(arguments[0]->sourceLocation(), |
3277 | "C_DEVLOC() argument may not be a zero-sized array"_err_en_US); |
3278 | } |
3279 | if (!(typeAndShape->type().category() != TypeCategory::Derived || |
3280 | typeAndShape->type().IsAssumedType() || |
3281 | (!typeAndShape->type().IsPolymorphic() && |
3282 | CountNonConstantLenParameters( |
3283 | typeAndShape->type().GetDerivedTypeSpec()) == 0))) { |
3284 | context.messages().Say(arguments[0]->sourceLocation(), |
3285 | "C_DEVLOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter"_err_en_US); |
3286 | } else if (typeAndShape->type().knownLength().value_or(1) == 0) { |
3287 | context.messages().Say(arguments[0]->sourceLocation(), |
3288 | "C_DEVLOC() argument may not be zero-length character"_err_en_US); |
3289 | } else if (typeAndShape->type().category() != TypeCategory::Derived && |
3290 | !IsInteroperableIntrinsicType(typeAndShape->type()).value_or(true)) { |
3291 | if (typeAndShape->type().category() == TypeCategory::Character && |
3292 | typeAndShape->type().kind() == 1) { |
3293 | // Default character kind, but length is not known to be 1 |
3294 | if (context.languageFeatures().ShouldWarn( |
3295 | common::UsageWarning::CharacterInteroperability)) { |
3296 | context.messages().Say( |
3297 | common::UsageWarning::CharacterInteroperability, |
3298 | arguments[0]->sourceLocation(), |
3299 | "C_DEVLOC() argument has non-interoperable character length"_warn_en_US); |
3300 | } |
3301 | } else if (context.languageFeatures().ShouldWarn( |
3302 | common::UsageWarning::Interoperability)) { |
3303 | context.messages().Say(common::UsageWarning::Interoperability, |
3304 | arguments[0]->sourceLocation(), |
3305 | "C_DEVLOC() argument has non-interoperable intrinsic type or kind"_warn_en_US); |
3306 | } |
3307 | } |
3308 | |
3309 | characteristics::DummyDataObject ddo{std::move(*typeAndShape)}; |
3310 | ddo.intent = common::Intent::In; |
3311 | return SpecificCall{ |
3312 | SpecificIntrinsic{"__builtin_c_devloc"s, |
3313 | characteristics::Procedure{ |
3314 | characteristics::FunctionResult{ |
3315 | DynamicType{GetBuiltinDerivedType( |
3316 | builtinsScope_, "__builtin_c_devptr")}}, |
3317 | characteristics::DummyArguments{ |
3318 | characteristics::DummyArgument{"cptr"s, std::move(ddo)}}, |
3319 | characteristics::Procedure::Attrs{ |
3320 | characteristics::Procedure::Attr::Pure}}}, |
3321 | std::move(arguments)}; |
3322 | } |
3323 | } |
3324 | return std::nullopt; |
3325 | } |
3326 | |
3327 | static bool CheckForNonPositiveValues(FoldingContext &context, |
3328 | const ActualArgument &arg, const std::string &procName, |
3329 | const std::string &argName) { |
3330 | bool ok{true}; |
3331 | if (arg.Rank() > 0) { |
3332 | if (const Expr<SomeType> *expr{arg.UnwrapExpr()}) { |
3333 | if (const auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) { |
3334 | Fortran::common::visit( |
3335 | [&](const auto &kindExpr) { |
3336 | using IntType = typename std::decay_t<decltype(kindExpr)>::Result; |
3337 | if (const auto *constArray{ |
3338 | UnwrapConstantValue<IntType>(kindExpr)}) { |
3339 | for (std::size_t j{0}; j < constArray->size(); ++j) { |
3340 | auto arrayExpr{constArray->values().at(j)}; |
3341 | if (arrayExpr.IsNegative() || arrayExpr.IsZero()) { |
3342 | ok = false; |
3343 | context.messages().Say(arg.sourceLocation(), |
3344 | "'%s=' argument for intrinsic '%s' must contain all positive values"_err_en_US, |
3345 | argName, procName); |
3346 | } |
3347 | } |
3348 | } |
3349 | }, |
3350 | intExpr->u); |
3351 | } |
3352 | } |
3353 | } else { |
3354 | if (auto val{ToInt64(arg.UnwrapExpr())}) { |
3355 | if (*val <= 0) { |
3356 | ok = false; |
3357 | context.messages().Say(arg.sourceLocation(), |
3358 | "'%s=' argument for intrinsic '%s' must be a positive value, but is %jd"_err_en_US, |
3359 | argName, procName, static_cast<std::intmax_t>(*val)); |
3360 | } |
3361 | } |
3362 | } |
3363 | return ok; |
3364 | } |
3365 | |
3366 | static bool CheckAtomicDefineAndRef(FoldingContext &context, |
3367 | const std::optional<ActualArgument> &atomArg, |
3368 | const std::optional<ActualArgument> &valueArg, |
3369 | const std::optional<ActualArgument> &statArg, const std::string &procName) { |
3370 | bool sameType{true}; |
3371 | if (valueArg && atomArg) { |
3372 | // for atomic_define and atomic_ref, 'value' arg must be the same type as |
3373 | // 'atom', but it doesn't have to be the same kind |
3374 | if (valueArg->GetType()->category() != atomArg->GetType()->category()) { |
3375 | sameType = false; |
3376 | context.messages().Say(valueArg->sourceLocation(), |
3377 | "'value=' argument to '%s' must have same type as 'atom=', but is '%s'"_err_en_US, |
3378 | procName, valueArg->GetType()->AsFortran()); |
3379 | } |
3380 | } |
3381 | |
3382 | return sameType && |
3383 | CheckForCoindexedObject(context.messages(), statArg, procName, "stat"); |
3384 | } |
3385 | |
3386 | // Applies any semantic checks peculiar to an intrinsic. |
3387 | // TODO: Move the rest of these checks to Semantics/check-call.cpp. |
3388 | static bool ApplySpecificChecks(SpecificCall &call, FoldingContext &context) { |
3389 | bool ok{true}; |
3390 | const std::string &name{call.specificIntrinsic.name}; |
3391 | if (name == "allocated") { |
3392 | const auto &arg{call.arguments[0]}; |
3393 | if (arg) { |
3394 | if (const auto *expr{arg->UnwrapExpr()}) { |
3395 | ok = IsAllocatableDesignator(*expr) || IsNullAllocatable(expr); |
3396 | } |
3397 | } |
3398 | if (!ok) { |
3399 | context.messages().Say( |
3400 | arg ? arg->sourceLocation() : context.messages().at(), |
3401 | "Argument of ALLOCATED() must be an ALLOCATABLE object or component"_err_en_US); |
3402 | } |
3403 | } else if (name == "atomic_add"|| name == "atomic_and"|| |
3404 | name == "atomic_or"|| name == "atomic_xor"|| name == "event_query") { |
3405 | return CheckForCoindexedObject( |
3406 | context.messages(), call.arguments[2], name, "stat"); |
3407 | } else if (name == "atomic_cas") { |
3408 | return CheckForCoindexedObject( |
3409 | context.messages(), call.arguments[4], name, "stat"); |
3410 | } else if (name == "atomic_define") { |
3411 | return CheckAtomicDefineAndRef( |
3412 | context, call.arguments[0], call.arguments[1], call.arguments[2], name); |
3413 | } else if (name == "atomic_fetch_add"|| name == "atomic_fetch_and"|| |
3414 | name == "atomic_fetch_or"|| name == "atomic_fetch_xor") { |
3415 | return CheckForCoindexedObject( |
3416 | context.messages(), call.arguments[3], name, "stat"); |
3417 | } else if (name == "atomic_ref") { |
3418 | return CheckAtomicDefineAndRef( |
3419 | context, call.arguments[1], call.arguments[0], call.arguments[2], name); |
3420 | } else if (name == "co_broadcast"|| name == "co_max"|| name == "co_min"|| |
3421 | name == "co_sum") { |
3422 | bool aOk{CheckForCoindexedObject( |
3423 | context.messages(), call.arguments[0], name, "a")}; |
3424 | bool statOk{CheckForCoindexedObject( |
3425 | context.messages(), call.arguments[2], name, "stat")}; |
3426 | bool errmsgOk{CheckForCoindexedObject( |
3427 | context.messages(), call.arguments[3], name, "errmsg")}; |
3428 | ok = aOk && statOk && errmsgOk; |
3429 | } else if (name == "image_status") { |
3430 | if (const auto &arg{call.arguments[0]}) { |
3431 | ok = CheckForNonPositiveValues(context, *arg, name, "image"); |
3432 | } |
3433 | } else if (name == "loc") { |
3434 | const auto &arg{call.arguments[0]}; |
3435 | ok = |
3436 | arg && (arg->GetAssumedTypeDummy() || GetLastSymbol(arg->UnwrapExpr())); |
3437 | if (!ok) { |
3438 | context.messages().Say( |
3439 | arg ? arg->sourceLocation() : context.messages().at(), |
3440 | "Argument of LOC() must be an object or procedure"_err_en_US); |
3441 | } |
3442 | } |
3443 | return ok; |
3444 | } |
3445 | |
3446 | static DynamicType GetReturnType(const SpecificIntrinsicInterface &interface, |
3447 | const common::IntrinsicTypeDefaultKinds &defaults) { |
3448 | TypeCategory category{TypeCategory::Integer}; |
3449 | switch (interface.result.kindCode) { |
3450 | case KindCode::defaultIntegerKind: |
3451 | break; |
3452 | case KindCode::doublePrecision: |
3453 | case KindCode::quadPrecision: |
3454 | case KindCode::defaultRealKind: |
3455 | category = TypeCategory::Real; |
3456 | break; |
3457 | default: |
3458 | CRASH_NO_CASE; |
3459 | } |
3460 | int kind{interface.result.kindCode == KindCode::doublePrecision |
3461 | ? defaults.doublePrecisionKind() |
3462 | : interface.result.kindCode == KindCode::quadPrecision |
3463 | ? defaults.quadPrecisionKind() |
3464 | : defaults.GetDefaultKind(category)}; |
3465 | return DynamicType{category, kind}; |
3466 | } |
3467 | |
3468 | // Probe the configured intrinsic procedure pattern tables in search of a |
3469 | // match for a given procedure reference. |
3470 | std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe( |
3471 | const CallCharacteristics &call, ActualArguments &arguments, |
3472 | FoldingContext &context) const { |
3473 | |
3474 | // All special cases handled here before the table probes below must |
3475 | // also be recognized as special names in IsIntrinsicSubroutine(). |
3476 | if (call.isSubroutineCall) { |
3477 | if (call.name == "__builtin_c_f_pointer") { |
3478 | return HandleC_F_Pointer(arguments, context); |
3479 | } else if (call.name == "random_seed") { |
3480 | int optionalCount{0}; |
3481 | for (const auto &arg : arguments) { |
3482 | if (const auto *expr{arg->UnwrapExpr()}) { |
3483 | optionalCount += |
3484 | Fortran::evaluate::MayBePassedAsAbsentOptional(*expr); |
3485 | } |
3486 | } |
3487 | if (arguments.size() - optionalCount > 1) { |
3488 | context.messages().Say( |
3489 | "RANDOM_SEED must have either 1 or no arguments"_err_en_US); |
3490 | } |
3491 | } |
3492 | } else { // function |
3493 | if (call.name == "__builtin_c_loc") { |
3494 | return HandleC_Loc(arguments, context); |
3495 | } else if (call.name == "__builtin_c_devloc") { |
3496 | return HandleC_Devloc(arguments, context); |
3497 | } else if (call.name == "null") { |
3498 | return HandleNull(arguments, context); |
3499 | } |
3500 | } |
3501 | |
3502 | if (call.isSubroutineCall) { |
3503 | const std::string &name{ResolveAlias(call.name)}; |
3504 | auto subrRange{subroutines_.equal_range(name)}; |
3505 | for (auto iter{subrRange.first}; iter != subrRange.second; ++iter) { |
3506 | if (auto specificCall{iter->second->Match( |
3507 | call, defaults_, arguments, context, builtinsScope_)}) { |
3508 | ApplySpecificChecks(*specificCall, context); |
3509 | return specificCall; |
3510 | } |
3511 | } |
3512 | if (IsIntrinsicFunction(call.name) && !IsDualIntrinsic(call.name)) { |
3513 | context.messages().Say( |
3514 | "Cannot use intrinsic function '%s' as a subroutine"_err_en_US, |
3515 | call.name); |
3516 | } |
3517 | return std::nullopt; |
3518 | } |
3519 | |
3520 | // Helper to avoid emitting errors before it is sure there is no match |
3521 | parser::Messages localBuffer; |
3522 | parser::Messages *finalBuffer{context.messages().messages()}; |
3523 | parser::ContextualMessages localMessages{ |
3524 | context.messages().at(), finalBuffer ? &localBuffer : nullptr}; |
3525 | FoldingContext localContext{context, localMessages}; |
3526 | auto matchOrBufferMessages{ |
3527 | [&](const IntrinsicInterface &intrinsic, |
3528 | parser::Messages &buffer) -> std::optional<SpecificCall> { |
3529 | if (auto specificCall{intrinsic.Match( |
3530 | call, defaults_, arguments, localContext, builtinsScope_)}) { |
3531 | if (finalBuffer) { |
3532 | finalBuffer->Annex(std::move(localBuffer)); |
3533 | } |
3534 | return specificCall; |
3535 | } else if (buffer.empty()) { |
3536 | buffer.Annex(std::move(localBuffer)); |
3537 | } else { |
3538 | // When there are multiple entries in the table for an |
3539 | // intrinsic that has multiple forms depending on the |
3540 | // presence of DIM=, use messages from a later entry if |
3541 | // the messages from an earlier entry complain about the |
3542 | // DIM= argument and it wasn't specified with a keyword. |
3543 | for (const auto &m : buffer.messages()) { |
3544 | if (m.ToString().find("'dim='") != std::string::npos) { |
3545 | bool hadDimKeyword{false}; |
3546 | for (const auto &a : arguments) { |
3547 | if (a) { |
3548 | if (auto kw{a->keyword()}; kw && kw == "dim") { |
3549 | hadDimKeyword = true; |
3550 | break; |
3551 | } |
3552 | } |
3553 | } |
3554 | if (!hadDimKeyword) { |
3555 | buffer = std::move(localBuffer); |
3556 | } |
3557 | break; |
3558 | } |
3559 | } |
3560 | localBuffer.clear(); |
3561 | } |
3562 | return std::nullopt; |
3563 | }}; |
3564 | |
3565 | // Probe the generic intrinsic function table first; allow for |
3566 | // the use of a legacy alias. |
3567 | parser::Messages genericBuffer; |
3568 | const std::string &name{ResolveAlias(call.name)}; |
3569 | auto genericRange{genericFuncs_.equal_range(name)}; |
3570 | for (auto iter{genericRange.first}; iter != genericRange.second; ++iter) { |
3571 | if (auto specificCall{ |
3572 | matchOrBufferMessages(*iter->second, genericBuffer)}) { |
3573 | ApplySpecificChecks(*specificCall, context); |
3574 | return specificCall; |
3575 | } |
3576 | } |
3577 | |
3578 | // Probe the specific intrinsic function table next. |
3579 | parser::Messages specificBuffer; |
3580 | auto specificRange{specificFuncs_.equal_range(call.name)}; |
3581 | for (auto specIter{specificRange.first}; specIter != specificRange.second; |
3582 | ++specIter) { |
3583 | // We only need to check the cases with distinct generic names. |
3584 | if (const char *genericName{specIter->second->generic}) { |
3585 | if (auto specificCall{ |
3586 | matchOrBufferMessages(*specIter->second, specificBuffer)}) { |
3587 | if (!specIter->second->useGenericAndForceResultType) { |
3588 | specificCall->specificIntrinsic.name = genericName; |
3589 | } |
3590 | specificCall->specificIntrinsic.isRestrictedSpecific = |
3591 | specIter->second->isRestrictedSpecific; |
3592 | // TODO test feature AdditionalIntrinsics, warn on nonstandard |
3593 | // specifics with DoublePrecisionComplex arguments. |
3594 | return specificCall; |
3595 | } |
3596 | } |
3597 | } |
3598 | |
3599 | // If there was no exact match with a specific, try to match the related |
3600 | // generic and convert the result to the specific required type. |
3601 | if (context.languageFeatures().IsEnabled(common::LanguageFeature:: |
3602 | UseGenericIntrinsicWhenSpecificDoesntMatch)) { |
3603 | for (auto specIter{specificRange.first}; specIter != specificRange.second; |
3604 | ++specIter) { |
3605 | // We only need to check the cases with distinct generic names. |
3606 | if (const char *genericName{specIter->second->generic}) { |
3607 | if (specIter->second->useGenericAndForceResultType) { |
3608 | auto genericRange{genericFuncs_.equal_range(genericName)}; |
3609 | for (auto genIter{genericRange.first}; genIter != genericRange.second; |
3610 | ++genIter) { |
3611 | if (auto specificCall{ |
3612 | matchOrBufferMessages(*genIter->second, specificBuffer)}) { |
3613 | // Force the call result type to the specific intrinsic result |
3614 | // type, if possible. |
3615 | DynamicType genericType{ |
3616 | DEREF(specificCall->specificIntrinsic.characteristics.value() |
3617 | .functionResult.value() |
3618 | .GetTypeAndShape()) |
3619 | .type()}; |
3620 | DynamicType newType{GetReturnType(*specIter->second, defaults_)}; |
3621 | if (genericType.category() == newType.category() || |
3622 | ((genericType.category() == TypeCategory::Integer || |
3623 | genericType.category() == TypeCategory::Real) && |
3624 | (newType.category() == TypeCategory::Integer || |
3625 | newType.category() == TypeCategory::Real))) { |
3626 | if (context.languageFeatures().ShouldWarn( |
3627 | common::LanguageFeature:: |
3628 | UseGenericIntrinsicWhenSpecificDoesntMatch)) { |
3629 | context.messages().Say( |
3630 | common::LanguageFeature:: |
3631 | UseGenericIntrinsicWhenSpecificDoesntMatch, |
3632 | "Argument types do not match specific intrinsic '%s' requirements; using '%s' generic instead and converting the result to %s if needed"_port_en_US, |
3633 | call.name, genericName, newType.AsFortran()); |
3634 | } |
3635 | specificCall->specificIntrinsic.name = call.name; |
3636 | specificCall->specificIntrinsic.characteristics.value() |
3637 | .functionResult.value() |
3638 | .SetType(newType); |
3639 | return specificCall; |
3640 | } |
3641 | } |
3642 | } |
3643 | } |
3644 | } |
3645 | } |
3646 | } |
3647 | |
3648 | if (specificBuffer.empty() && genericBuffer.empty() && |
3649 | IsIntrinsicSubroutine(call.name) && !IsDualIntrinsic(call.name)) { |
3650 | context.messages().Say( |
3651 | "Cannot use intrinsic subroutine '%s' as a function"_err_en_US, |
3652 | call.name); |
3653 | } |
3654 | |
3655 | // No match; report the right errors, if any |
3656 | if (finalBuffer) { |
3657 | if (specificBuffer.empty()) { |
3658 | finalBuffer->Annex(std::move(genericBuffer)); |
3659 | } else { |
3660 | finalBuffer->Annex(std::move(specificBuffer)); |
3661 | } |
3662 | } |
3663 | return std::nullopt; |
3664 | } |
3665 | |
3666 | std::optional<SpecificIntrinsicFunctionInterface> |
3667 | IntrinsicProcTable::Implementation::IsSpecificIntrinsicFunction( |
3668 | const std::string &name) const { |
3669 | auto specificRange{specificFuncs_.equal_range(name)}; |
3670 | for (auto iter{specificRange.first}; iter != specificRange.second; ++iter) { |
3671 | const SpecificIntrinsicInterface &specific{*iter->second}; |
3672 | std::string genericName{name}; |
3673 | if (specific.generic) { |
3674 | genericName = std::string(specific.generic); |
3675 | } |
3676 | characteristics::FunctionResult fResult{GetSpecificType(specific.result)}; |
3677 | characteristics::DummyArguments args; |
3678 | int dummies{specific.CountArguments()}; |
3679 | for (int j{0}; j < dummies; ++j) { |
3680 | characteristics::DummyDataObject dummy{ |
3681 | GetSpecificType(specific.dummy[j].typePattern)}; |
3682 | dummy.intent = specific.dummy[j].intent; |
3683 | args.emplace_back( |
3684 | std::string{specific.dummy[j].keyword}, std::move(dummy)); |
3685 | } |
3686 | characteristics::Procedure::Attrs attrs; |
3687 | attrs.set(characteristics::Procedure::Attr::Pure) |
3688 | .set(characteristics::Procedure::Attr::Elemental); |
3689 | characteristics::Procedure chars{ |
3690 | std::move(fResult), std::move(args), attrs}; |
3691 | return SpecificIntrinsicFunctionInterface{ |
3692 | std::move(chars), genericName, specific.isRestrictedSpecific}; |
3693 | } |
3694 | return std::nullopt; |
3695 | } |
3696 | |
3697 | DynamicType IntrinsicProcTable::Implementation::GetSpecificType( |
3698 | const TypePattern &pattern) const { |
3699 | const CategorySet &set{pattern.categorySet}; |
3700 | CHECK(set.count() == 1); |
3701 | TypeCategory category{set.LeastElement().value()}; |
3702 | if (pattern.kindCode == KindCode::doublePrecision) { |
3703 | return DynamicType{category, defaults_.doublePrecisionKind()}; |
3704 | } else if (pattern.kindCode == KindCode::quadPrecision) { |
3705 | return DynamicType{category, defaults_.quadPrecisionKind()}; |
3706 | } else if (category == TypeCategory::Character) { |
3707 | // All character arguments to specific intrinsic functions are |
3708 | // assumed-length. |
3709 | return DynamicType{defaults_.GetDefaultKind(category), assumedLen_}; |
3710 | } else { |
3711 | return DynamicType{category, defaults_.GetDefaultKind(category)}; |
3712 | } |
3713 | } |
3714 | |
3715 | IntrinsicProcTable::~IntrinsicProcTable() = default; |
3716 | |
3717 | IntrinsicProcTable IntrinsicProcTable::Configure( |
3718 | const common::IntrinsicTypeDefaultKinds &defaults) { |
3719 | IntrinsicProcTable result; |
3720 | result.impl_ = std::make_unique<IntrinsicProcTable::Implementation>(defaults); |
3721 | return result; |
3722 | } |
3723 | |
3724 | void IntrinsicProcTable::SupplyBuiltins( |
3725 | const semantics::Scope &builtins) const { |
3726 | DEREF(impl_.get()).SupplyBuiltins(builtins); |
3727 | } |
3728 | |
3729 | bool IntrinsicProcTable::IsIntrinsic(const std::string &name) const { |
3730 | return DEREF(impl_.get()).IsIntrinsic(name); |
3731 | } |
3732 | bool IntrinsicProcTable::IsIntrinsicFunction(const std::string &name) const { |
3733 | return DEREF(impl_.get()).IsIntrinsicFunction(name); |
3734 | } |
3735 | bool IntrinsicProcTable::IsIntrinsicSubroutine(const std::string &name) const { |
3736 | return DEREF(impl_.get()).IsIntrinsicSubroutine(name); |
3737 | } |
3738 | |
3739 | IntrinsicClass IntrinsicProcTable::GetIntrinsicClass( |
3740 | const std::string &name) const { |
3741 | return DEREF(impl_.get()).GetIntrinsicClass(name); |
3742 | } |
3743 | |
3744 | std::string IntrinsicProcTable::GetGenericIntrinsicName( |
3745 | const std::string &name) const { |
3746 | return DEREF(impl_.get()).GetGenericIntrinsicName(name); |
3747 | } |
3748 | |
3749 | std::optional<SpecificCall> IntrinsicProcTable::Probe( |
3750 | const CallCharacteristics &call, ActualArguments &arguments, |
3751 | FoldingContext &context) const { |
3752 | return DEREF(impl_.get()).Probe(call, arguments, context); |
3753 | } |
3754 | |
3755 | std::optional<SpecificIntrinsicFunctionInterface> |
3756 | IntrinsicProcTable::IsSpecificIntrinsicFunction(const std::string &name) const { |
3757 | return DEREF(impl_.get()).IsSpecificIntrinsicFunction(name); |
3758 | } |
3759 | |
3760 | llvm::raw_ostream &TypePattern::Dump(llvm::raw_ostream &o) const { |
3761 | if (categorySet == AnyType) { |
3762 | o << "any type"; |
3763 | } else { |
3764 | const char *sep = ""; |
3765 | auto set{categorySet}; |
3766 | while (auto least{set.LeastElement()}) { |
3767 | o << sep << EnumToString(*least); |
3768 | sep = " or "; |
3769 | set.reset(*least); |
3770 | } |
3771 | } |
3772 | o << '(' << EnumToString(kindCode) << ')'; |
3773 | return o; |
3774 | } |
3775 | |
3776 | llvm::raw_ostream &IntrinsicDummyArgument::Dump(llvm::raw_ostream &o) const { |
3777 | if (keyword) { |
3778 | o << keyword << '='; |
3779 | } |
3780 | return typePattern.Dump(o) |
3781 | << ' ' << EnumToString(rank) << ' ' << EnumToString(optionality) |
3782 | << EnumToString(intent); |
3783 | } |
3784 | |
3785 | llvm::raw_ostream &IntrinsicInterface::Dump(llvm::raw_ostream &o) const { |
3786 | o << name; |
3787 | char sep{'('}; |
3788 | for (const auto &d : dummy) { |
3789 | if (d.typePattern.kindCode == KindCode::none) { |
3790 | break; |
3791 | } |
3792 | d.Dump(o << sep); |
3793 | sep = ','; |
3794 | } |
3795 | if (sep == '(') { |
3796 | o << "()"; |
3797 | } |
3798 | return result.Dump(o << " -> ") << ' ' << EnumToString(rank); |
3799 | } |
3800 | |
3801 | llvm::raw_ostream &IntrinsicProcTable::Implementation::Dump( |
3802 | llvm::raw_ostream &o) const { |
3803 | o << "generic intrinsic functions:\n"; |
3804 | for (const auto &iter : genericFuncs_) { |
3805 | iter.second->Dump(o << iter.first << ": ") << '\n'; |
3806 | } |
3807 | o << "specific intrinsic functions:\n"; |
3808 | for (const auto &iter : specificFuncs_) { |
3809 | iter.second->Dump(o << iter.first << ": "); |
3810 | if (const char *g{iter.second->generic}) { |
3811 | o << " -> "<< g; |
3812 | } |
3813 | o << '\n'; |
3814 | } |
3815 | o << "subroutines:\n"; |
3816 | for (const auto &iter : subroutines_) { |
3817 | iter.second->Dump(o << iter.first << ": ") << '\n'; |
3818 | } |
3819 | return o; |
3820 | } |
3821 | |
3822 | llvm::raw_ostream &IntrinsicProcTable::Dump(llvm::raw_ostream &o) const { |
3823 | return DEREF(impl_.get()).Dump(o); |
3824 | } |
3825 | |
3826 | // In general C846 prohibits allocatable coarrays to be passed to INTENT(OUT) |
3827 | // dummy arguments. This rule does not apply to intrinsics in general. |
3828 | // Some intrinsic explicitly allow coarray allocatable in their description. |
3829 | // It is assumed that unless explicitly allowed for an intrinsic, |
3830 | // this is forbidden. |
3831 | // Since there are very few intrinsic identified that allow this, they are |
3832 | // listed here instead of adding a field in the table. |
3833 | bool AcceptsIntentOutAllocatableCoarray(const std::string &intrinsic) { |
3834 | return intrinsic == "move_alloc"; |
3835 | } |
3836 | } // namespace Fortran::evaluate |
3837 |
Definitions
- IntType
- UnsignedType
- RealType
- ComplexType
- CharType
- LogicalType
- IntOrUnsignedType
- IntOrRealType
- IntUnsignedOrRealType
- IntOrRealOrCharType
- IntOrLogicalType
- FloatingType
- NumericType
- RelatableType
- DerivedType
- IntrinsicType
- AnyType
- ENUM_CLASS
- TypePattern
- DefaultInt
- DefaultReal
- DefaultComplex
- DefaultChar
- DefaultLogical
- BOZ
- EventType
- IeeeFlagType
- IeeeRoundType
- TeamType
- DoublePrecision
- DoublePrecisionComplex
- QuadPrecision
- SubscriptInt
- AnyInt
- AnyIntOrUnsigned
- AnyReal
- AnyIntOrReal
- AnyIntUnsignedOrReal
- AnyIntOrRealOrChar
- AnyIntOrLogical
- AnyComplex
- AnyFloating
- AnyNumeric
- AnyChar
- AnyLogical
- AnyRelatable
- AnyIntrinsic
- ExtensibleDerived
- AnyData
- Addressable
- SameInt
- SameIntOrUnsigned
- SameReal
- SameIntOrReal
- SameIntUnsignedOrReal
- SameComplex
- SameFloating
- SameNumeric
- SameChar
- SameCharNoLen
- SameLogical
- SameRelatable
- SameIntrinsic
- SameType
- OperandInt
- OperandReal
- OperandIntOrReal
- OperandUnsigned
- AnyPointer
- ResultLogical
- ResultNumeric
- KINDInt
- KINDUnsigned
- KINDReal
- KINDComplex
- KINDChar
- KINDLogical
- AtomicInt
- AtomicIntOrLogical
- SameAtom
- ENUM_CLASS
- DefaultingKIND
- MatchingDefaultKIND
- SizeDefaultKIND
- RequiredDIM
- OptionalDIM
- MissingDIM
- OptionalMASK
- OptionalTEAM
- IntrinsicInterface
- maxArguments
- CountArguments
- genericIntrinsicFunction
- genericAlias
- SpecificIntrinsicInterface
- specificIntrinsicFunction
- intrinsicSubroutine
- GetBuiltinDerivedType
- GetBuiltinKind
- CheckMaxMinArgument
- CheckAndPushMinMaxArgument
- CheckAtomicKind
- Match
- CheckAndRearrangeArguments
- CheckForNonPositiveValues
- CheckAtomicDefineAndRef
- ApplySpecificChecks
- GetReturnType
- Dump
- Dump
Improve your Profiling and Debugging skills
Find out more