blob: 64ec5713ac5831c4adaca7b71b322a6a682b043b [file] [log] [blame]
peter klausler67f13ef2019-01-07 18:55:091// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
peter klausler42b33da2018-09-29 00:02:112//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "intrinsics.h"
peter klausler146e13c2019-04-18 21:11:1516#include "common.h"
peter klauslera62636f2018-10-08 22:35:1917#include "expression.h"
peter klauslerfe3acf5f2019-01-07 18:15:2718#include "fold.h"
peter klauslerb65572d2019-04-03 23:04:1319#include "shape.h"
peter klauslerabac2282018-10-26 22:10:2420#include "tools.h"
peter klausler42b33da2018-09-29 00:02:1121#include "type.h"
peter klauslerab74d1a2019-02-28 18:48:4122#include "../common/Fortran.h"
peter klausler42b33da2018-09-29 00:02:1123#include "../common/enum-set.h"
peter klauslera70f5962018-10-04 20:43:3324#include "../common/idioms.h"
peter klausler84ea49d2018-10-18 17:50:5525#include <algorithm>
peter klauslera70f5962018-10-04 20:43:3326#include <map>
peter klausler7bda1b32018-10-12 23:01:5527#include <ostream>
28#include <sstream>
peter klauslera70f5962018-10-04 20:43:3329#include <string>
30#include <utility>
peter klausler42b33da2018-09-29 00:02:1131
peter klauslercb308d32018-10-05 18:32:5432using namespace Fortran::parser::literals;
33
peter klausler42b33da2018-09-29 00:02:1134namespace Fortran::evaluate {
35
peter klausler146e13c2019-04-18 21:11:1536class FoldingContext;
peter klausler42b33da2018-09-29 00:02:1137
peter klauslera70f5962018-10-04 20:43:3338// This file defines the supported intrinsic procedures and implements
39// their recognition and validation. It is largely table-driven. See
40// documentation/intrinsics.md and section 16 of the Fortran 2018 standard
41// for full details on each of the intrinsics. Be advised, they have
42// complicated details, and the design of these tables has to accommodate
43// that complexity.
44
peter klausler42b33da2018-09-29 00:02:1145// Dummy arguments to generic intrinsic procedures are each specified by
peter klauslera70f5962018-10-04 20:43:3346// their keyword name (rarely used, but always defined), allowable type
peter klauslercb308d32018-10-05 18:32:5447// categories, a kind pattern, a rank pattern, and information about
48// optionality and defaults. The kind and rank patterns are represented
49// here with code values that are significant to the matching/validation engine.
peter klausler42b33da2018-09-29 00:02:1150
peter klauslera70f5962018-10-04 20:43:3351// These are small bit-sets of type category enumerators.
52// Note that typeless (BOZ literal) values don't have a distinct type category.
53// These typeless arguments are represented in the tables as if they were
54// INTEGER with a special "typeless" kind code. Arguments of intrinsic types
peter klausler25e6f032019-05-03 18:29:1555// that can also be typeless values are encoded with an "elementalOrBOZ"
peter klauslercb308d32018-10-05 18:32:5456// rank pattern.
peter klausler146e13c2019-04-18 21:11:1557// Assumed-type (TYPE(*)) dummy arguments can be forwarded along to some
58// intrinsic functions that accept AnyType + Rank::anyOrAssumedRank.
peter klauslera70f5962018-10-04 20:43:3359using CategorySet = common::EnumSet<TypeCategory, 8>;
peter klausler51b09b62018-10-15 19:17:3060static constexpr CategorySet IntType{TypeCategory::Integer};
61static constexpr CategorySet RealType{TypeCategory::Real};
62static constexpr CategorySet ComplexType{TypeCategory::Complex};
63static constexpr CategorySet CharType{TypeCategory::Character};
64static constexpr CategorySet LogicalType{TypeCategory::Logical};
65static constexpr CategorySet IntOrRealType{IntType | RealType};
66static constexpr CategorySet FloatingType{RealType | ComplexType};
67static constexpr CategorySet NumericType{IntType | RealType | ComplexType};
68static constexpr CategorySet RelatableType{IntType | RealType | CharType};
peter klauslera70f5962018-10-04 20:43:3369static constexpr CategorySet IntrinsicType{
peter klausler51b09b62018-10-15 19:17:3070 IntType | RealType | ComplexType | CharType | LogicalType};
peter klauslera70f5962018-10-04 20:43:3371static constexpr CategorySet AnyType{
72 IntrinsicType | CategorySet{TypeCategory::Derived}};
peter klausler42b33da2018-09-29 00:02:1173
peter klausler7bda1b32018-10-12 23:01:5574ENUM_CLASS(KindCode, none, defaultIntegerKind,
75 defaultRealKind, // is also the default COMPLEX kind
76 doublePrecision, defaultCharKind, defaultLogicalKind,
77 any, // matches any kind value; each instance is independent
peter klausler146e13c2019-04-18 21:11:1578 same, // match any kind, but all "same" kinds must be equal
peter klausler7bda1b32018-10-12 23:01:5579 typeless, // BOZ literals are INTEGER with this kind
80 teamType, // TEAM_TYPE from module ISO_FORTRAN_ENV (for coarrays)
81 kindArg, // this argument is KIND=
82 effectiveKind, // for function results: same "kindArg", possibly defaulted
83 dimArg, // this argument is DIM=
peter klausler7bda1b32018-10-12 23:01:5584 likeMultiply, // for DOT_PRODUCT and MATMUL
peter klausler8e932262019-07-01 20:22:2285 subscript, // address-sized integer
peter klausler7bda1b32018-10-12 23:01:5586)
peter klausler42b33da2018-09-29 00:02:1187
88struct TypePattern {
89 CategorySet categorySet;
peter klauslerb22d4942018-10-01 18:27:4590 KindCode kindCode{KindCode::none};
peter klausler7bda1b32018-10-12 23:01:5591 std::ostream &Dump(std::ostream &) const;
peter klausler42b33da2018-09-29 00:02:1192};
93
peter klauslera70f5962018-10-04 20:43:3394// Abbreviations for argument and result patterns in the intrinsic prototypes:
95
96// Match specific kinds of intrinsic types
peter klausler7c402d92018-10-16 21:42:2297static constexpr TypePattern DefaultInt{IntType, KindCode::defaultIntegerKind};
98static constexpr TypePattern DefaultReal{RealType, KindCode::defaultRealKind};
99static constexpr TypePattern DefaultComplex{
100 ComplexType, KindCode::defaultRealKind};
101static constexpr TypePattern DefaultChar{CharType, KindCode::defaultCharKind};
102static constexpr TypePattern DefaultLogical{
peter klausler51b09b62018-10-15 19:17:30103 LogicalType, KindCode::defaultLogicalKind};
104static constexpr TypePattern BOZ{IntType, KindCode::typeless};
105static constexpr TypePattern TEAM_TYPE{IntType, KindCode::teamType};
106static constexpr TypePattern DoublePrecision{
107 RealType, KindCode::doublePrecision};
peter klauslera0e50522019-06-21 21:04:40108static constexpr TypePattern DoublePrecisionComplex{
109 ComplexType, KindCode::doublePrecision};
peter klausler8e932262019-07-01 20:22:22110static constexpr TypePattern SubscriptInt{IntType, KindCode::subscript};
peter klauslera70f5962018-10-04 20:43:33111
112// Match any kind of some intrinsic or derived types
peter klausler51b09b62018-10-15 19:17:30113static constexpr TypePattern AnyInt{IntType, KindCode::any};
114static constexpr TypePattern AnyReal{RealType, KindCode::any};
115static constexpr TypePattern AnyIntOrReal{IntOrRealType, KindCode::any};
116static constexpr TypePattern AnyComplex{ComplexType, KindCode::any};
peter klauslerf4b12092019-05-29 22:38:33117static constexpr TypePattern AnyFloating{FloatingType, KindCode::any};
peter klausler51b09b62018-10-15 19:17:30118static constexpr TypePattern AnyNumeric{NumericType, KindCode::any};
119static constexpr TypePattern AnyChar{CharType, KindCode::any};
120static constexpr TypePattern AnyLogical{LogicalType, KindCode::any};
121static constexpr TypePattern AnyRelatable{RelatableType, KindCode::any};
peter klauslerbe3b7652018-12-04 18:55:32122static constexpr TypePattern AnyIntrinsic{IntrinsicType, KindCode::any};
peter klauslerf7f2a732018-10-09 19:07:29123static constexpr TypePattern Anything{AnyType, KindCode::any};
peter klauslera70f5962018-10-04 20:43:33124
125// Match some kind of some intrinsic type(s); all "Same" values must match,
126// even when not in the same category (e.g., SameComplex and SameReal).
127// Can be used to specify a result so long as at least one argument is
128// a "Same".
peter klausler51b09b62018-10-15 19:17:30129static constexpr TypePattern SameInt{IntType, KindCode::same};
130static constexpr TypePattern SameReal{RealType, KindCode::same};
131static constexpr TypePattern SameIntOrReal{IntOrRealType, KindCode::same};
132static constexpr TypePattern SameComplex{ComplexType, KindCode::same};
133static constexpr TypePattern SameFloating{FloatingType, KindCode::same};
134static constexpr TypePattern SameNumeric{NumericType, KindCode::same};
135static constexpr TypePattern SameChar{CharType, KindCode::same};
136static constexpr TypePattern SameLogical{LogicalType, KindCode::same};
137static constexpr TypePattern SameRelatable{RelatableType, KindCode::same};
peter klauslera70f5962018-10-04 20:43:33138static constexpr TypePattern SameIntrinsic{IntrinsicType, KindCode::same};
139static constexpr TypePattern SameDerivedType{
140 CategorySet{TypeCategory::Derived}, KindCode::same};
141static constexpr TypePattern SameType{AnyType, KindCode::same};
142
peter klauslerf7f2a732018-10-09 19:07:29143// For DOT_PRODUCT and MATMUL, the result type depends on the arguments
peter klausler51b09b62018-10-15 19:17:30144static constexpr TypePattern ResultLogical{LogicalType, KindCode::likeMultiply};
145static constexpr TypePattern ResultNumeric{NumericType, KindCode::likeMultiply};
peter klauslerf7f2a732018-10-09 19:07:29146
peter klauslera70f5962018-10-04 20:43:33147// Result types with known category and KIND=
peter klausler51b09b62018-10-15 19:17:30148static constexpr TypePattern KINDInt{IntType, KindCode::effectiveKind};
149static constexpr TypePattern KINDReal{RealType, KindCode::effectiveKind};
150static constexpr TypePattern KINDComplex{ComplexType, KindCode::effectiveKind};
151static constexpr TypePattern KINDChar{CharType, KindCode::effectiveKind};
152static constexpr TypePattern KINDLogical{LogicalType, KindCode::effectiveKind};
peter klausler42b33da2018-09-29 00:02:11153
154// The default rank pattern for dummy arguments and function results is
155// "elemental".
peter klausler7bda1b32018-10-12 23:01:55156ENUM_CLASS(Rank,
157 elemental, // scalar, or array that conforms with other array arguments
158 elementalOrBOZ, // elemental, or typeless BOZ literal scalar
159 scalar, vector,
160 shape, // INTEGER vector of known length and no negative element
161 matrix,
162 array, // not scalar, rank is known and greater than zero
163 known, // rank is known and can be scalar
peter klausler146e13c2019-04-18 21:11:15164 anyOrAssumedRank, // rank can be unknown; assumed-type TYPE(*) allowed
peter klausler7bda1b32018-10-12 23:01:55165 conformable, // scalar, or array of same rank & shape as "array" argument
166 reduceOperation, // a pure function with constraints for REDUCE
167 dimReduced, // scalar if no DIM= argument, else rank(array)-1
168 dimRemoved, // scalar, or rank(array)-1
169 rankPlus1, // rank(known)+1
170 shaped, // rank is length of SHAPE vector
171)
peter klausler42b33da2018-09-29 00:02:11172
peter klausler7bda1b32018-10-12 23:01:55173ENUM_CLASS(Optionality, required, optional,
174 defaultsToSameKind, // for MatchingDefaultKIND
175 defaultsToDefaultForResult, // for DefaultingKIND
peter klausler7c402d92018-10-16 21:42:22176 defaultsToSubscriptKind, // for SubscriptDefaultKIND
peter klausler7bda1b32018-10-12 23:01:55177 repeats, // for MAX/MIN and their several variants
178)
peter klausler42b33da2018-09-29 00:02:11179
180struct IntrinsicDummyArgument {
peter klauslerb22d4942018-10-01 18:27:45181 const char *keyword{nullptr};
peter klausler42b33da2018-09-29 00:02:11182 TypePattern typePattern;
peter klauslera70f5962018-10-04 20:43:33183 Rank rank{Rank::elemental};
peter klauslercb308d32018-10-05 18:32:54184 Optionality optionality{Optionality::required};
peter klausler7bda1b32018-10-12 23:01:55185 std::ostream &Dump(std::ostream &) const;
peter klausler42b33da2018-09-29 00:02:11186};
187
peter klauslera70f5962018-10-04 20:43:33188// constexpr abbreviations for popular arguments:
189// DefaultingKIND is a KIND= argument whose default value is the appropriate
190// KIND(0), KIND(0.0), KIND(''), &c. value for the function result.
peter klauslercb308d32018-10-05 18:32:54191static constexpr IntrinsicDummyArgument DefaultingKIND{"kind",
peter klausler51b09b62018-10-15 19:17:30192 {IntType, KindCode::kindArg}, Rank::scalar,
peter klauslercb308d32018-10-05 18:32:54193 Optionality::defaultsToDefaultForResult};
peter klauslera70f5962018-10-04 20:43:33194// MatchingDefaultKIND is a KIND= argument whose default value is the
195// kind of any "Same" function argument (viz., the one whose kind pattern is
196// "same").
peter klauslercb308d32018-10-05 18:32:54197static constexpr IntrinsicDummyArgument MatchingDefaultKIND{"kind",
peter klausler51b09b62018-10-15 19:17:30198 {IntType, KindCode::kindArg}, Rank::scalar,
199 Optionality::defaultsToSameKind};
peter klausler7c402d92018-10-16 21:42:22200// SubscriptDefaultKind is a KIND= argument whose default value is
201// the kind of INTEGER used for address calculations.
202static constexpr IntrinsicDummyArgument SubscriptDefaultKIND{"kind",
203 {IntType, KindCode::kindArg}, Rank::scalar,
204 Optionality::defaultsToSubscriptKind};
peter klausler00e128e2019-06-25 20:07:32205static constexpr IntrinsicDummyArgument RequiredDIM{
peter klausler28c03d32019-06-27 16:57:48206 "dim", {IntType, KindCode::dimArg}, Rank::scalar, Optionality::required};
peter klauslera70f5962018-10-04 20:43:33207static constexpr IntrinsicDummyArgument OptionalDIM{
peter klausler51b09b62018-10-15 19:17:30208 "dim", {IntType, KindCode::dimArg}, Rank::scalar, Optionality::optional};
peter klauslera70f5962018-10-04 20:43:33209static constexpr IntrinsicDummyArgument OptionalMASK{
peter klauslercb308d32018-10-05 18:32:54210 "mask", AnyLogical, Rank::conformable, Optionality::optional};
peter klausler42b33da2018-09-29 00:02:11211
212struct IntrinsicInterface {
peter klausler84ea49d2018-10-18 17:50:55213 static constexpr int maxArguments{7}; // if not a MAX/MIN(...)
peter klauslerb22d4942018-10-01 18:27:45214 const char *name{nullptr};
peter klausler42b33da2018-09-29 00:02:11215 IntrinsicDummyArgument dummy[maxArguments];
216 TypePattern result;
peter klauslera70f5962018-10-04 20:43:33217 Rank rank{Rank::elemental};
peter klausleref9dd9d2018-10-17 22:09:48218 std::optional<SpecificCall> Match(const CallCharacteristics &,
peter klauslerf9d6c0a2019-01-18 20:40:47219 const common::IntrinsicTypeDefaultKinds &, ActualArguments &,
peter klausler146e13c2019-04-18 21:11:15220 FoldingContext &context) const;
peter klauslerba56b912019-02-22 23:45:30221 int CountArguments() const;
peter klausler7bda1b32018-10-12 23:01:55222 std::ostream &Dump(std::ostream &) const;
peter klausler42b33da2018-09-29 00:02:11223};
224
peter klauslerba56b912019-02-22 23:45:30225int IntrinsicInterface::CountArguments() const {
226 int n{0};
227 while (n < maxArguments && dummy[n].keyword != nullptr) {
228 ++n;
229 }
230 return n;
231}
232
peter klausler94041d72018-10-15 20:39:51233// GENERIC INTRINSIC FUNCTION INTERFACES
234// Each entry in this table defines a pattern. Some intrinsic
235// functions have more than one such pattern. Besides the name
236// of the intrinsic function, each pattern has specifications for
237// the dummy arguments and for the result of the function.
peter klausler59342b02019-05-13 16:33:18238// The dummy argument patterns each have a name (these are from the
peter klausler94041d72018-10-15 20:39:51239// standard, but rarely appear in actual code), a type and kind
240// pattern, allowable ranks, and optionality indicators.
241// Be advised, the default rank pattern is "elemental".
peter klauslerb22d4942018-10-01 18:27:45242static const IntrinsicInterface genericIntrinsicFunction[]{
peter klauslera70f5962018-10-04 20:43:33243 {"abs", {{"a", SameIntOrReal}}, SameIntOrReal},
244 {"abs", {{"a", SameComplex}}, SameReal},
peter klauslerad9aede2018-10-11 21:51:14245 {"achar", {{"i", AnyInt}, DefaultingKIND}, KINDChar},
peter klauslera70f5962018-10-04 20:43:33246 {"acos", {{"x", SameFloating}}, SameFloating},
247 {"acosh", {{"x", SameFloating}}, SameFloating},
248 {"adjustl", {{"string", SameChar}}, SameChar},
249 {"adjustr", {{"string", SameChar}}, SameChar},
250 {"aimag", {{"x", SameComplex}}, SameReal},
251 {"aint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
252 {"all", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
253 Rank::dimReduced},
peter klausler4f2c8fa2019-06-19 18:50:07254 {"allocated", {{"array", Anything, Rank::array}}, DefaultLogical},
255 {"allocated", {{"scalar", Anything, Rank::scalar}}, DefaultLogical},
peter klauslera70f5962018-10-04 20:43:33256 {"anint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
257 {"any", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
258 Rank::dimReduced},
259 {"asin", {{"x", SameFloating}}, SameFloating},
260 {"asinh", {{"x", SameFloating}}, SameFloating},
peter klauslera0e50522019-06-21 21:04:40261 {"associated",
262 {{"pointer", Anything, Rank::known},
263 {"target", Anything, Rank::known, Optionality::optional}},
264 DefaultLogical},
peter klauslera70f5962018-10-04 20:43:33265 {"atan", {{"x", SameFloating}}, SameFloating},
266 {"atan", {{"y", SameReal}, {"x", SameReal}}, SameReal},
267 {"atan2", {{"y", SameReal}, {"x", SameReal}}, SameReal},
268 {"atanh", {{"x", SameFloating}}, SameFloating},
269 {"bessel_j0", {{"x", SameReal}}, SameReal},
270 {"bessel_j1", {{"x", SameReal}}, SameReal},
271 {"bessel_jn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
peter klauslerf7f2a732018-10-09 19:07:29272 {"bessel_jn",
273 {{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
274 {"x", SameReal, Rank::scalar}},
275 SameReal, Rank::vector},
peter klauslera70f5962018-10-04 20:43:33276 {"bessel_y0", {{"x", SameReal}}, SameReal},
277 {"bessel_y1", {{"x", SameReal}}, SameReal},
278 {"bessel_yn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
peter klauslerf7f2a732018-10-09 19:07:29279 {"bessel_yn",
280 {{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
281 {"x", SameReal, Rank::scalar}},
282 SameReal, Rank::vector},
peter klauslera70f5962018-10-04 20:43:33283 {"bge",
peter klauslercb308d32018-10-05 18:32:54284 {{"i", AnyInt, Rank::elementalOrBOZ},
285 {"j", AnyInt, Rank::elementalOrBOZ}},
peter klausler7c402d92018-10-16 21:42:22286 DefaultLogical},
peter klauslera70f5962018-10-04 20:43:33287 {"bgt",
peter klauslercb308d32018-10-05 18:32:54288 {{"i", AnyInt, Rank::elementalOrBOZ},
289 {"j", AnyInt, Rank::elementalOrBOZ}},
peter klausler7c402d92018-10-16 21:42:22290 DefaultLogical},
peter klauslera70f5962018-10-04 20:43:33291 {"ble",
peter klauslercb308d32018-10-05 18:32:54292 {{"i", AnyInt, Rank::elementalOrBOZ},
293 {"j", AnyInt, Rank::elementalOrBOZ}},
peter klausler7c402d92018-10-16 21:42:22294 DefaultLogical},
peter klauslera70f5962018-10-04 20:43:33295 {"blt",
peter klauslercb308d32018-10-05 18:32:54296 {{"i", AnyInt, Rank::elementalOrBOZ},
297 {"j", AnyInt, Rank::elementalOrBOZ}},
peter klausler7c402d92018-10-16 21:42:22298 DefaultLogical},
299 {"btest", {{"i", AnyInt}, {"pos", AnyInt}}, DefaultLogical},
peter klauslera70f5962018-10-04 20:43:33300 {"ceiling", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
301 {"char", {{"i", AnyInt}, DefaultingKIND}, KINDChar},
302 {"cmplx", {{"x", AnyComplex}, DefaultingKIND}, KINDComplex},
peter klausler42b33da2018-09-29 00:02:11303 {"cmplx",
peter klausler5774f0a2019-06-04 17:50:34304 {{"x", AnyIntOrReal, Rank::elementalOrBOZ},
305 {"y", AnyIntOrReal, Rank::elementalOrBOZ, Optionality::optional},
peter klausler25e6f032019-05-03 18:29:15306 DefaultingKIND},
peter klauslera70f5962018-10-04 20:43:33307 KINDComplex},
peter klausler7c402d92018-10-16 21:42:22308 {"command_argument_count", {}, DefaultInt, Rank::scalar},
peter klauslera70f5962018-10-04 20:43:33309 {"conjg", {{"z", SameComplex}}, SameComplex},
310 {"cos", {{"x", SameFloating}}, SameFloating},
311 {"cosh", {{"x", SameFloating}}, SameFloating},
312 {"count", {{"mask", AnyLogical, Rank::array}, OptionalDIM, DefaultingKIND},
313 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11314 {"cshift",
peter klauslera70f5962018-10-04 20:43:33315 {{"array", SameType, Rank::array}, {"shift", AnyInt, Rank::dimRemoved},
316 OptionalDIM},
peter klauslerd29530e2019-05-21 23:58:46317 SameType, Rank::conformable},
peter klausleref9dd9d2018-10-17 22:09:48318 {"dble", {{"a", AnyNumeric, Rank::elementalOrBOZ}}, DoublePrecision},
peter klauslera70f5962018-10-04 20:43:33319 {"dim", {{"x", SameIntOrReal}, {"y", SameIntOrReal}}, SameIntOrReal},
peter klauslerf7f2a732018-10-09 19:07:29320 {"dot_product",
321 {{"vector_a", AnyLogical, Rank::vector},
322 {"vector_b", AnyLogical, Rank::vector}},
323 ResultLogical, Rank::scalar},
324 {"dot_product",
325 {{"vector_a", AnyComplex, Rank::vector},
326 {"vector_b", AnyNumeric, Rank::vector}},
327 ResultNumeric, Rank::scalar}, // conjugates vector_a
328 {"dot_product",
329 {{"vector_a", AnyIntOrReal, Rank::vector},
330 {"vector_b", AnyNumeric, Rank::vector}},
331 ResultNumeric, Rank::scalar},
peter klausler7c402d92018-10-16 21:42:22332 {"dprod", {{"x", DefaultReal}, {"y", DefaultReal}}, DoublePrecision},
peter klauslera70f5962018-10-04 20:43:33333 {"dshiftl",
peter klauslercb308d32018-10-05 18:32:54334 {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ},
peter klauslera70f5962018-10-04 20:43:33335 {"shift", AnyInt}},
336 SameInt},
337 {"dshiftl", {{"i", BOZ}, {"j", SameInt}, {"shift", AnyInt}}, SameInt},
338 {"dshiftr",
peter klauslercb308d32018-10-05 18:32:54339 {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ},
peter klauslera70f5962018-10-04 20:43:33340 {"shift", AnyInt}},
341 SameInt},
342 {"dshiftr", {{"i", BOZ}, {"j", SameInt}, {"shift", AnyInt}}, SameInt},
peter klausler42b33da2018-09-29 00:02:11343 {"eoshift",
peter klauslera70f5962018-10-04 20:43:33344 {{"array", SameIntrinsic, Rank::array},
345 {"shift", AnyInt, Rank::dimRemoved},
peter klauslercb308d32018-10-05 18:32:54346 {"boundary", SameIntrinsic, Rank::dimRemoved,
347 Optionality::optional},
peter klauslera70f5962018-10-04 20:43:33348 OptionalDIM},
peter klauslerd29530e2019-05-21 23:58:46349 SameIntrinsic, Rank::conformable},
peter klausler42b33da2018-09-29 00:02:11350 {"eoshift",
peter klauslera70f5962018-10-04 20:43:33351 {{"array", SameDerivedType, Rank::array},
352 {"shift", AnyInt, Rank::dimRemoved},
353 {"boundary", SameDerivedType, Rank::dimRemoved}, OptionalDIM},
peter klauslerd29530e2019-05-21 23:58:46354 SameDerivedType, Rank::conformable},
peter klauslera70f5962018-10-04 20:43:33355 {"erf", {{"x", SameReal}}, SameReal},
356 {"erfc", {{"x", SameReal}}, SameReal},
357 {"erfc_scaled", {{"x", SameReal}}, SameReal},
358 {"exp", {{"x", SameFloating}}, SameFloating},
peter klausler7c402d92018-10-16 21:42:22359 {"exponent", {{"x", AnyReal}}, DefaultInt},
peter klausler42b33da2018-09-29 00:02:11360 {"findloc",
peter klauslerad9aede2018-10-11 21:51:14361 {{"array", AnyNumeric, Rank::array},
peter klausler00e128e2019-06-25 20:07:32362 {"value", AnyNumeric, Rank::scalar}, RequiredDIM, OptionalMASK,
peter klausler7c402d92018-10-16 21:42:22363 SubscriptDefaultKIND,
peter klauslercb308d32018-10-05 18:32:54364 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
peter klausler00e128e2019-06-25 20:07:32365 KINDInt, Rank::dimRemoved},
366 {"findloc",
367 {{"array", AnyNumeric, Rank::array},
368 {"value", AnyNumeric, Rank::scalar}, OptionalMASK,
369 SubscriptDefaultKIND,
370 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
371 KINDInt, Rank::vector},
peter klausler42b33da2018-09-29 00:02:11372 {"findloc",
peter klauslera70f5962018-10-04 20:43:33373 {{"array", SameChar, Rank::array}, {"value", SameChar, Rank::scalar},
peter klausler00e128e2019-06-25 20:07:32374 RequiredDIM, OptionalMASK, SubscriptDefaultKIND,
peter klauslercb308d32018-10-05 18:32:54375 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
peter klausler00e128e2019-06-25 20:07:32376 KINDInt, Rank::dimRemoved},
377 {"findloc",
378 {{"array", SameChar, Rank::array}, {"value", SameChar, Rank::scalar},
379 OptionalMASK, SubscriptDefaultKIND,
380 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
381 KINDInt, Rank::vector},
peter klausler42b33da2018-09-29 00:02:11382 {"findloc",
peter klauslera70f5962018-10-04 20:43:33383 {{"array", AnyLogical, Rank::array},
peter klausler00e128e2019-06-25 20:07:32384 {"value", AnyLogical, Rank::scalar}, RequiredDIM, OptionalMASK,
peter klausler7c402d92018-10-16 21:42:22385 SubscriptDefaultKIND,
peter klauslercb308d32018-10-05 18:32:54386 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
peter klausler00e128e2019-06-25 20:07:32387 KINDInt, Rank::dimRemoved},
388 {"findloc",
389 {{"array", AnyLogical, Rank::array},
390 {"value", AnyLogical, Rank::scalar}, OptionalMASK,
391 SubscriptDefaultKIND,
392 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
393 KINDInt, Rank::vector},
peter klauslera70f5962018-10-04 20:43:33394 {"floor", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
395 {"fraction", {{"x", SameReal}}, SameReal},
396 {"gamma", {{"x", SameReal}}, SameReal},
397 {"hypot", {{"x", SameReal}, {"y", SameReal}}, SameReal},
398 {"iachar", {{"c", AnyChar}, DefaultingKIND}, KINDInt},
399 {"iall", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
400 SameInt, Rank::dimReduced},
401 {"iany", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
402 SameInt, Rank::dimReduced},
403 {"iparity", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
404 SameInt, Rank::dimReduced},
peter klauslercb308d32018-10-05 18:32:54405 {"iand", {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ}}, SameInt},
peter klauslera70f5962018-10-04 20:43:33406 {"iand", {{"i", BOZ}, {"j", SameInt}}, SameInt},
407 {"ibclr", {{"i", SameInt}, {"pos", AnyInt}}, SameInt},
408 {"ibits", {{"i", SameInt}, {"pos", AnyInt}, {"len", AnyInt}}, SameInt},
409 {"ibset", {{"i", SameInt}, {"pos", AnyInt}}, SameInt},
410 {"ichar", {{"c", AnyChar}, DefaultingKIND}, KINDInt},
peter klauslercb308d32018-10-05 18:32:54411 {"ieor", {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ}}, SameInt},
peter klauslera70f5962018-10-04 20:43:33412 {"ieor", {{"i", BOZ}, {"j", SameInt}}, SameInt},
413 {"image_status",
peter klauslercb308d32018-10-05 18:32:54414 {{"image", SameInt},
415 {"team", TEAM_TYPE, Rank::scalar, Optionality::optional}},
peter klausler7c402d92018-10-16 21:42:22416 DefaultInt},
peter klausler42b33da2018-09-29 00:02:11417 {"index",
peter klauslera70f5962018-10-04 20:43:33418 {{"string", SameChar}, {"substring", SameChar},
peter klauslercb308d32018-10-05 18:32:54419 {"back", AnyLogical, Rank::scalar, Optionality::optional},
peter klausler7c402d92018-10-16 21:42:22420 SubscriptDefaultKIND},
peter klauslera70f5962018-10-04 20:43:33421 KINDInt},
peter klauslercb308d32018-10-05 18:32:54422 {"int", {{"a", AnyNumeric, Rank::elementalOrBOZ}, DefaultingKIND}, KINDInt},
423 {"ior", {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ}}, SameInt},
peter klauslera70f5962018-10-04 20:43:33424 {"ior", {{"i", BOZ}, {"j", SameInt}}, SameInt},
425 {"ishft", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
426 {"ishftc",
427 {{"i", SameInt}, {"shift", AnyInt},
peter klauslercb308d32018-10-05 18:32:54428 {"size", AnyInt, Rank::elemental, Optionality::optional}},
peter klauslera70f5962018-10-04 20:43:33429 SameInt},
peter klausler7c402d92018-10-16 21:42:22430 {"is_iostat_end", {{"i", AnyInt}}, DefaultLogical},
431 {"is_iostat_eor", {{"i", AnyInt}}, DefaultLogical},
peter klauslerbe3b7652018-12-04 18:55:32432 {"kind", {{"x", AnyIntrinsic}}, DefaultInt},
peter klausler7c402d92018-10-16 21:42:22433 {"lbound",
peter klausler00e128e2019-06-25 20:07:32434 {{"array", Anything, Rank::anyOrAssumedRank}, RequiredDIM,
peter klausler7c402d92018-10-16 21:42:22435 SubscriptDefaultKIND},
peter klauslerf7f2a732018-10-09 19:07:29436 KINDInt, Rank::scalar},
peter klauslerd29530e2019-05-21 23:58:46437 {"lbound",
438 {{"array", Anything, Rank::anyOrAssumedRank}, SubscriptDefaultKIND},
439 KINDInt, Rank::vector},
peter klausler7c402d92018-10-16 21:42:22440 {"leadz", {{"i", AnyInt}}, DefaultInt},
peter klauslerfb1fcbb2019-06-04 17:09:54441 {"len", {{"string", AnyChar, Rank::anyOrAssumedRank}, SubscriptDefaultKIND},
peter klausler5774f0a2019-06-04 17:50:34442 KINDInt, Rank::scalar},
peter klausler7c402d92018-10-16 21:42:22443 {"len_trim", {{"string", AnyChar}, SubscriptDefaultKIND}, KINDInt},
444 {"lge", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
445 {"lgt", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
446 {"lle", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
447 {"llt", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
peter klausler8e932262019-07-01 20:22:22448 {"loc", {{"x", Anything, Rank::anyOrAssumedRank}}, SubscriptInt,
449 Rank::scalar},
peter klauslera70f5962018-10-04 20:43:33450 {"log", {{"x", SameFloating}}, SameFloating},
451 {"log10", {{"x", SameReal}}, SameReal},
452 {"logical", {{"l", AnyLogical}, DefaultingKIND}, KINDLogical},
453 {"log_gamma", {{"x", SameReal}}, SameReal},
peter klauslerf7f2a732018-10-09 19:07:29454 {"matmul",
455 {{"array_a", AnyLogical, Rank::vector},
456 {"array_b", AnyLogical, Rank::matrix}},
457 ResultLogical, Rank::vector},
458 {"matmul",
459 {{"array_a", AnyLogical, Rank::matrix},
460 {"array_b", AnyLogical, Rank::vector}},
461 ResultLogical, Rank::vector},
462 {"matmul",
463 {{"array_a", AnyLogical, Rank::matrix},
464 {"array_b", AnyLogical, Rank::matrix}},
465 ResultLogical, Rank::matrix},
466 {"matmul",
467 {{"array_a", AnyNumeric, Rank::vector},
468 {"array_b", AnyNumeric, Rank::matrix}},
469 ResultNumeric, Rank::vector},
470 {"matmul",
471 {{"array_a", AnyNumeric, Rank::matrix},
472 {"array_b", AnyNumeric, Rank::vector}},
473 ResultNumeric, Rank::vector},
474 {"matmul",
475 {{"array_a", AnyNumeric, Rank::matrix},
476 {"array_b", AnyNumeric, Rank::matrix}},
477 ResultNumeric, Rank::matrix},
peter klauslera70f5962018-10-04 20:43:33478 {"maskl", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
479 {"maskr", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
peter klauslerad9aede2018-10-11 21:51:14480 {"max",
481 {{"a1", SameRelatable}, {"a2", SameRelatable},
482 {"a3", SameRelatable, Rank::elemental, Optionality::repeats}},
483 SameRelatable},
peter klausler42b33da2018-09-29 00:02:11484 {"maxloc",
peter klauslera70f5962018-10-04 20:43:33485 {{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
peter klausler7c402d92018-10-16 21:42:22486 SubscriptDefaultKIND,
peter klauslercb308d32018-10-05 18:32:54487 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
peter klauslera70f5962018-10-04 20:43:33488 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11489 {"maxval",
peter klauslera70f5962018-10-04 20:43:33490 {{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
491 SameRelatable, Rank::dimReduced},
peter klauslerad9aede2018-10-11 21:51:14492 {"merge",
493 {{"tsource", SameType}, {"fsource", SameType}, {"mask", AnyLogical}},
494 SameType},
peter klausler42b33da2018-09-29 00:02:11495 {"merge_bits",
peter klauslercb308d32018-10-05 18:32:54496 {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ},
497 {"mask", SameInt, Rank::elementalOrBOZ}},
peter klauslera70f5962018-10-04 20:43:33498 SameInt},
499 {"merge_bits",
peter klauslercb308d32018-10-05 18:32:54500 {{"i", BOZ}, {"j", SameInt}, {"mask", SameInt, Rank::elementalOrBOZ}},
peter klauslera70f5962018-10-04 20:43:33501 SameInt},
peter klauslerad9aede2018-10-11 21:51:14502 {"min",
503 {{"a1", SameRelatable}, {"a2", SameRelatable},
504 {"a3", SameRelatable, Rank::elemental, Optionality::repeats}},
505 SameRelatable},
peter klausler42b33da2018-09-29 00:02:11506 {"minloc",
peter klauslera70f5962018-10-04 20:43:33507 {{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
peter klausler7c402d92018-10-16 21:42:22508 SubscriptDefaultKIND,
peter klauslercb308d32018-10-05 18:32:54509 {"back", AnyLogical, Rank::scalar, Optionality::optional}},
peter klauslera70f5962018-10-04 20:43:33510 KINDInt, Rank::dimReduced},
peter klausler42b33da2018-09-29 00:02:11511 {"minval",
peter klauslera70f5962018-10-04 20:43:33512 {{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
513 SameRelatable, Rank::dimReduced},
514 {"mod", {{"a", SameIntOrReal}, {"p", SameIntOrReal}}, SameIntOrReal},
515 {"modulo", {{"a", SameIntOrReal}, {"p", SameIntOrReal}}, SameIntOrReal},
516 {"nearest", {{"x", SameReal}, {"s", AnyReal}}, SameReal},
517 {"nint", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
518 {"norm2", {{"x", SameReal, Rank::array}, OptionalDIM}, SameReal,
519 Rank::dimReduced},
520 {"not", {{"i", SameInt}}, SameInt},
peter klausler8efb8972018-10-10 17:48:12521 // NULL() is a special case handled in Probe() below
peter klausler42b33da2018-09-29 00:02:11522 {"out_of_range",
peter klauslerad9aede2018-10-11 21:51:14523 {{"x", AnyIntOrReal}, {"mold", AnyIntOrReal, Rank::scalar}},
peter klausler7c402d92018-10-16 21:42:22524 DefaultLogical},
peter klauslera70f5962018-10-04 20:43:33525 {"out_of_range",
526 {{"x", AnyReal}, {"mold", AnyInt, Rank::scalar},
peter klauslercb308d32018-10-05 18:32:54527 {"round", AnyLogical, Rank::scalar, Optionality::optional}},
peter klausler7c402d92018-10-16 21:42:22528 DefaultLogical},
529 {"out_of_range", {{"x", AnyReal}, {"mold", AnyReal}}, DefaultLogical},
peter klausler42b33da2018-09-29 00:02:11530 {"pack",
peter klauslera70f5962018-10-04 20:43:33531 {{"array", SameType, Rank::array},
532 {"mask", AnyLogical, Rank::conformable},
peter klauslercb308d32018-10-05 18:32:54533 {"vector", SameType, Rank::vector, Optionality::optional}},
peter klauslera70f5962018-10-04 20:43:33534 SameType, Rank::vector},
535 {"parity", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
536 Rank::dimReduced},
peter klausler7c402d92018-10-16 21:42:22537 {"popcnt", {{"i", AnyInt}}, DefaultInt},
538 {"poppar", {{"i", AnyInt}}, DefaultInt},
peter klausler42b33da2018-09-29 00:02:11539 {"product",
peter klauslera70f5962018-10-04 20:43:33540 {{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
541 SameNumeric, Rank::dimReduced},
peter klauslerf4b12092019-05-29 22:38:33542 {"precision", {{"x", AnyFloating, Rank::anyOrAssumedRank}}, DefaultInt},
peter klausler59342b02019-05-13 16:33:18543 {"present", {{"a", Anything, Rank::anyOrAssumedRank}}, DefaultLogical},
peter klauslerd49aa3c2019-05-29 23:00:31544 {"radix", {{"x", AnyNumeric, Rank::anyOrAssumedRank}}, DefaultInt},
545 {"range", {{"x", AnyNumeric, Rank::anyOrAssumedRank}}, DefaultInt},
peter klausler28184c42019-04-04 20:58:46546 {"rank", {{"a", Anything, Rank::anyOrAssumedRank}}, DefaultInt},
peter klauslercb308d32018-10-05 18:32:54547 {"real", {{"a", AnyNumeric, Rank::elementalOrBOZ}, DefaultingKIND},
peter klauslera70f5962018-10-04 20:43:33548 KINDReal},
peter klauslerad9aede2018-10-11 21:51:14549 {"reduce",
550 {{"array", SameType, Rank::array},
551 {"operation", SameType, Rank::reduceOperation}, OptionalDIM,
552 OptionalMASK, {"identity", SameType, Rank::scalar},
553 {"ordered", AnyLogical, Rank::scalar, Optionality::optional}},
554 SameType, Rank::dimReduced},
peter klausler24379cc2018-10-10 23:45:17555 {"repeat", {{"string", SameChar, Rank::scalar}, {"ncopies", AnyInt}},
556 SameChar, Rank::scalar},
peter klausler42b33da2018-09-29 00:02:11557 {"reshape",
peter klauslera70f5962018-10-04 20:43:33558 {{"source", SameType, Rank::array}, {"shape", AnyInt, Rank::shape},
peter klauslercb308d32018-10-05 18:32:54559 {"pad", SameType, Rank::array, Optionality::optional},
560 {"order", AnyInt, Rank::vector, Optionality::optional}},
peter klauslera70f5962018-10-04 20:43:33561 SameType, Rank::shaped},
562 {"rrspacing", {{"x", SameReal}}, SameReal},
563 {"scale", {{"x", SameReal}, {"i", AnyInt}}, SameReal},
peter klausler42b33da2018-09-29 00:02:11564 {"scan",
peter klauslera70f5962018-10-04 20:43:33565 {{"string", SameChar}, {"set", SameChar},
peter klauslercb308d32018-10-05 18:32:54566 {"back", AnyLogical, Rank::elemental, Optionality::optional},
peter klausler7c402d92018-10-16 21:42:22567 SubscriptDefaultKIND},
peter klauslera70f5962018-10-04 20:43:33568 KINDInt},
peter klausler7c402d92018-10-16 21:42:22569 {"selected_char_kind", {{"name", DefaultChar, Rank::scalar}}, DefaultInt,
peter klausler24379cc2018-10-10 23:45:17570 Rank::scalar},
peter klausler7c402d92018-10-16 21:42:22571 {"selected_int_kind", {{"r", AnyInt, Rank::scalar}}, DefaultInt,
572 Rank::scalar},
peter klauslerad9aede2018-10-11 21:51:14573 {"selected_real_kind",
574 {{"p", AnyInt, Rank::scalar},
575 {"r", AnyInt, Rank::scalar, Optionality::optional},
576 {"radix", AnyInt, Rank::scalar, Optionality::optional}},
peter klausler7c402d92018-10-16 21:42:22577 DefaultInt, Rank::scalar},
peter klauslerad9aede2018-10-11 21:51:14578 {"selected_real_kind",
579 {{"p", AnyInt, Rank::scalar, Optionality::optional},
580 {"r", AnyInt, Rank::scalar},
581 {"radix", AnyInt, Rank::scalar, Optionality::optional}},
peter klausler7c402d92018-10-16 21:42:22582 DefaultInt, Rank::scalar},
peter klauslerad9aede2018-10-11 21:51:14583 {"selected_real_kind",
584 {{"p", AnyInt, Rank::scalar, Optionality::optional},
585 {"r", AnyInt, Rank::scalar, Optionality::optional},
586 {"radix", AnyInt, Rank::scalar}},
peter klausler7c402d92018-10-16 21:42:22587 DefaultInt, Rank::scalar},
peter klauslera70f5962018-10-04 20:43:33588 {"set_exponent", {{"x", SameReal}, {"i", AnyInt}}, SameReal},
peter klausler7c402d92018-10-16 21:42:22589 {"shape",
590 {{"source", Anything, Rank::anyOrAssumedRank}, SubscriptDefaultKIND},
peter klausler24379cc2018-10-10 23:45:17591 KINDInt, Rank::vector},
peter klauslera70f5962018-10-04 20:43:33592 {"shifta", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
593 {"shiftl", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
594 {"shiftr", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
595 {"sign", {{"a", SameIntOrReal}, {"b", SameIntOrReal}}, SameIntOrReal},
596 {"sin", {{"x", SameFloating}}, SameFloating},
597 {"sinh", {{"x", SameFloating}}, SameFloating},
peter klausler7c402d92018-10-16 21:42:22598 {"size",
peter klauslerfe3acf5f2019-01-07 18:15:27599 {{"array", Anything, Rank::anyOrAssumedRank}, OptionalDIM,
peter klausler7c402d92018-10-16 21:42:22600 SubscriptDefaultKIND},
peter klauslerf7f2a732018-10-09 19:07:29601 KINDInt, Rank::scalar},
peter klauslera70f5962018-10-04 20:43:33602 {"spacing", {{"x", SameReal}}, SameReal},
peter klausler42b33da2018-09-29 00:02:11603 {"spread",
peter klausler00e128e2019-06-25 20:07:32604 {{"source", SameType, Rank::known}, RequiredDIM,
peter klauslera70f5962018-10-04 20:43:33605 {"ncopies", AnyInt, Rank::scalar}},
606 SameType, Rank::rankPlus1},
607 {"sqrt", {{"x", SameFloating}}, SameFloating},
608 {"sum", {{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
609 SameNumeric, Rank::dimReduced},
610 {"tan", {{"x", SameFloating}}, SameFloating},
611 {"tanh", {{"x", SameFloating}}, SameFloating},
peter klausler7c402d92018-10-16 21:42:22612 {"trailz", {{"i", AnyInt}}, DefaultInt},
peter klauslerf7f2a732018-10-09 19:07:29613 {"transfer",
614 {{"source", Anything, Rank::known}, {"mold", SameType, Rank::scalar}},
615 SameType, Rank::scalar},
616 {"transfer",
617 {{"source", Anything, Rank::known}, {"mold", SameType, Rank::array}},
618 SameType, Rank::vector},
619 {"transfer",
peter klausler8b580e42018-12-14 19:23:14620 {{"source", Anything, Rank::anyOrAssumedRank},
621 {"mold", SameType, Rank::anyOrAssumedRank},
peter klauslerf7f2a732018-10-09 19:07:29622 {"size", AnyInt, Rank::scalar}},
623 SameType, Rank::vector},
624 {"transpose", {{"matrix", SameType, Rank::matrix}}, SameType, Rank::matrix},
peter klauslerad9aede2018-10-11 21:51:14625 {"trim", {{"string", SameChar, Rank::scalar}}, SameChar, Rank::scalar},
peter klausler7c402d92018-10-16 21:42:22626 {"ubound",
peter klausler00e128e2019-06-25 20:07:32627 {{"array", Anything, Rank::anyOrAssumedRank}, RequiredDIM,
peter klausler7c402d92018-10-16 21:42:22628 SubscriptDefaultKIND},
peter klauslerf7f2a732018-10-09 19:07:29629 KINDInt, Rank::scalar},
peter klauslerd29530e2019-05-21 23:58:46630 {"ubound",
631 {{"array", Anything, Rank::anyOrAssumedRank}, SubscriptDefaultKIND},
632 KINDInt, Rank::vector},
peter klauslerf7f2a732018-10-09 19:07:29633 {"unpack",
634 {{"vector", SameType, Rank::vector}, {"mask", AnyLogical, Rank::array},
635 {"field", SameType, Rank::conformable}},
636 SameType, Rank::conformable},
peter klausler42b33da2018-09-29 00:02:11637 {"verify",
peter klauslera70f5962018-10-04 20:43:33638 {{"string", SameChar}, {"set", SameChar},
peter klauslercb308d32018-10-05 18:32:54639 {"back", AnyLogical, Rank::elemental, Optionality::optional},
peter klausler7c402d92018-10-16 21:42:22640 SubscriptDefaultKIND},
peter klauslera70f5962018-10-04 20:43:33641 KINDInt},
peter klausler42b33da2018-09-29 00:02:11642};
643
peter klausler8efb8972018-10-10 17:48:12644// TODO: Coarray intrinsic functions
peter klauslerad9aede2018-10-11 21:51:14645// LCOBOUND, UCOBOUND, FAILED_IMAGES, GET_TEAM, IMAGE_INDEX,
646// NUM_IMAGES, STOPPED_IMAGES, TEAM_NUMBER, THIS_IMAGE,
647// COSHAPE
peter klausler8efb8972018-10-10 17:48:12648// TODO: Object characteristic inquiry functions
peter klausler4f2c8fa2019-06-19 18:50:07649// ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS,
peter klausler59342b02019-05-13 16:33:18650// SAME_TYPE, STORAGE_SIZE
peter klauslerad9aede2018-10-11 21:51:14651// TODO: Type inquiry intrinsic functions - these return constants
652// BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT,
peter klauslerf4b12092019-05-29 22:38:33653// NEW_LINE, TINY
peter klauslerad9aede2018-10-11 21:51:14654// TODO: Non-standard intrinsic functions
655// AND, OR, XOR, LSHIFT, RSHIFT, SHIFT, ZEXT, IZEXT,
656// COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL,
peter klausler8e932262019-07-01 20:22:22657// DCMPLX, EQV, NEQV, INT8, JINT, JNINT, KNINT,
peter klauslerad9aede2018-10-11 21:51:14658// QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM,
659// INUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF,
660// MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR
661// IARG, IARGC, NARGS, NUMARG, BADDRESS, IADDR, CACHESIZE,
662// EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC
663// probably more (these are PGI + Intel, possibly incomplete)
peter klausler8e932262019-07-01 20:22:22664// TODO: Optionally warn on use of non-standard intrinsics:
665// LOC, probably others
peter klausler42b33da2018-09-29 00:02:11666
peter klauslerba56b912019-02-22 23:45:30667// The following table contains the intrinsic functions listed in
668// Tables 16.2 and 16.3 in Fortran 2018. The "unrestricted" functions
669// in Table 16.2 can be used as actual arguments, PROCEDURE() interfaces,
670// and procedure pointer targets.
peter klausler42b33da2018-09-29 00:02:11671struct SpecificIntrinsicInterface : public IntrinsicInterface {
672 const char *generic{nullptr};
peter klauslerba56b912019-02-22 23:45:30673 bool isRestrictedSpecific{false};
peter klausler8a326cb2019-06-05 22:40:59674 bool forceResultType{false};
peter klausler42b33da2018-09-29 00:02:11675};
676
peter klauslerb22d4942018-10-01 18:27:45677static const SpecificIntrinsicInterface specificIntrinsicFunction[]{
peter klausler7c402d92018-10-16 21:42:22678 {{"abs", {{"a", DefaultReal}}, DefaultReal}},
679 {{"acos", {{"x", DefaultReal}}, DefaultReal}},
680 {{"aimag", {{"z", DefaultComplex}}, DefaultReal}},
681 {{"aint", {{"a", DefaultReal}}, DefaultReal}},
682 {{"alog", {{"x", DefaultReal}}, DefaultReal}, "log"},
683 {{"alog10", {{"x", DefaultReal}}, DefaultReal}, "log10"},
peter klauslerad9aede2018-10-11 21:51:14684 {{"amax0",
peter klausler7c402d92018-10-16 21:42:22685 {{"a1", DefaultInt}, {"a2", DefaultInt},
686 {"a3", DefaultInt, Rank::elemental, Optionality::repeats}},
687 DefaultReal},
peter klausler8a326cb2019-06-05 22:40:59688 "max", true, true},
peter klauslerad9aede2018-10-11 21:51:14689 {{"amax1",
peter klausler7c402d92018-10-16 21:42:22690 {{"a1", DefaultReal}, {"a2", DefaultReal},
691 {"a3", DefaultReal, Rank::elemental, Optionality::repeats}},
692 DefaultReal},
peter klausler8a326cb2019-06-05 22:40:59693 "max", true, true},
peter klauslerad9aede2018-10-11 21:51:14694 {{"amin0",
peter klausler7c402d92018-10-16 21:42:22695 {{"a1", DefaultInt}, {"a2", DefaultInt},
696 {"a3", DefaultInt, Rank::elemental, Optionality::repeats}},
697 DefaultReal},
peter klausler8a326cb2019-06-05 22:40:59698 "min", true, true},
peter klauslerad9aede2018-10-11 21:51:14699 {{"amin1",
peter klausler7c402d92018-10-16 21:42:22700 {{"a1", DefaultReal}, {"a2", DefaultReal},
701 {"a3", DefaultReal, Rank::elemental, Optionality::repeats}},
702 DefaultReal},
peter klausler8a326cb2019-06-05 22:40:59703 "min", true, true},
peter klausler7c402d92018-10-16 21:42:22704 {{"amod", {{"a", DefaultReal}, {"p", DefaultReal}}, DefaultReal}, "mod"},
705 {{"anint", {{"a", DefaultReal}}, DefaultReal}},
706 {{"asin", {{"x", DefaultReal}}, DefaultReal}},
707 {{"atan", {{"x", DefaultReal}}, DefaultReal}},
708 {{"atan2", {{"y", DefaultReal}, {"x", DefaultReal}}, DefaultReal}},
709 {{"cabs", {{"a", DefaultComplex}}, DefaultReal}, "abs"},
710 {{"ccos", {{"a", DefaultComplex}}, DefaultComplex}, "cos"},
peter klauslera0e50522019-06-21 21:04:40711 {{"cdabs", {{"a", DoublePrecisionComplex}}, DoublePrecision}, "abs"},
712 {{"cdcos", {{"a", DoublePrecisionComplex}}, DoublePrecisionComplex}, "cos"},
713 {{"cdexp", {{"a", DoublePrecisionComplex}}, DoublePrecisionComplex}, "exp"},
714 {{"cdlog", {{"a", DoublePrecisionComplex}}, DoublePrecisionComplex}, "log"},
715 {{"cdsin", {{"a", DoublePrecisionComplex}}, DoublePrecisionComplex}, "sin"},
716 {{"cdsqrt", {{"a", DoublePrecisionComplex}}, DoublePrecisionComplex},
717 "sqrt"},
peter klausler7c402d92018-10-16 21:42:22718 {{"cexp", {{"a", DefaultComplex}}, DefaultComplex}, "exp"},
719 {{"clog", {{"a", DefaultComplex}}, DefaultComplex}, "log"},
720 {{"conjg", {{"a", DefaultComplex}}, DefaultComplex}},
721 {{"cos", {{"x", DefaultReal}}, DefaultReal}},
722 {{"csin", {{"a", DefaultComplex}}, DefaultComplex}, "sin"},
723 {{"csqrt", {{"a", DefaultComplex}}, DefaultComplex}, "sqrt"},
724 {{"ctan", {{"a", DefaultComplex}}, DefaultComplex}, "tan"},
peter klauslera70f5962018-10-04 20:43:33725 {{"dabs", {{"a", DoublePrecision}}, DoublePrecision}, "abs"},
726 {{"dacos", {{"x", DoublePrecision}}, DoublePrecision}, "acos"},
727 {{"dasin", {{"x", DoublePrecision}}, DoublePrecision}, "asin"},
728 {{"datan", {{"x", DoublePrecision}}, DoublePrecision}, "atan"},
729 {{"datan2", {{"y", DoublePrecision}, {"x", DoublePrecision}},
730 DoublePrecision},
731 "atan2"},
peter klauslera0e50522019-06-21 21:04:40732 {{"dconjg", {{"a", DoublePrecisionComplex}}, DoublePrecisionComplex},
733 "conjg"},
peter klauslera70f5962018-10-04 20:43:33734 {{"dcos", {{"x", DoublePrecision}}, DoublePrecision}, "cos"},
735 {{"dcosh", {{"x", DoublePrecision}}, DoublePrecision}, "cosh"},
736 {{"ddim", {{"x", DoublePrecision}, {"y", DoublePrecision}},
737 DoublePrecision},
738 "dim"},
739 {{"dexp", {{"x", DoublePrecision}}, DoublePrecision}, "exp"},
peter klausler7c402d92018-10-16 21:42:22740 {{"dim", {{"x", DefaultReal}, {"y", DefaultReal}}, DefaultReal}},
peter klauslera70f5962018-10-04 20:43:33741 {{"dint", {{"a", DoublePrecision}}, DoublePrecision}, "aint"},
742 {{"dlog", {{"x", DoublePrecision}}, DoublePrecision}, "log"},
743 {{"dlog10", {{"x", DoublePrecision}}, DoublePrecision}, "log10"},
peter klauslerad9aede2018-10-11 21:51:14744 {{"dmax1",
745 {{"a1", DoublePrecision}, {"a2", DoublePrecision},
746 {"a3", DoublePrecision, Rank::elemental, Optionality::repeats}},
747 DoublePrecision},
748 "max", true},
749 {{"dmin1",
750 {{"a1", DoublePrecision}, {"a2", DoublePrecision},
751 {"a3", DoublePrecision, Rank::elemental, Optionality::repeats}},
752 DoublePrecision},
753 "min", true},
peter klauslera70f5962018-10-04 20:43:33754 {{"dmod", {{"a", DoublePrecision}, {"p", DoublePrecision}},
755 DoublePrecision},
756 "mod"},
757 {{"dnint", {{"a", DoublePrecision}}, DoublePrecision}, "anint"},
peter klausler7c402d92018-10-16 21:42:22758 {{"dprod", {{"x", DefaultReal}, {"y", DefaultReal}}, DoublePrecision}},
peter klauslera70f5962018-10-04 20:43:33759 {{"dsign", {{"a", DoublePrecision}, {"b", DoublePrecision}},
760 DoublePrecision},
761 "sign"},
762 {{"dsin", {{"x", DoublePrecision}}, DoublePrecision}, "sin"},
763 {{"dsinh", {{"x", DoublePrecision}}, DoublePrecision}, "sinh"},
764 {{"dsqrt", {{"x", DoublePrecision}}, DoublePrecision}, "sqrt"},
765 {{"dtan", {{"x", DoublePrecision}}, DoublePrecision}, "tan"},
766 {{"dtanh", {{"x", DoublePrecision}}, DoublePrecision}, "tanh"},
peter klausler7c402d92018-10-16 21:42:22767 {{"exp", {{"x", DefaultReal}}, DefaultReal}},
768 {{"float", {{"i", DefaultInt}}, DefaultReal}, "real", true},
769 {{"iabs", {{"a", DefaultInt}}, DefaultInt}, "abs"},
770 {{"idim", {{"x", DefaultInt}, {"y", DefaultInt}}, DefaultInt}, "dim"},
771 {{"idint", {{"a", DoublePrecision}}, DefaultInt}, "int", true},
772 {{"idnint", {{"a", DoublePrecision}}, DefaultInt}, "nint"},
773 {{"ifix", {{"a", DefaultReal}}, DefaultInt}, "int", true},
774 {{"index", {{"string", DefaultChar}, {"substring", DefaultChar}},
775 DefaultInt}},
776 {{"isign", {{"a", DefaultInt}, {"b", DefaultInt}}, DefaultInt}, "sign"},
peter klausler5774f0a2019-06-04 17:50:34777 {{"len", {{"string", DefaultChar, Rank::anyOrAssumedRank}}, DefaultInt,
778 Rank::scalar}},
peter klausler8a326cb2019-06-05 22:40:59779 {{"lge", {{"string_a", DefaultChar}, {"string_b", DefaultChar}},
780 DefaultLogical}},
781 {{"lgt", {{"string_a", DefaultChar}, {"string_b", DefaultChar}},
782 DefaultLogical}},
783 {{"lle", {{"string_a", DefaultChar}, {"string_b", DefaultChar}},
784 DefaultLogical}},
785 {{"llt", {{"string_a", DefaultChar}, {"string_b", DefaultChar}},
786 DefaultLogical}},
peter klausler7c402d92018-10-16 21:42:22787 {{"log", {{"x", DefaultReal}}, DefaultReal}},
788 {{"log10", {{"x", DefaultReal}}, DefaultReal}},
peter klauslerad9aede2018-10-11 21:51:14789 {{"max0",
peter klausler7c402d92018-10-16 21:42:22790 {{"a1", DefaultInt}, {"a2", DefaultInt},
791 {"a3", DefaultInt, Rank::elemental, Optionality::repeats}},
792 DefaultInt},
peter klausler8a326cb2019-06-05 22:40:59793 "max", true, true},
peter klauslerad9aede2018-10-11 21:51:14794 {{"max1",
peter klausler7c402d92018-10-16 21:42:22795 {{"a1", DefaultReal}, {"a2", DefaultReal},
796 {"a3", DefaultReal, Rank::elemental, Optionality::repeats}},
797 DefaultInt},
peter klausler8a326cb2019-06-05 22:40:59798 "max", true, true},
peter klauslerad9aede2018-10-11 21:51:14799 {{"min0",
peter klausler7c402d92018-10-16 21:42:22800 {{"a1", DefaultInt}, {"a2", DefaultInt},
801 {"a3", DefaultInt, Rank::elemental, Optionality::repeats}},
802 DefaultInt},
peter klausler8a326cb2019-06-05 22:40:59803 "min", true, true},
peter klauslerad9aede2018-10-11 21:51:14804 {{"min1",
peter klausler7c402d92018-10-16 21:42:22805 {{"a1", DefaultReal}, {"a2", DefaultReal},
806 {"a3", DefaultReal, Rank::elemental, Optionality::repeats}},
807 DefaultInt},
peter klausler8a326cb2019-06-05 22:40:59808 "min", true, true},
peter klausler7c402d92018-10-16 21:42:22809 {{"mod", {{"a", DefaultInt}, {"p", DefaultInt}}, DefaultInt}},
810 {{"nint", {{"a", DefaultReal}}, DefaultInt}},
811 {{"sign", {{"a", DefaultReal}, {"b", DefaultReal}}, DefaultReal}},
812 {{"sin", {{"x", DefaultReal}}, DefaultReal}},
813 {{"sinh", {{"x", DefaultReal}}, DefaultReal}},
814 {{"sngl", {{"a", DoublePrecision}}, DefaultReal}, "real", true},
815 {{"sqrt", {{"x", DefaultReal}}, DefaultReal}},
816 {{"tan", {{"x", DefaultReal}}, DefaultReal}},
817 {{"tanh", {{"x", DefaultReal}}, DefaultReal}},
peter klausler42b33da2018-09-29 00:02:11818};
819
peter klauslerad9aede2018-10-11 21:51:14820// TODO: Intrinsic subroutines
821// MVBITS (elemental), CPU_TIME, DATE_AND_TIME, EVENT_QUERY,
822// EXECUTE_COMMAND_LINE, GET_COMMAND, GET_COMMAND_ARGUMENT,
823// GET_ENVIRONMENT_VARIABLE, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER,
824// RANDOM_SEED, SYSTEM_CLOCK
825// TODO: Atomic intrinsic subroutines: ATOMIC_ADD &al.
826// TODO: Collective intrinsic subroutines: CO_BROADCAST &al.
peter klausler42b33da2018-09-29 00:02:11827
peter klauslera70f5962018-10-04 20:43:33828// Intrinsic interface matching against the arguments of a particular
829// procedure reference.
peter klausleref9dd9d2018-10-17 22:09:48830std::optional<SpecificCall> IntrinsicInterface::Match(
peter klauslerbf339f82018-10-15 22:28:47831 const CallCharacteristics &call,
peter klauslerf9d6c0a2019-01-18 20:40:47832 const common::IntrinsicTypeDefaultKinds &defaults,
peter klausler146e13c2019-04-18 21:11:15833 ActualArguments &arguments, FoldingContext &context) const {
834 auto &messages{context.messages()};
peter klauslera70f5962018-10-04 20:43:33835 // Attempt to construct a 1-1 correspondence between the dummy arguments in
836 // a particular intrinsic procedure's generic interface and the actual
837 // arguments in a procedure reference.
peter klausler84ea49d2018-10-18 17:50:55838 std::size_t dummyArgPatterns{0};
839 for (; dummyArgPatterns < maxArguments &&
840 dummy[dummyArgPatterns].keyword != nullptr;
841 ++dummyArgPatterns) {
peter klauslera70f5962018-10-04 20:43:33842 }
peter klausler84ea49d2018-10-18 17:50:55843 std::vector<ActualArgument *> actualForDummy(dummyArgPatterns, nullptr);
844 // MAX and MIN (and others that map to them) allow their last argument to
845 // be repeated indefinitely. The actualForDummy vector is sized
846 // and null-initialized to the non-repeated dummy argument count,
847 // but additional actual argument pointers can be pushed on it
848 // when this flag is set.
849 bool repeatLastDummy{dummyArgPatterns > 0 &&
850 dummy[dummyArgPatterns - 1].optionality == Optionality::repeats};
851 int missingActualArguments{0};
peter klausleref9dd9d2018-10-17 22:09:48852 for (std::optional<ActualArgument> &arg : arguments) {
peter klausler84ea49d2018-10-18 17:50:55853 if (!arg.has_value()) {
854 ++missingActualArguments;
855 } else {
peter klausleref9dd9d2018-10-17 22:09:48856 if (arg->isAlternateReturn) {
857 messages.Say(
858 "alternate return specifier not acceptable on call to intrinsic '%s'"_err_en_US,
859 name);
860 return std::nullopt;
861 }
862 bool found{false};
peter klausler84ea49d2018-10-18 17:50:55863 int slot{missingActualArguments};
864 for (std::size_t j{0}; j < dummyArgPatterns && !found; ++j) {
865 if (arg->keyword.has_value()) {
866 found = *arg->keyword == dummy[j].keyword;
867 if (found) {
868 if (const auto *previous{actualForDummy[j]}) {
869 if (previous->keyword.has_value()) {
870 messages.Say(*arg->keyword,
871 "repeated keyword argument to intrinsic '%s'"_err_en_US,
872 name);
873 } else {
874 messages.Say(*arg->keyword,
875 "keyword argument to intrinsic '%s' was supplied "
876 "positionally by an earlier actual argument"_err_en_US,
877 name);
878 }
879 return std::nullopt;
880 }
peter klausleref9dd9d2018-10-17 22:09:48881 }
peter klausler84ea49d2018-10-18 17:50:55882 } else {
883 found = actualForDummy[j] == nullptr && slot-- == 0;
884 }
885 if (found) {
886 actualForDummy[j] = &*arg;
peter klauslera70f5962018-10-04 20:43:33887 }
888 }
peter klausleref9dd9d2018-10-17 22:09:48889 if (!found) {
peter klausler84ea49d2018-10-18 17:50:55890 if (repeatLastDummy && !arg->keyword.has_value()) {
891 // MAX/MIN argument after the 2nd
892 actualForDummy.push_back(&*arg);
peter klausleref9dd9d2018-10-17 22:09:48893 } else {
peter klausler84ea49d2018-10-18 17:50:55894 if (arg->keyword.has_value()) {
895 messages.Say(*arg->keyword,
896 "unknown keyword argument to intrinsic '%s'"_err_en_US, name);
897 } else {
898 messages.Say(
899 "too many actual arguments for intrinsic '%s'"_err_en_US, name);
900 }
901 return std::nullopt;
peter klausleref9dd9d2018-10-17 22:09:48902 }
peter klauslera70f5962018-10-04 20:43:33903 }
904 }
905 }
906
peter klausler84ea49d2018-10-18 17:50:55907 std::size_t dummies{actualForDummy.size()};
908
peter klauslera70f5962018-10-04 20:43:33909 // Check types and kinds of the actual arguments against the intrinsic's
910 // interface. Ensure that two or more arguments that have to have the same
911 // type and kind do so. Check for missing non-optional arguments now, too.
peter klauslera62636f2018-10-08 22:35:19912 const ActualArgument *sameArg{nullptr};
peter klauslera70f5962018-10-04 20:43:33913 const IntrinsicDummyArgument *kindDummyArg{nullptr};
peter klauslera62636f2018-10-08 22:35:19914 const ActualArgument *kindArg{nullptr};
peter klauslera70f5962018-10-04 20:43:33915 bool hasDimArg{false};
peter klausler84ea49d2018-10-18 17:50:55916 for (std::size_t j{0}; j < dummies; ++j) {
917 const IntrinsicDummyArgument &d{dummy[std::min(j, dummyArgPatterns - 1)]};
peter klauslera70f5962018-10-04 20:43:33918 if (d.typePattern.kindCode == KindCode::kindArg) {
919 CHECK(kindDummyArg == nullptr);
920 kindDummyArg = &d;
921 }
peter klausler84ea49d2018-10-18 17:50:55922 const ActualArgument *arg{actualForDummy[j]};
peter klauslera70f5962018-10-04 20:43:33923 if (!arg) {
peter klauslercb308d32018-10-05 18:32:54924 if (d.optionality == Optionality::required) {
peter klausler7bda1b32018-10-12 23:01:55925 messages.Say("missing mandatory '%s=' argument"_err_en_US, d.keyword);
peter klauslera70f5962018-10-04 20:43:33926 return std::nullopt; // missing non-OPTIONAL argument
peter klauslercb308d32018-10-05 18:32:54927 } else {
928 continue;
peter klauslera70f5962018-10-04 20:43:33929 }
930 }
peter klausler146e13c2019-04-18 21:11:15931 if (arg->GetAssumedTypeDummy()) {
932 // TYPE(*) assumed-type dummy argument forwarded to intrinsic
933 if (d.typePattern.categorySet == AnyType &&
934 d.typePattern.kindCode == KindCode::any &&
935 d.rank == Rank::anyOrAssumedRank) {
936 continue;
peter klausler25e6f032019-05-03 18:29:15937 } else {
938 messages.Say("Assumed type TYPE(*) dummy argument not allowed "
939 "for '%s=' intrinsic argument"_err_en_US,
940 d.keyword);
941 return std::nullopt;
peter klausler146e13c2019-04-18 21:11:15942 }
peter klausler146e13c2019-04-18 21:11:15943 }
peter klauslera62636f2018-10-08 22:35:19944 std::optional<DynamicType> type{arg->GetType()};
945 if (!type.has_value()) {
946 CHECK(arg->Rank() == 0);
peter klauslerd29530e2019-05-21 23:58:46947 const Expr<SomeType> *expr{arg->UnwrapExpr()};
peter klausler25e6f032019-05-03 18:29:15948 CHECK(expr != nullptr);
949 if (std::holds_alternative<BOZLiteralConstant>(expr->u)) {
950 if (d.typePattern.kindCode == KindCode::typeless ||
951 d.rank == Rank::elementalOrBOZ) {
952 continue;
953 } else {
954 messages.Say(
955 "Typeless (BOZ) not allowed for '%s=' argument"_err_en_US,
956 d.keyword);
957 }
958 } else {
959 // NULL(), pointer to subroutine, &c.
960 messages.Say("Typeless item not allowed for '%s=' argument"_err_en_US,
961 d.keyword);
peter klauslera70f5962018-10-04 20:43:33962 }
peter klauslercb308d32018-10-05 18:32:54963 return std::nullopt;
peter klausler59342b02019-05-13 16:33:18964 } else if (!d.typePattern.categorySet.test(type->category())) {
peter klausler25e6f032019-05-03 18:29:15965 messages.Say("Actual argument for '%s=' has bad type '%s'"_err_en_US,
peter klauslerec6cf762019-05-06 16:33:45966 d.keyword, type->AsFortran());
peter klauslera70f5962018-10-04 20:43:33967 return std::nullopt; // argument has invalid type category
968 }
969 bool argOk{false};
970 switch (d.typePattern.kindCode) {
971 case KindCode::none:
972 case KindCode::typeless:
973 case KindCode::teamType: // TODO: TEAM_TYPE
974 argOk = false;
975 break;
976 case KindCode::defaultIntegerKind:
peter klausler59342b02019-05-13 16:33:18977 argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Integer);
peter klauslera70f5962018-10-04 20:43:33978 break;
979 case KindCode::defaultRealKind:
peter klausler59342b02019-05-13 16:33:18980 argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Real);
peter klauslera70f5962018-10-04 20:43:33981 break;
982 case KindCode::doublePrecision:
peter klausler59342b02019-05-13 16:33:18983 argOk = type->kind() == defaults.doublePrecisionKind();
peter klauslera70f5962018-10-04 20:43:33984 break;
985 case KindCode::defaultCharKind:
peter klausler59342b02019-05-13 16:33:18986 argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Character);
peter klauslera70f5962018-10-04 20:43:33987 break;
988 case KindCode::defaultLogicalKind:
peter klausler59342b02019-05-13 16:33:18989 argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Logical);
peter klauslera70f5962018-10-04 20:43:33990 break;
991 case KindCode::any: argOk = true; break;
992 case KindCode::kindArg:
peter klausler59342b02019-05-13 16:33:18993 CHECK(type->category() == TypeCategory::Integer);
peter klauslera70f5962018-10-04 20:43:33994 CHECK(kindArg == nullptr);
995 kindArg = arg;
peter klauslerf7f2a732018-10-09 19:07:29996 argOk = true;
peter klauslera70f5962018-10-04 20:43:33997 break;
998 case KindCode::dimArg:
peter klausler59342b02019-05-13 16:33:18999 CHECK(type->category() == TypeCategory::Integer);
peter klauslera70f5962018-10-04 20:43:331000 hasDimArg = true;
1001 argOk = true;
1002 break;
1003 case KindCode::same:
1004 if (sameArg == nullptr) {
1005 sameArg = arg;
1006 }
peter klausler1b1f60f2018-12-05 21:03:391007 argOk = type.value() == sameArg->GetType();
peter klauslera70f5962018-10-04 20:43:331008 break;
1009 case KindCode::effectiveKind:
1010 common::die("INTERNAL: KindCode::effectiveKind appears on argument '%s' "
1011 "for intrinsic '%s'",
1012 d.keyword, name);
1013 break;
1014 default: CRASH_NO_CASE;
1015 }
1016 if (!argOk) {
peter klauslercb308d32018-10-05 18:32:541017 messages.Say(
peter klausler5774f0a2019-06-04 17:50:341018 "Actual argument for '%s=' has bad type or kind '%s'"_err_en_US,
peter klauslerec6cf762019-05-06 16:33:451019 d.keyword, type->AsFortran());
peter klauslera70f5962018-10-04 20:43:331020 return std::nullopt;
1021 }
1022 }
1023
1024 // Check the ranks of the arguments against the intrinsic's interface.
peter klauslera62636f2018-10-08 22:35:191025 const ActualArgument *arrayArg{nullptr};
1026 const ActualArgument *knownArg{nullptr};
peter klauslerb65572d2019-04-03 23:04:131027 std::optional<int> shapeArgSize;
peter klauslera70f5962018-10-04 20:43:331028 int elementalRank{0};
peter klausler84ea49d2018-10-18 17:50:551029 for (std::size_t j{0}; j < dummies; ++j) {
1030 const IntrinsicDummyArgument &d{dummy[std::min(j, dummyArgPatterns - 1)]};
1031 if (const ActualArgument * arg{actualForDummy[j]}) {
peter klausler146e13c2019-04-18 21:11:151032 if (IsAssumedRank(*arg) && d.rank != Rank::anyOrAssumedRank) {
peter klausler5774f0a2019-06-04 17:50:341033 messages.Say("Assumed-rank array cannot be forwarded to "
peter klausler03618fd2018-10-29 22:25:351034 "'%s=' argument"_err_en_US,
peter klauslercb308d32018-10-05 18:32:541035 d.keyword);
peter klauslera70f5962018-10-04 20:43:331036 return std::nullopt;
1037 }
peter klauslera62636f2018-10-08 22:35:191038 int rank{arg->Rank()};
peter klauslera70f5962018-10-04 20:43:331039 bool argOk{false};
1040 switch (d.rank) {
1041 case Rank::elemental:
peter klauslercb308d32018-10-05 18:32:541042 case Rank::elementalOrBOZ:
peter klauslera70f5962018-10-04 20:43:331043 if (elementalRank == 0) {
peter klauslera62636f2018-10-08 22:35:191044 elementalRank = rank;
peter klauslera70f5962018-10-04 20:43:331045 }
peter klauslera62636f2018-10-08 22:35:191046 argOk = rank == 0 || rank == elementalRank;
peter klauslera70f5962018-10-04 20:43:331047 break;
peter klauslera62636f2018-10-08 22:35:191048 case Rank::scalar: argOk = rank == 0; break;
1049 case Rank::vector: argOk = rank == 1; break;
peter klauslera70f5962018-10-04 20:43:331050 case Rank::shape:
peter klauslerb65572d2019-04-03 23:04:131051 CHECK(!shapeArgSize.has_value());
1052 if (rank == 1) {
peter klausler146e13c2019-04-18 21:11:151053 if (auto shape{GetShape(context, *arg)}) {
peter klausler28184c42019-04-04 20:58:461054 if (auto constShape{AsConstantShape(*shape)}) {
peter klausler59342b02019-05-13 16:33:181055 shapeArgSize = constShape->At(ConstantSubscripts{1}).ToInt64();
peter klausler28184c42019-04-04 20:58:461056 CHECK(shapeArgSize >= 0);
1057 argOk = true;
peter klauslerb65572d2019-04-03 23:04:131058 }
1059 }
1060 }
1061 if (!argOk) {
1062 messages.Say(
1063 "'shape=' argument must be a vector of known size"_err_en_US);
1064 return std::nullopt;
1065 }
peter klauslera70f5962018-10-04 20:43:331066 break;
peter klauslera62636f2018-10-08 22:35:191067 case Rank::matrix: argOk = rank == 2; break;
peter klauslera70f5962018-10-04 20:43:331068 case Rank::array:
peter klauslera62636f2018-10-08 22:35:191069 argOk = rank > 0;
peter klauslera70f5962018-10-04 20:43:331070 if (!arrayArg) {
1071 arrayArg = arg;
1072 } else {
peter klauslera62636f2018-10-08 22:35:191073 argOk &= rank == arrayArg->Rank();
peter klauslera70f5962018-10-04 20:43:331074 }
1075 break;
1076 case Rank::known:
1077 CHECK(knownArg == nullptr);
1078 knownArg = arg;
1079 argOk = true;
1080 break;
1081 case Rank::anyOrAssumedRank: argOk = true; break;
1082 case Rank::conformable:
1083 CHECK(arrayArg != nullptr);
peter klauslera62636f2018-10-08 22:35:191084 argOk = rank == 0 || rank == arrayArg->Rank();
peter klauslera70f5962018-10-04 20:43:331085 break;
1086 case Rank::dimRemoved:
1087 CHECK(arrayArg != nullptr);
1088 if (hasDimArg) {
peter klauslerc3ce68c2019-05-30 23:14:241089 argOk = rank == 0 || rank + 1 == arrayArg->Rank();
peter klauslera70f5962018-10-04 20:43:331090 } else {
peter klauslera62636f2018-10-08 22:35:191091 argOk = rank == 0;
peter klauslera70f5962018-10-04 20:43:331092 }
1093 break;
peter klauslerad9aede2018-10-11 21:51:141094 case Rank::reduceOperation:
1095 // TODO: Confirm that the argument is a pure function
1096 // of two arguments with several constraints
1097 CHECK(arrayArg != nullptr);
1098 argOk = rank == 0;
1099 break;
peter klauslera70f5962018-10-04 20:43:331100 case Rank::dimReduced:
1101 case Rank::rankPlus1:
1102 case Rank::shaped:
1103 common::die("INTERNAL: result-only rank code appears on argument '%s' "
1104 "for intrinsic '%s'",
1105 d.keyword, name);
1106 default: CRASH_NO_CASE;
1107 }
1108 if (!argOk) {
peter klausler7bda1b32018-10-12 23:01:551109 messages.Say("'%s=' argument has unacceptable rank %d"_err_en_US,
peter klauslera62636f2018-10-08 22:35:191110 d.keyword, rank);
peter klauslera70f5962018-10-04 20:43:331111 return std::nullopt;
1112 }
1113 }
1114 }
1115
peter klauslera70f5962018-10-04 20:43:331116 // Calculate the characteristics of the function result, if any
peter klausleref9dd9d2018-10-17 22:09:481117 std::optional<DynamicType> resultType;
peter klausler25e6f032019-05-03 18:29:151118 if (auto category{result.categorySet.LeastElement()}) {
1119 // The intrinsic is not a subroutine.
peter klausleref9dd9d2018-10-17 22:09:481120 if (call.isSubroutineCall) {
1121 return std::nullopt;
1122 }
peter klausleref9dd9d2018-10-17 22:09:481123 switch (result.kindCode) {
1124 case KindCode::defaultIntegerKind:
1125 CHECK(result.categorySet == IntType);
peter klausler25e6f032019-05-03 18:29:151126 CHECK(*category == TypeCategory::Integer);
1127 resultType = DynamicType{TypeCategory::Integer,
1128 defaults.GetDefaultKind(TypeCategory::Integer)};
peter klausleref9dd9d2018-10-17 22:09:481129 break;
1130 case KindCode::defaultRealKind:
peter klausler25e6f032019-05-03 18:29:151131 CHECK(result.categorySet == CategorySet{*category});
1132 CHECK(FloatingType.test(*category));
1133 resultType =
1134 DynamicType{*category, defaults.GetDefaultKind(TypeCategory::Real)};
peter klausleref9dd9d2018-10-17 22:09:481135 break;
1136 case KindCode::doublePrecision:
1137 CHECK(result.categorySet == RealType);
peter klausler25e6f032019-05-03 18:29:151138 CHECK(*category == TypeCategory::Real);
1139 resultType =
1140 DynamicType{TypeCategory::Real, defaults.doublePrecisionKind()};
peter klausleref9dd9d2018-10-17 22:09:481141 break;
1142 case KindCode::defaultCharKind:
1143 CHECK(result.categorySet == CharType);
peter klausler25e6f032019-05-03 18:29:151144 CHECK(*category == TypeCategory::Character);
1145 resultType = DynamicType{TypeCategory::Character,
1146 defaults.GetDefaultKind(TypeCategory::Character)};
peter klausleref9dd9d2018-10-17 22:09:481147 break;
1148 case KindCode::defaultLogicalKind:
1149 CHECK(result.categorySet == LogicalType);
peter klausler25e6f032019-05-03 18:29:151150 CHECK(*category == TypeCategory::Logical);
1151 resultType = DynamicType{TypeCategory::Logical,
1152 defaults.GetDefaultKind(TypeCategory::Logical)};
peter klausleref9dd9d2018-10-17 22:09:481153 break;
1154 case KindCode::same:
1155 CHECK(sameArg != nullptr);
1156 if (std::optional<DynamicType> aType{sameArg->GetType()}) {
peter klausler59342b02019-05-13 16:33:181157 if (result.categorySet.test(aType->category())) {
peter klausleref9dd9d2018-10-17 22:09:481158 resultType = *aType;
1159 } else {
peter klausler59342b02019-05-13 16:33:181160 resultType = DynamicType{*category, aType->kind()};
peter klausleref9dd9d2018-10-17 22:09:481161 }
1162 }
1163 break;
1164 case KindCode::effectiveKind:
1165 CHECK(kindDummyArg != nullptr);
peter klausler25e6f032019-05-03 18:29:151166 CHECK(result.categorySet == CategorySet{*category});
peter klausleref9dd9d2018-10-17 22:09:481167 if (kindArg != nullptr) {
peter klauslerd29530e2019-05-21 23:58:461168 if (auto *expr{kindArg->UnwrapExpr()}) {
peter klausler146e13c2019-04-18 21:11:151169 CHECK(expr->Rank() == 0);
1170 if (auto code{ToInt64(*expr)}) {
peter klausler25e6f032019-05-03 18:29:151171 if (IsValidKindOfIntrinsicType(*category, *code)) {
1172 resultType = DynamicType{*category, static_cast<int>(*code)};
peter klausler146e13c2019-04-18 21:11:151173 break;
1174 }
peter klauslerf7f2a732018-10-09 19:07:291175 }
1176 }
peter klausleref9dd9d2018-10-17 22:09:481177 messages.Say("'kind=' argument must be a constant scalar integer "
1178 "whose value is a supported kind for the "
1179 "intrinsic result type"_err_en_US);
1180 return std::nullopt;
1181 } else if (kindDummyArg->optionality == Optionality::defaultsToSameKind) {
1182 CHECK(sameArg != nullptr);
1183 resultType = *sameArg->GetType();
1184 } else if (kindDummyArg->optionality ==
1185 Optionality::defaultsToSubscriptKind) {
peter klausler25e6f032019-05-03 18:29:151186 CHECK(*category == TypeCategory::Integer);
1187 resultType =
1188 DynamicType{TypeCategory::Integer, defaults.subscriptIntegerKind()};
peter klausleref9dd9d2018-10-17 22:09:481189 } else {
1190 CHECK(kindDummyArg->optionality ==
1191 Optionality::defaultsToDefaultForResult);
peter klausler25e6f032019-05-03 18:29:151192 resultType = DynamicType{*category, defaults.GetDefaultKind(*category)};
peter klauslerf7f2a732018-10-09 19:07:291193 }
peter klausleref9dd9d2018-10-17 22:09:481194 break;
1195 case KindCode::likeMultiply:
1196 CHECK(dummies >= 2);
1197 CHECK(actualForDummy[0] != nullptr);
1198 CHECK(actualForDummy[1] != nullptr);
1199 resultType = actualForDummy[0]->GetType()->ResultTypeForMultiply(
1200 *actualForDummy[1]->GetType());
1201 break;
peter klausler8e932262019-07-01 20:22:221202 case KindCode::subscript:
1203 CHECK(result.categorySet == IntType);
1204 CHECK(*category == TypeCategory::Integer);
1205 resultType =
1206 DynamicType{TypeCategory::Integer, defaults.subscriptIntegerKind()};
1207 break;
peter klausleref9dd9d2018-10-17 22:09:481208 case KindCode::typeless:
1209 case KindCode::teamType:
1210 case KindCode::any:
1211 case KindCode::kindArg:
1212 case KindCode::dimArg:
1213 common::die(
1214 "INTERNAL: bad KindCode appears on intrinsic '%s' result", name);
1215 break;
1216 default: CRASH_NO_CASE;
peter klauslera70f5962018-10-04 20:43:331217 }
peter klausler25e6f032019-05-03 18:29:151218 } else {
1219 if (!call.isSubroutineCall) {
1220 return std::nullopt;
1221 }
1222 CHECK(result.kindCode == KindCode::none);
peter klauslera70f5962018-10-04 20:43:331223 }
1224
peter klauslerf7f2a732018-10-09 19:07:291225 // At this point, the call is acceptable.
peter klauslera70f5962018-10-04 20:43:331226 // Determine the rank of the function result.
1227 int resultRank{0};
1228 switch (rank) {
1229 case Rank::elemental: resultRank = elementalRank; break;
1230 case Rank::scalar: resultRank = 0; break;
1231 case Rank::vector: resultRank = 1; break;
1232 case Rank::matrix: resultRank = 2; break;
peter klauslerf7f2a732018-10-09 19:07:291233 case Rank::conformable:
1234 CHECK(arrayArg != nullptr);
1235 resultRank = arrayArg->Rank();
1236 break;
peter klauslera70f5962018-10-04 20:43:331237 case Rank::dimReduced:
1238 CHECK(arrayArg != nullptr);
peter klauslera62636f2018-10-08 22:35:191239 resultRank = hasDimArg ? arrayArg->Rank() - 1 : 0;
peter klauslera70f5962018-10-04 20:43:331240 break;
peter klausler00e128e2019-06-25 20:07:321241 case Rank::dimRemoved:
1242 CHECK(arrayArg != nullptr);
1243 resultRank = arrayArg->Rank() - 1;
1244 break;
peter klauslera70f5962018-10-04 20:43:331245 case Rank::rankPlus1:
1246 CHECK(knownArg != nullptr);
peter klauslera62636f2018-10-08 22:35:191247 resultRank = knownArg->Rank() + 1;
peter klauslera70f5962018-10-04 20:43:331248 break;
1249 case Rank::shaped:
peter klauslerb65572d2019-04-03 23:04:131250 CHECK(shapeArgSize.has_value());
1251 resultRank = *shapeArgSize;
peter klauslera70f5962018-10-04 20:43:331252 break;
peter klauslercb308d32018-10-05 18:32:541253 case Rank::elementalOrBOZ:
peter klauslera70f5962018-10-04 20:43:331254 case Rank::shape:
1255 case Rank::array:
1256 case Rank::known:
1257 case Rank::anyOrAssumedRank:
peter klauslerad9aede2018-10-11 21:51:141258 case Rank::reduceOperation:
peter klauslera70f5962018-10-04 20:43:331259 common::die("INTERNAL: bad Rank code on intrinsic '%s' result", name);
1260 break;
1261 default: CRASH_NO_CASE;
1262 }
1263 CHECK(resultRank >= 0);
1264
peter klausleref9dd9d2018-10-17 22:09:481265 // Rearrange the actual arguments into dummy argument order.
1266 ActualArguments rearranged(dummies);
peter klausler84ea49d2018-10-18 17:50:551267 for (std::size_t j{0}; j < dummies; ++j) {
peter klausleref9dd9d2018-10-17 22:09:481268 if (ActualArgument * arg{actualForDummy[j]}) {
peter klausler84ea49d2018-10-18 17:50:551269 rearranged[j] = std::move(*arg);
peter klausleref9dd9d2018-10-17 22:09:481270 }
1271 }
1272
peter klausler25e6f032019-05-03 18:29:151273 // Characterize the specific intrinsic function.
1274 characteristics::TypeAndShape typeAndShape{resultType.value(), resultRank};
1275 characteristics::FunctionResult funcResult{std::move(typeAndShape)};
1276 characteristics::DummyArguments dummyArgs;
1277 std::optional<int> sameDummyArg;
1278 for (std::size_t j{0}; j < dummies; ++j) {
1279 const IntrinsicDummyArgument &d{dummy[std::min(j, dummyArgPatterns - 1)]};
1280 if (const auto &arg{rearranged[j]}) {
peter klauslerd29530e2019-05-21 23:58:461281 const Expr<SomeType> *expr{arg->UnwrapExpr()};
peter klausler25e6f032019-05-03 18:29:151282 CHECK(expr != nullptr);
1283 std::optional<characteristics::TypeAndShape> typeAndShape;
1284 if (auto type{expr->GetType()}) {
1285 if (auto shape{GetShape(context, *expr)}) {
1286 typeAndShape.emplace(*type, std::move(*shape));
1287 } else {
1288 typeAndShape.emplace(*type);
1289 }
1290 } else {
1291 typeAndShape.emplace(DynamicType::TypelessIntrinsicArgument());
1292 }
1293 dummyArgs.emplace_back(
1294 characteristics::DummyDataObject{std::move(typeAndShape.value())});
1295 if (d.typePattern.kindCode == KindCode::same &&
1296 !sameDummyArg.has_value()) {
1297 sameDummyArg = j;
1298 }
1299 } else {
1300 // optional argument is absent
1301 CHECK(d.optionality != Optionality::required);
1302 if (d.typePattern.kindCode == KindCode::same) {
1303 dummyArgs.emplace_back(dummyArgs[sameDummyArg.value()]);
1304 } else {
1305 auto category{d.typePattern.categorySet.LeastElement().value()};
1306 characteristics::TypeAndShape typeAndShape{
1307 DynamicType{category, defaults.GetDefaultKind(category)}};
1308 dummyArgs.emplace_back(
1309 characteristics::DummyDataObject{std::move(typeAndShape)});
1310 }
1311 std::get<characteristics::DummyDataObject>(dummyArgs.back())
1312 .attrs.set(characteristics::DummyDataObject::Attr::Optional);
1313 }
1314 }
1315 characteristics::Procedure::Attrs attrs;
1316 if (elementalRank > 0) {
1317 attrs.set(characteristics::Procedure::Attr::Elemental);
1318 }
1319 characteristics::Procedure chars{
1320 std::move(funcResult), std::move(dummyArgs), attrs};
1321
1322 return SpecificCall{
1323 SpecificIntrinsic{name, std::move(chars)}, std::move(rearranged)};
peter klauslera70f5962018-10-04 20:43:331324}
1325
peter klauslerba56b912019-02-22 23:45:301326class IntrinsicProcTable::Implementation {
1327public:
peter klauslerf9d6c0a2019-01-18 20:40:471328 explicit Implementation(const common::IntrinsicTypeDefaultKinds &dfts)
peter klauslerba56b912019-02-22 23:45:301329 : defaults_{dfts} {
peter klauslera70f5962018-10-04 20:43:331330 for (const IntrinsicInterface &f : genericIntrinsicFunction) {
peter klauslerba56b912019-02-22 23:45:301331 genericFuncs_.insert(std::make_pair(std::string{f.name}, &f));
peter klauslera70f5962018-10-04 20:43:331332 }
1333 for (const SpecificIntrinsicInterface &f : specificIntrinsicFunction) {
peter klauslerba56b912019-02-22 23:45:301334 specificFuncs_.insert(std::make_pair(std::string{f.name}, &f));
peter klauslera70f5962018-10-04 20:43:331335 }
1336 }
peter klausler42b33da2018-09-29 00:02:111337
peter klauslerf9535832019-02-26 22:26:281338 bool IsIntrinsic(const std::string &) const;
1339
peter klausler25e6f032019-05-03 18:29:151340 std::optional<SpecificCall> Probe(const CallCharacteristics &,
1341 ActualArguments &, FoldingContext &, const IntrinsicProcTable &) const;
peter klausler75a32092018-10-05 16:57:531342
peter klauslerba56b912019-02-22 23:45:301343 std::optional<UnrestrictedSpecificIntrinsicFunctionInterface>
1344 IsUnrestrictedSpecificIntrinsicFunction(const std::string &) const;
1345
peter klausler7bda1b32018-10-12 23:01:551346 std::ostream &Dump(std::ostream &) const;
peter klauslerba56b912019-02-22 23:45:301347
1348private:
peter klausler25e6f032019-05-03 18:29:151349 DynamicType GetSpecificType(const TypePattern &) const;
1350 SpecificCall HandleNull(
1351 ActualArguments &, FoldingContext &, const IntrinsicProcTable &) const;
1352
peter klauslerba56b912019-02-22 23:45:301353 common::IntrinsicTypeDefaultKinds defaults_;
1354 std::multimap<std::string, const IntrinsicInterface *> genericFuncs_;
1355 std::multimap<std::string, const SpecificIntrinsicInterface *> specificFuncs_;
peter klausler42b33da2018-09-29 00:02:111356};
1357
peter klauslerf9535832019-02-26 22:26:281358bool IntrinsicProcTable::Implementation::IsIntrinsic(
1359 const std::string &name) const {
1360 auto specificRange{specificFuncs_.equal_range(name)};
1361 if (specificRange.first != specificRange.second) {
1362 return true;
1363 }
1364 auto genericRange{genericFuncs_.equal_range(name)};
1365 if (genericRange.first != genericRange.second) {
1366 return true;
1367 }
1368 // special cases
1369 return name == "null"; // TODO more
1370}
1371
peter klausler25e6f032019-05-03 18:29:151372// The NULL() intrinsic is a special case.
1373SpecificCall IntrinsicProcTable::Implementation::HandleNull(
1374 ActualArguments &arguments, FoldingContext &context,
1375 const IntrinsicProcTable &intrinsics) const {
1376 if (!arguments.empty()) {
1377 if (arguments.size() > 1) {
1378 context.messages().Say("Too many arguments to NULL()"_err_en_US);
1379 } else if (arguments[0].has_value() && arguments[0]->keyword.has_value() &&
1380 arguments[0]->keyword->ToString() != "mold") {
1381 context.messages().Say("Unknown argument '%s' to NULL()"_err_en_US,
peter klauslerec6cf762019-05-06 16:33:451382 arguments[0]->keyword->ToString());
peter klausler25e6f032019-05-03 18:29:151383 } else {
peter klauslerd29530e2019-05-21 23:58:461384 if (Expr<SomeType> * mold{arguments[0]->UnwrapExpr()}) {
peter klausler25e6f032019-05-03 18:29:151385 if (IsAllocatableOrPointer(*mold)) {
1386 characteristics::DummyArguments args;
1387 std::optional<characteristics::FunctionResult> fResult;
1388 if (IsProcedurePointer(*mold)) {
1389 // MOLD= procedure pointer
1390 const Symbol *last{GetLastSymbol(*mold)};
1391 CHECK(last != nullptr);
1392 auto procPointer{
1393 characteristics::Procedure::Characterize(*last, intrinsics)};
1394 characteristics::DummyProcedure dp{
1395 common::Clone(procPointer.value())};
1396 args.emplace_back(std::move(dp));
1397 fResult.emplace(std::move(procPointer.value()));
1398 } else if (auto type{mold->GetType()}) {
1399 // MOLD= object pointer
1400 std::optional<characteristics::TypeAndShape> typeAndShape;
1401 if (auto shape{GetShape(context, *mold)}) {
1402 typeAndShape.emplace(*type, std::move(*shape));
1403 } else {
1404 typeAndShape.emplace(*type);
1405 }
1406 characteristics::DummyDataObject ddo{typeAndShape.value()};
1407 args.emplace_back(std::move(ddo));
1408 fResult.emplace(std::move(*typeAndShape));
1409 } else {
1410 context.messages().Say(
1411 "MOLD= argument to NULL() lacks type"_err_en_US);
1412 }
1413 fResult->attrs.set(characteristics::FunctionResult::Attr::Pointer);
1414 characteristics::Procedure::Attrs attrs;
1415 attrs.set(characteristics::Procedure::Attr::NullPointer);
1416 characteristics::Procedure chars{
1417 std::move(*fResult), std::move(args), attrs};
1418 return SpecificCall{SpecificIntrinsic{"null"s, std::move(chars)},
1419 std::move(arguments)};
1420 }
1421 }
1422 context.messages().Say(
1423 "MOLD= argument to NULL() must be a pointer or allocatable"_err_en_US);
1424 }
1425 }
1426 characteristics::Procedure::Attrs attrs;
1427 attrs.set(characteristics::Procedure::Attr::NullPointer);
1428 arguments.clear();
1429 return SpecificCall{
1430 SpecificIntrinsic{"null"s,
1431 characteristics::Procedure{characteristics::DummyArguments{}, attrs}},
1432 std::move(arguments)};
1433}
1434
peter klausler4f2c8fa2019-06-19 18:50:071435// Applies any semantic checks peculiar to an intrinsic.
1436static bool ApplySpecificChecks(
1437 SpecificCall &call, parser::ContextualMessages &messages) {
1438 bool ok{true};
1439 const std::string &name{call.specificIntrinsic.name};
1440 if (name == "allocated") {
1441 if (const auto &arg{call.arguments[0]}) {
1442 if (const auto *expr{arg->UnwrapExpr()}) {
1443 if (const Symbol * symbol{GetLastSymbol(*expr)}) {
1444 ok = symbol->has<semantics::ObjectEntityDetails>() &&
1445 symbol->attrs().test(semantics::Attr::ALLOCATABLE);
1446 }
1447 }
1448 }
1449 if (!ok) {
1450 messages.Say(
1451 "Argument of ALLOCATED() must be an ALLOCATABLE object or component"_err_en_US);
1452 }
peter klauslera0e50522019-06-21 21:04:401453 } else if (name == "associated") {
1454 if (const auto &arg{call.arguments[0]}) {
1455 if (const auto *expr{arg->UnwrapExpr()}) {
1456 if (const Symbol * symbol{GetLastSymbol(*expr)}) {
1457 ok = symbol->attrs().test(semantics::Attr::POINTER);
1458 // TODO: validate the TARGET= argument vs. the pointer
1459 }
1460 }
1461 }
1462 if (!ok) {
1463 messages.Say(
1464 "Arguments of ASSOCIATED() must be a POINTER and an optional valid target"_err_en_US);
1465 }
peter klausler8e932262019-07-01 20:22:221466 } else if (name == "loc") {
1467 if (const auto &arg{call.arguments[0]}) {
1468 ok = GetLastSymbol(arg->UnwrapExpr()) != nullptr;
1469 }
1470 if (!ok) {
1471 messages.Say(
1472 "Argument of LOC() must be an object or procedure"_err_en_US);
1473 }
peter klausler4f2c8fa2019-06-19 18:50:071474 } else if (name == "present") {
1475 if (const auto &arg{call.arguments[0]}) {
1476 if (const auto *expr{arg->UnwrapExpr()}) {
1477 if (const Symbol * symbol{UnwrapWholeSymbolDataRef(*expr)}) {
1478 ok = symbol->attrs().test(semantics::Attr::OPTIONAL);
1479 }
1480 }
1481 }
1482 if (!ok) {
1483 messages.Say(
1484 "Argument of PRESENT() must be the name of an OPTIONAL dummy argument"_err_en_US);
1485 }
1486 }
1487 return ok;
peter klauslercedf98c2019-06-19 19:37:491488}
peter klausler4f2c8fa2019-06-19 18:50:071489
peter klauslercb308d32018-10-05 18:32:541490// Probe the configured intrinsic procedure pattern tables in search of a
1491// match for a given procedure reference.
peter klausleref9dd9d2018-10-17 22:09:481492std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
1493 const CallCharacteristics &call, ActualArguments &arguments,
peter klausler25e6f032019-05-03 18:29:151494 FoldingContext &context, const IntrinsicProcTable &intrinsics) const {
peter klausler75a32092018-10-05 16:57:531495 if (call.isSubroutineCall) {
1496 return std::nullopt; // TODO
1497 }
peter klausler146e13c2019-04-18 21:11:151498 parser::Messages *finalBuffer{context.messages().messages()};
peter klausler25e6f032019-05-03 18:29:151499 // Special case: NULL()
peter klausler737fe292019-06-26 22:30:531500 // All special cases handled here before the table probes below must
1501 // also be caught as special names in IsIntrinsic().
peter klausler59342b02019-05-13 16:33:181502 if (call.name == "null") {
peter klausler25e6f032019-05-03 18:29:151503 parser::Messages nullBuffer;
1504 parser::ContextualMessages nullErrors{
1505 call.name, finalBuffer ? &nullBuffer : nullptr};
1506 FoldingContext nullContext{context, nullErrors};
1507 auto result{HandleNull(arguments, nullContext, intrinsics)};
1508 if (finalBuffer != nullptr) {
1509 finalBuffer->Annex(std::move(nullBuffer));
1510 }
1511 return result;
1512 }
peter klausler8a326cb2019-06-05 22:40:591513 // Probe the generic intrinsic function table first.
1514 parser::Messages localBuffer;
peter klausler59342b02019-05-13 16:33:181515 parser::ContextualMessages localMessages{
1516 call.name, finalBuffer ? &localBuffer : nullptr};
1517 FoldingContext localContext{context, localMessages};
peter klausler75a32092018-10-05 16:57:531518 std::string name{call.name.ToString()};
peter klausler62425d62018-10-12 00:01:311519 parser::Messages genericBuffer;
peter klauslerba56b912019-02-22 23:45:301520 auto genericRange{genericFuncs_.equal_range(name)};
peter klausler75a32092018-10-05 16:57:531521 for (auto iter{genericRange.first}; iter != genericRange.second; ++iter) {
peter klausler5774f0a2019-06-04 17:50:341522 CHECK(localBuffer.empty());
peter klausleref9dd9d2018-10-17 22:09:481523 if (auto specificCall{
peter klausler59342b02019-05-13 16:33:181524 iter->second->Match(call, defaults_, arguments, localContext)}) {
peter klausler4f2c8fa2019-06-19 18:50:071525 ApplySpecificChecks(*specificCall, localMessages);
peter klausler59342b02019-05-13 16:33:181526 if (finalBuffer != nullptr) {
1527 finalBuffer->Annex(std::move(localBuffer));
1528 }
peter klausleref9dd9d2018-10-17 22:09:481529 return specificCall;
peter klausler59342b02019-05-13 16:33:181530 } else {
1531 genericBuffer.Annex(std::move(localBuffer));
peter klausler75a32092018-10-05 16:57:531532 }
1533 }
peter klausler8a326cb2019-06-05 22:40:591534 // Probe the specific intrinsic function table next.
1535 // Each specific intrinsic maps to a generic intrinsic.
1536 parser::Messages specificBuffer;
1537 auto specificRange{specificFuncs_.equal_range(name)};
1538 for (auto specIter{specificRange.first}; specIter != specificRange.second;
1539 ++specIter) {
1540 // We only need to check the cases with distinct generic names.
1541 if (const char *genericName{specIter->second->generic}) {
1542 auto genericRange{genericFuncs_.equal_range(genericName)};
1543 for (auto genIter{genericRange.first}; genIter != genericRange.second;
1544 ++genIter) {
1545 CHECK(localBuffer.empty());
1546 if (auto specificCall{genIter->second->Match(
1547 call, defaults_, arguments, localContext)}) {
1548 specificCall->specificIntrinsic.name = genericName;
1549 specificCall->specificIntrinsic.isRestrictedSpecific =
1550 specIter->second->isRestrictedSpecific;
1551 if (finalBuffer != nullptr) {
1552 finalBuffer->Annex(std::move(localBuffer));
1553 }
1554 if (specIter->second->forceResultType) {
1555 // Force the result type on AMAX0/1, MIN0/1, &c.
1556 TypeCategory category{TypeCategory::Integer};
1557 switch (specIter->second->result.kindCode) {
1558 case KindCode::defaultIntegerKind: break;
1559 case KindCode::defaultRealKind:
1560 category = TypeCategory::Real;
1561 break;
1562 default: CRASH_NO_CASE;
1563 }
1564 DynamicType newType{category, defaults_.GetDefaultKind(category)};
1565 specificCall->specificIntrinsic.characteristics.value()
1566 .functionResult.value()
1567 .SetType(newType);
1568 }
peter klauslera0e50522019-06-21 21:04:401569 // TODO test feature AdditionalIntrinsics, warn on nonstandard
1570 // specifics with DoublePrecisionComplex arguments.
peter klausler8a326cb2019-06-05 22:40:591571 return specificCall;
1572 } else {
1573 specificBuffer.Annex(std::move(localBuffer));
1574 }
1575 }
1576 }
1577 }
peter klausler25e6f032019-05-03 18:29:151578 // No match; report the right errors, if any
peter klausler146e13c2019-04-18 21:11:151579 if (finalBuffer != nullptr) {
peter klausler8a326cb2019-06-05 22:40:591580 if (specificBuffer.empty()) {
peter klausler7bda1b32018-10-12 23:01:551581 finalBuffer->Annex(std::move(genericBuffer));
peter klausler8a326cb2019-06-05 22:40:591582 } else {
1583 finalBuffer->Annex(std::move(specificBuffer));
peter klausler62425d62018-10-12 00:01:311584 }
peter klauslercb308d32018-10-05 18:32:541585 }
peter klausler75a32092018-10-05 16:57:531586 return std::nullopt;
1587}
1588
peter klauslerba56b912019-02-22 23:45:301589std::optional<UnrestrictedSpecificIntrinsicFunctionInterface>
1590IntrinsicProcTable::Implementation::IsUnrestrictedSpecificIntrinsicFunction(
1591 const std::string &name) const {
1592 auto specificRange{specificFuncs_.equal_range(name)};
1593 for (auto iter{specificRange.first}; iter != specificRange.second; ++iter) {
1594 const SpecificIntrinsicInterface &specific{*iter->second};
1595 if (!specific.isRestrictedSpecific) {
peter klausler25e6f032019-05-03 18:29:151596 std::string genericName{name};
peter klauslerba56b912019-02-22 23:45:301597 if (specific.generic != nullptr) {
peter klausler25e6f032019-05-03 18:29:151598 genericName = std::string(specific.generic);
peter klauslerba56b912019-02-22 23:45:301599 }
peter klausler25e6f032019-05-03 18:29:151600 characteristics::FunctionResult fResult{GetSpecificType(specific.result)};
1601 characteristics::DummyArguments args;
peter klauslerf9535832019-02-26 22:26:281602 int dummies{specific.CountArguments()};
1603 for (int j{0}; j < dummies; ++j) {
1604 characteristics::DummyDataObject dummy{
1605 GetSpecificType(specific.dummy[j].typePattern)};
1606 dummy.intent = common::Intent::In;
peter klausler25e6f032019-05-03 18:29:151607 args.emplace_back(std::move(dummy));
peter klauslerf9535832019-02-26 22:26:281608 }
peter klausler25e6f032019-05-03 18:29:151609 characteristics::Procedure::Attrs attrs;
1610 attrs.set(characteristics::Procedure::Attr::Pure)
1611 .set(characteristics::Procedure::Attr::Elemental);
1612 characteristics::Procedure chars{
1613 std::move(fResult), std::move(args), attrs};
1614 return UnrestrictedSpecificIntrinsicFunctionInterface{
1615 std::move(chars), genericName};
peter klauslerba56b912019-02-22 23:45:301616 }
1617 }
1618 return std::nullopt;
1619}
1620
1621DynamicType IntrinsicProcTable::Implementation::GetSpecificType(
1622 const TypePattern &pattern) const {
1623 const CategorySet &set{pattern.categorySet};
1624 CHECK(set.count() == 1);
1625 TypeCategory category{set.LeastElement().value()};
1626 return DynamicType{category, defaults_.GetDefaultKind(category)};
1627}
1628
peter klauslera62636f2018-10-08 22:35:191629IntrinsicProcTable::~IntrinsicProcTable() {
peter klauslercb308d32018-10-05 18:32:541630 // Discard the configured tables.
peter klausler42b33da2018-09-29 00:02:111631 delete impl_;
1632 impl_ = nullptr;
1633}
1634
peter klauslera62636f2018-10-08 22:35:191635IntrinsicProcTable IntrinsicProcTable::Configure(
peter klauslerf9d6c0a2019-01-18 20:40:471636 const common::IntrinsicTypeDefaultKinds &defaults) {
peter klauslera62636f2018-10-08 22:35:191637 IntrinsicProcTable result;
1638 result.impl_ = new IntrinsicProcTable::Implementation(defaults);
peter klausler42b33da2018-09-29 00:02:111639 return result;
1640}
1641
peter klauslerf9535832019-02-26 22:26:281642bool IntrinsicProcTable::IsIntrinsic(const std::string &name) const {
1643 CHECK(impl_ != nullptr || !"IntrinsicProcTable: not configured");
1644 return impl_->IsIntrinsic(name);
1645}
1646
peter klausleref9dd9d2018-10-17 22:09:481647std::optional<SpecificCall> IntrinsicProcTable::Probe(
1648 const CallCharacteristics &call, ActualArguments &arguments,
peter klausler146e13c2019-04-18 21:11:151649 FoldingContext &context) const {
peter klauslera62636f2018-10-08 22:35:191650 CHECK(impl_ != nullptr || !"IntrinsicProcTable: not configured");
peter klausler25e6f032019-05-03 18:29:151651 return impl_->Probe(call, arguments, context, *this);
peter klausler42b33da2018-09-29 00:02:111652}
peter klauslerad9aede2018-10-11 21:51:141653
peter klauslerba56b912019-02-22 23:45:301654std::optional<UnrestrictedSpecificIntrinsicFunctionInterface>
1655IntrinsicProcTable::IsUnrestrictedSpecificIntrinsicFunction(
1656 const std::string &name) const {
1657 CHECK(impl_ != nullptr || !"IntrinsicProcTable: not configured");
1658 return impl_->IsUnrestrictedSpecificIntrinsicFunction(name);
1659}
1660
peter klausler7bda1b32018-10-12 23:01:551661std::ostream &TypePattern::Dump(std::ostream &o) const {
1662 if (categorySet == AnyType) {
1663 o << "any type";
1664 } else {
1665 const char *sep = "";
1666 auto set{categorySet};
1667 while (auto least{set.LeastElement()}) {
1668 o << sep << EnumToString(*least);
1669 sep = " or ";
1670 set.reset(*least);
1671 }
1672 }
1673 o << '(' << EnumToString(kindCode) << ')';
1674 return o;
1675}
1676
1677std::ostream &IntrinsicDummyArgument::Dump(std::ostream &o) const {
1678 if (keyword) {
1679 o << keyword << '=';
1680 }
1681 return typePattern.Dump(o)
1682 << ' ' << EnumToString(rank) << ' ' << EnumToString(optionality);
1683}
1684
1685std::ostream &IntrinsicInterface::Dump(std::ostream &o) const {
1686 o << name;
1687 char sep{'('};
1688 for (const auto &d : dummy) {
1689 if (d.typePattern.kindCode == KindCode::none) {
1690 break;
1691 }
1692 d.Dump(o << sep);
1693 sep = ',';
1694 }
1695 if (sep == '(') {
1696 o << "()";
1697 }
1698 return result.Dump(o << " -> ") << ' ' << EnumToString(rank);
1699}
1700
1701std::ostream &IntrinsicProcTable::Implementation::Dump(std::ostream &o) const {
1702 o << "generic intrinsic functions:\n";
peter klauslerba56b912019-02-22 23:45:301703 for (const auto &iter : genericFuncs_) {
peter klausler7bda1b32018-10-12 23:01:551704 iter.second->Dump(o << iter.first << ": ") << '\n';
1705 }
1706 o << "specific intrinsic functions:\n";
peter klauslerba56b912019-02-22 23:45:301707 for (const auto &iter : specificFuncs_) {
peter klausler7bda1b32018-10-12 23:01:551708 iter.second->Dump(o << iter.first << ": ");
1709 if (const char *g{iter.second->generic}) {
1710 o << " -> " << g;
1711 }
1712 o << '\n';
1713 }
1714 return o;
1715}
1716
1717std::ostream &IntrinsicProcTable::Dump(std::ostream &o) const {
1718 return impl_->Dump(o);
1719}
Jean Perierf7e7cb32018-10-25 12:55:231720}