SpecificCall HandleNull(ActualArguments &, FoldingContext &) const;
std::optional<SpecificCall> HandleC_F_Pointer(
ActualArguments &, FoldingContext &) const;
+ std::optional<SpecificCall> HandleC_Loc(
+ ActualArguments &, FoldingContext &) const;
const std::string &ResolveAlias(const std::string &name) const {
auto iter{aliases_.find(name)};
return iter == aliases_.end() ? name : iter->second;
return true;
}
// special cases
- return name == "null";
+ return name == "__builtin_c_loc" || name == "null";
}
bool IntrinsicProcTable::Implementation::IsIntrinsicSubroutine(
const std::string &name) const {
}
}
+static bool CheckForCoindexedObject(FoldingContext &context,
+ const std::optional<ActualArgument> &arg, const std::string &procName,
+ const std::string &argName) {
+ bool ok{true};
+ if (arg) {
+ if (ExtractCoarrayRef(arg->UnwrapExpr())) {
+ ok = false;
+ context.messages().Say(arg->sourceLocation(),
+ "'%s' argument to '%s' may not be a coindexed object"_err_en_US,
+ argName, procName);
+ }
+ }
+ return ok;
+}
+
+// Function C_LOC(X) from intrinsic module ISO_C_BINDING (18.2.3.6)
+std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
+ ActualArguments &arguments, FoldingContext &context) const {
+ static const char *const keywords[]{"x", nullptr};
+ if (CheckAndRearrangeArguments(arguments, context.messages(), keywords)) {
+ CHECK(arguments.size() == 1);
+ CheckForCoindexedObject(context, arguments[0], "c_loc", "x");
+ const auto *expr{arguments[0].value().UnwrapExpr()};
+ if (expr &&
+ !(IsObjectPointer(*expr, context) ||
+ (IsVariable(*expr) && GetLastTarget(GetSymbolVector(*expr))))) {
+ context.messages().Say(arguments[0]->sourceLocation(),
+ "C_LOC() argument must be a data pointer or target"_err_en_US);
+ }
+ if (auto typeAndShape{characteristics::TypeAndShape::Characterize(
+ arguments[0], context)}) {
+ if (expr && !IsContiguous(*expr, context).value_or(true)) {
+ context.messages().Say(arguments[0]->sourceLocation(),
+ "C_LOC() argument must be contiguous"_err_en_US);
+ }
+ if (auto constExtents{AsConstantExtents(context, typeAndShape->shape())};
+ constExtents && GetSize(*constExtents) == 0) {
+ context.messages().Say(arguments[0]->sourceLocation(),
+ "C_LOC() argument may not be a zero-sized array"_err_en_US);
+ }
+ if (!(typeAndShape->type().category() != TypeCategory::Derived ||
+ typeAndShape->type().IsAssumedType() ||
+ (!typeAndShape->type().IsPolymorphic() &&
+ CountNonConstantLenParameters(
+ typeAndShape->type().GetDerivedTypeSpec()) == 0))) {
+ context.messages().Say(arguments[0]->sourceLocation(),
+ "C_LOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter"_err_en_US);
+ } else if (typeAndShape->type().knownLength().value_or(1) == 0) {
+ context.messages().Say(arguments[0]->sourceLocation(),
+ "C_LOC() argument may not be zero-length character"_err_en_US);
+ } else if (typeAndShape->type().category() != TypeCategory::Derived &&
+ !IsInteroperableIntrinsicType(typeAndShape->type())) {
+ context.messages().Say(arguments[0]->sourceLocation(),
+ "C_LOC() argument has non-interoperable intrinsic type, kind, or length"_warn_en_US);
+ }
+
+ return SpecificCall{SpecificIntrinsic{"__builtin_c_loc"s,
+ characteristics::Procedure{
+ characteristics::FunctionResult{
+ DynamicType{GetBuiltinDerivedType(
+ builtinsScope_, "__builtin_c_ptr")}},
+ characteristics::DummyArguments{
+ characteristics::DummyArgument{"x"s,
+ characteristics::DummyDataObject{
+ std::move(*typeAndShape)}}},
+ characteristics::Procedure::Attrs{}}},
+ std::move(arguments)};
+ }
+ }
+ return std::nullopt;
+}
+
static bool CheckForNonPositiveValues(FoldingContext &context,
const ActualArgument &arg, const std::string &procName,
const std::string &argName) {
return ok;
}
-static bool CheckForCoindexedObject(FoldingContext &context,
- const std::optional<ActualArgument> &arg, const std::string &procName,
- const std::string &argName) {
- bool ok{true};
- if (arg) {
- if (ExtractCoarrayRef(arg->UnwrapExpr())) {
- ok = false;
- context.messages().Say(arg->sourceLocation(),
- "'%s' argument to '%s' may not be a coindexed object"_err_en_US,
- argName, procName);
- }
- }
- return ok;
-}
-
static bool CheckAtomicDefineAndRef(FoldingContext &context,
const std::optional<ActualArgument> &atomArg,
const std::optional<ActualArgument> &valueArg,
"RANDOM_SEED must have either 1 or no arguments"_err_en_US);
}
}
- } else if (call.name == "null") {
- return HandleNull(arguments, context);
+ } else { // function
+ if (call.name == "__builtin_c_loc") {
+ return HandleC_Loc(arguments, context);
+ } else if (call.name == "null") {
+ return HandleNull(arguments, context);
+ }
}
if (call.isSubroutineCall) {
--- /dev/null
+! RUN: %python %S/test_errors.py %s %flang_fc1
+module m
+ use iso_c_binding
+ type haslen(L)
+ integer, len :: L
+ end type
+ contains
+ subroutine test(assumedType, poly, nclen)
+ type(*), target :: assumedType
+ class(*), target :: poly
+ type(c_ptr) cp
+ real notATarget
+ procedure(sin), pointer :: pptr
+ real, target :: arr(3)
+ type(hasLen(1)), target :: clen
+ type(hasLen(*)), target :: nclen
+ character(2), target :: ch
+ !ERROR: C_LOC() argument must be a data pointer or target
+ cp = c_loc(notATarget)
+ !ERROR: C_LOC() argument must be a data pointer or target
+ cp = c_loc(pptr)
+ !ERROR: C_LOC() argument must be contiguous
+ cp = c_loc(arr(1:3:2))
+ !ERROR: C_LOC() argument may not be a zero-sized array
+ cp = c_loc(arr(3:1))
+ !ERROR: C_LOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter
+ cp = c_loc(poly)
+ cp = c_loc(clen) ! ok
+ !ERROR: C_LOC() argument must have an intrinsic type, assumed type, or non-polymorphic derived type with no non-constant length parameter
+ cp = c_loc(nclen)
+ !ERROR: C_LOC() argument may not be zero-length character
+ cp = c_loc(ch(2:1))
+ !WARNING: C_LOC() argument has non-interoperable intrinsic type, kind, or length
+ cp = c_loc(ch)
+ cp = c_loc(ch(1:1)) ! ok)
+ end
+end module