effectiveKind, // for function results: same "kindArg", possibly defaulted
dimArg, // this argument is DIM=
likeMultiply, // for DOT_PRODUCT and MATMUL
+ subscript, // address-sized integer
)
struct TypePattern {
RealType, KindCode::doublePrecision};
static constexpr TypePattern DoublePrecisionComplex{
ComplexType, KindCode::doublePrecision};
+static constexpr TypePattern SubscriptInt{IntType, KindCode::subscript};
// Match any kind of some intrinsic or derived types
static constexpr TypePattern AnyInt{IntType, KindCode::any};
{"lgt", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
{"lle", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
{"llt", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
+ {"loc", {{"x", Anything, Rank::anyOrAssumedRank}}, SubscriptInt,
+ Rank::scalar},
{"log", {{"x", SameFloating}}, SameFloating},
{"log10", {{"x", SameReal}}, SameReal},
{"logical", {{"l", AnyLogical}, DefaultingKIND}, KINDLogical},
// TODO: Non-standard intrinsic functions
// AND, OR, XOR, LSHIFT, RSHIFT, SHIFT, ZEXT, IZEXT,
// COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL,
-// DCMPLX, EQV, NEQV, INT8, JINT, JNINT, KNINT, LOC,
+// DCMPLX, EQV, NEQV, INT8, JINT, JNINT, KNINT,
// QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM,
// INUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF,
// MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR
// IARG, IARGC, NARGS, NUMARG, BADDRESS, IADDR, CACHESIZE,
// EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC
// probably more (these are PGI + Intel, possibly incomplete)
+// TODO: Optionally warn on use of non-standard intrinsics:
+// LOC, probably others
// The following table contains the intrinsic functions listed in
// Tables 16.2 and 16.3 in Fortran 2018. The "unrestricted" functions
resultType = actualForDummy[0]->GetType()->ResultTypeForMultiply(
*actualForDummy[1]->GetType());
break;
+ case KindCode::subscript:
+ CHECK(result.categorySet == IntType);
+ CHECK(*category == TypeCategory::Integer);
+ resultType =
+ DynamicType{TypeCategory::Integer, defaults.subscriptIntegerKind()};
+ break;
case KindCode::typeless:
case KindCode::teamType:
case KindCode::any:
messages.Say(
"Arguments of ASSOCIATED() must be a POINTER and an optional valid target"_err_en_US);
}
+ } else if (name == "loc") {
+ if (const auto &arg{call.arguments[0]}) {
+ ok = GetLastSymbol(arg->UnwrapExpr()) != nullptr;
+ }
+ if (!ok) {
+ messages.Say(
+ "Argument of LOC() must be an object or procedure"_err_en_US);
+ }
} else if (name == "present") {
if (const auto &arg{call.arguments[0]}) {
if (const auto *expr{arg->UnwrapExpr()}) {
template<typename A> const semantics::Symbol *GetLastSymbol(const A &) {
return nullptr;
}
+template<typename... A> const semantics::Symbol *GetLastSymbol(const std::variant<A...> &);
+template<typename A> const semantics::Symbol *GetLastSymbol(const std::optional<A> &);
+template<typename A> const semantics::Symbol *GetLastSymbol(const A *);
inline const semantics::Symbol *GetLastSymbol(const Symbol &x) { return &x; }
inline const semantics::Symbol *GetLastSymbol(const Component &x) {
return &x.GetLastSymbol();
return GetLastSymbol(x.proc());
}
template<typename T> const semantics::Symbol *GetLastSymbol(const Expr<T> &x) {
- return std::visit([](const auto &y) { return GetLastSymbol(y); }, x.u);
+ return GetLastSymbol(x.u);
+}
+template<typename... A> const semantics::Symbol *GetLastSymbol(const std::variant<A...> &u) {
+ return std::visit([](const auto &x) { return GetLastSymbol(x); }, u);
}
template<typename A>
const semantics::Symbol *GetLastSymbol(const std::optional<A> &x) {
return nullptr;
}
}
+template<typename A> const semantics::Symbol *GetLastSymbol(const A *p) {
+ if (p != nullptr) {
+ return GetLastSymbol(*p);
+ } else {
+ return nullptr;
+ }
+}
// Convenience: If GetLastSymbol() succeeds on the argument, return its
// set of attributes, otherwise the empty set.