| 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 {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 | |