[flang-commits] [clang] [flang] [flang][semantics] Add a flag to relax some of the semantic constraints on C_LOC (PR #195112)

Andre Kuhlenschmidt via flang-commits flang-commits at lists.llvm.org
Thu Apr 30 08:49:26 PDT 2026


https://github.com/akuhlens created https://github.com/llvm/llvm-project/pull/195112

This PR adds a flag that downgrades some of the semantic constraints on C_LOC so that it can be used more like LOC. Without the flag behavior is unmodified, with the flag the constraint that the address be object pointer or target is removed. There are other constraints we might consider relaxing, but I think this is a start.

>From 307e315b24cd66b415a7ab790be0329ddc5acd1e Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 30 Apr 2026 08:29:40 -0700
Subject: [PATCH] initial commit

---
 clang/include/clang/Options/Options.td        |  2 +
 .../include/flang/Support/Fortran-features.h  |  4 +-
 flang/lib/Evaluate/intrinsics.cpp             | 47 +++++++++++++------
 flang/lib/Frontend/CompilerInvocation.cpp     |  6 +++
 flang/lib/Support/Fortran-features.cpp        |  1 +
 5 files changed, 44 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c16c41ad4057d..d8780351dbbee 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -7676,6 +7676,8 @@ defm ppc_native_vec_elem_order: BoolOptionWithoutMarshalling<"f", "ppc-native-ve
   PosFlag<SetTrue, [], [ClangOption], "Specifies PowerPC native vector element order (default)">,
   NegFlag<SetFalse, [], [ClangOption], "Specifies PowerPC non-native vector element order">>;
 defm unsigned : OptInFC1FFlag<"unsigned", "Enables UNSIGNED type">;
+defm relaxed_c_loc : OptInFC1FFlag<"relaxed-c-loc",
+  "Relax C_LOC() argument restrictions, allowing non-target non-pointer arguments">;
 
 def fno_automatic : Flag<["-"], "fno-automatic">, Group<f_Group>,
   HelpText<"Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE">;
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 4f6cd02fd35ef..0b54c9104a6e5 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -59,7 +59,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     PointerPassObject, MultipleIdenticalDATA,
     DefaultStructConstructorNullPointer, AssumedRankIoItem,
     MultipleProgramUnitsOnSameLine, AllocatedForAssociated,
-    OpenMPThreadprivateEquivalence)
+    OpenMPThreadprivateEquivalence, RelaxedCLoc)
 
 // Portability and suspicious usage warnings
 ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
@@ -85,7 +85,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
     RealConstantWidening, VolatileOrAsynchronousTemporary, UnusedVariable,
     UsedUndefinedVariable, BadValueInDeadCode, AssumedTypeSizeDummy,
     MisplacedIgnoreTKR, NamelistParameter, ImpureFinalInPure,
-    IgnoredNoReallocateLHS)
+    IgnoredNoReallocateLHS, CLoc)
 
 using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
 using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 84cd2288fcd0b..79ea6414666e3 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -3498,11 +3498,26 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
     CHECK(arguments.size() == 1);
     CheckForCoindexedObject(context.messages(), arguments[0], "c_loc", "x");
     const auto *expr{arguments[0].value().UnwrapExpr()};
+    SpecificCall specificCall{
+        SpecificIntrinsic{"__builtin_c_loc"s,
+            characteristics::Procedure{
+                characteristics::FunctionResult{DynamicType{
+                    GetBuiltinDerivedType(builtinsScope_, "__builtin_c_ptr")}},
+                characteristics::DummyArguments{},
+                characteristics::Procedure::Attrs{
+                    characteristics::Procedure::Attr::Pure}}},
+        {/*arguments*/}};
     if (expr &&
         !(IsObjectPointer(*expr) ||
             (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 (context.languageFeatures().IsEnabled(
+              common::LanguageFeature::RelaxedCLoc)) {
+        context.Warn(common::UsageWarning::CLoc, arguments[0]->sourceLocation(),
+            "C_LOC() argument must be a data pointer or target"_warn_en_US);
+      } else {
+        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)}) {
@@ -3539,20 +3554,24 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
               "C_LOC() argument has non-interoperable intrinsic type or kind"_warn_en_US);
         }
       }
-
       characteristics::DummyDataObject ddo{std::move(*typeAndShape)};
       ddo.intent = common::Intent::In;
-      return SpecificCall{
-          SpecificIntrinsic{"__builtin_c_loc"s,
-              characteristics::Procedure{
-                  characteristics::FunctionResult{
-                      DynamicType{GetBuiltinDerivedType(
-                          builtinsScope_, "__builtin_c_ptr")}},
-                  characteristics::DummyArguments{
-                      characteristics::DummyArgument{"x"s, std::move(ddo)}},
-                  characteristics::Procedure::Attrs{
-                      characteristics::Procedure::Attr::Pure}}},
-          std::move(arguments)};
+      specificCall.specificIntrinsic.characteristics.value()
+          .dummyArguments.emplace_back(std::move(ddo));
+      specificCall.arguments.emplace_back(std::move(arguments[0]));
+      return specificCall;
+    } else if (expr && IsProcedurePointer(*expr)) {
+      auto dummyArg{characteristics::DummyArgument::FromActual(
+          "x", *expr, context, /*forImplicitInterface=*/false)};
+      CHECK(dummyArg.has_value());
+      dummyArg->intent = common::Intent::In;
+      specificCall.specificIntrinsic.characteristics.value()
+          .dummyArguments.emplace_back(std::move(*dummyArg));
+      specificCall.arguments.emplace_back(std::move(arguments[0]));
+      return specificCall;
+    } else {
+      context.messages().Say(arguments[0]->sourceLocation(),
+          "C_LOC() argument must be a object or procedure"_err_en_US);
     }
   }
   return std::nullopt;
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index a8cb681c1004d..35d6521563e20 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -869,6 +869,12 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
                        args.hasFlag(clang::options::OPT_funsigned,
                                     clang::options::OPT_fno_unsigned, false));
 
+  // -f{no-}relaxed-c-loc
+  opts.features.Enable(Fortran::common::LanguageFeature::RelaxedCLoc,
+                       args.hasFlag(clang::options::OPT_frelaxed_c_loc,
+                                    clang::options::OPT_fno_relaxed_c_loc,
+                                    false));
+
   // -f{no-}xor-operator
   opts.features.Enable(Fortran::common::LanguageFeature::XOROperator,
                        args.hasFlag(clang::options::OPT_fxor_operator,
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 67cdb8d67c8af..a6ac306315518 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -163,6 +163,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
   warnUsage_.set(UsageWarning::MisplacedIgnoreTKR);
   warnUsage_.set(UsageWarning::ImpureFinalInPure);
   warnUsage_.set(UsageWarning::IgnoredNoReallocateLHS);
+  warnUsage_.set(UsageWarning::CLoc);
   warnLanguage_.set(LanguageFeature::OpenMPThreadprivateEquivalence);
 }
 



More information about the flang-commits mailing list