aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Evaluate/intrinsics.cpp
diff options
context:
space:
mode:
authorPeter Klausler <pklausler@nvidia.com>2023-04-21 10:03:17 -0700
committerPeter Klausler <pklausler@nvidia.com>2023-05-08 15:58:09 -0700
commita88cee1fd06dd633fc6551d242c55f4235d4862d (patch)
treeaa5d3dce880ab5fc28ab3f1e3eec7fe651c467df /flang/lib/Evaluate/intrinsics.cpp
parent5da7f30f24c4620c4f4425206fbdd0921d333dc0 (diff)
downloadllvm-a88cee1fd06dd633fc6551d242c55f4235d4862d.zip
llvm-a88cee1fd06dd633fc6551d242c55f4235d4862d.tar.gz
llvm-a88cee1fd06dd633fc6551d242c55f4235d4862d.tar.bz2
[flang] Semantics for ISO_C_BINDING's C_LOC()
Make __builtin_c_loc() into an intrinsic function and verify the special semantic requirements on its actual arguments. Differential Revision: https://reviews.llvm.org/D149988
Diffstat (limited to 'flang/lib/Evaluate/intrinsics.cpp')
-rw-r--r--flang/lib/Evaluate/intrinsics.cpp99
1 files changed, 81 insertions, 18 deletions
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 649d468..7b7ce78 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -2410,6 +2410,8 @@ private:
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;
@@ -2435,7 +2437,7 @@ bool IntrinsicProcTable::Implementation::IsIntrinsicFunction(
return true;
}
// special cases
- return name == "null";
+ return name == "__builtin_c_loc" || name == "null";
}
bool IntrinsicProcTable::Implementation::IsIntrinsicSubroutine(
const std::string &name) const {
@@ -2691,6 +2693,78 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
}
}
+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) {
@@ -2751,21 +2825,6 @@ static bool CheckDimAgainstCorank(SpecificCall &call, FoldingContext &context) {
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,
@@ -3013,8 +3072,12 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
"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) {