diff options
author | Peter Klausler <pklausler@nvidia.com> | 2023-04-21 10:03:17 -0700 |
---|---|---|
committer | Peter Klausler <pklausler@nvidia.com> | 2023-05-08 15:58:09 -0700 |
commit | a88cee1fd06dd633fc6551d242c55f4235d4862d (patch) | |
tree | aa5d3dce880ab5fc28ab3f1e3eec7fe651c467df /flang/lib/Evaluate/intrinsics.cpp | |
parent | 5da7f30f24c4620c4f4425206fbdd0921d333dc0 (diff) | |
download | llvm-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.cpp | 99 |
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) { |