[flang-commits] [flang] c6bf92e - [flang][semantics] Add a flag to relax some of the semantic constraints on C_LOC (#195112)
via flang-commits
flang-commits at lists.llvm.org
Mon May 4 10:22:37 PDT 2026
Author: Andre Kuhlenschmidt
Date: 2026-05-04T17:22:31Z
New Revision: c6bf92e51d58d69e69101e2ca691cdab726d980c
URL: https://github.com/llvm/llvm-project/commit/c6bf92e51d58d69e69101e2ca691cdab726d980c
DIFF: https://github.com/llvm/llvm-project/commit/c6bf92e51d58d69e69101e2ca691cdab726d980c.diff
LOG: [flang][semantics] Add a flag to relax some of the semantic constraints on C_LOC (#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.
Added:
flang/test/Semantics/c_loc01-relaxed.f90
Modified:
clang/include/clang/Options/FlangOptions.td
flang/docs/Extensions.md
flang/include/flang/Support/Fortran-features.h
flang/lib/Evaluate/intrinsics.cpp
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Support/Fortran-features.cpp
flang/test/Semantics/c_loc01.f90
Removed:
################################################################################
diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td
index ffb64646709df..1ab83b6ffbbad 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -291,6 +291,17 @@ defm unsafe_cray_pointers : BoolOptionWithoutMarshalling<"f", "unsafe-cray-point
PosFlag<SetTrue, [], [FlangOption, FC1Option], "Optimizations allow for unsafe Cray pointer usages">,
NegFlag<SetFalse, [], [FlangOption, FC1Option], "Optimizations don't allow for unsafe Cray pointer usages (default)">>;
+def relaxed_c_loc : Flag<["-"], "frelaxed-c-loc">, Group<f_Group>,
+ Visibility<[FlangOption, FC1Option]>,
+ HelpText<"Unsafe relaxation of C_LOC() argument restrictions for compatibility">,
+ DocBrief<[{
+ Unsafe relaxation of C_LOC() argument restrictions for compatibility.
+ All C_LOC values should be passed directly to C calls.
+
+ This is unsafe, because it can be used to create aliases the compiler
+ is unaware of, please fix your applications instead of using this flag.
+ This may be removed in the future.}]>;
+
def fhermetic_module_files : Flag<["-"], "fhermetic-module-files">, Group<f_Group>,
HelpText<"Emit hermetic module files (no nested USE association)">;
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 391fe99749fd6..bbacc61632339 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -527,6 +527,12 @@ end program
* Default exponent of zero, e.g. `3.14159E`, on a READ from a
fixed-width input field. Includes the case with only an
exponent letter for compatibility with other compilers.
+* Relax some restrictions to make `C_LOC` more like `LOC` for
+ compatibility with legacy code that should be fixed. This is
+ unsafe and can be used to create aliases that the compiler
+ does not know about. Locations obtained this way should be
+ passed directly to C code. This could be removed at any time.
+ [-frelaxed-c-loc]
### Extensions and legacy features deliberately not supported
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index df93eaa8b4936..af72b71d9d1e6 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 27eff51741498..0bb4d692267e7 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -3500,11 +3500,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 should 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)}) {
@@ -3541,20 +3556,28 @@ 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(
+ characteristics::DummyArgument{"x", std::move(ddo)});
+ specificCall.arguments.emplace_back(std::move(arguments[0]));
+ return specificCall;
+ } else if (context.languageFeatures().IsEnabled(
+ common::LanguageFeature::RelaxedCLoc)) {
+ if (!expr || !IsProcedurePointer(*expr)) {
+ // There are more specific errors as to why the expression doesn't exist
+ // or isn't characterizable as a data object or procedure.
+ } else if (auto proc{characteristics::Procedure::Characterize(
+ *expr, context)}) {
+ characteristics::DummyProcedure dProc{std::move(*proc)};
+ dProc.intent = common::Intent::In;
+ specificCall.specificIntrinsic.characteristics.value()
+ .dummyArguments.emplace_back(
+ characteristics::DummyArgument{"x", std::move(dProc)});
+ specificCall.arguments.emplace_back(std::move(arguments[0]));
+ return specificCall;
+ }
}
}
return std::nullopt;
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index a1508f40bf490..e7f4762e167fb 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -869,6 +869,11 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
args.hasFlag(clang::options::OPT_funsigned,
clang::options::OPT_fno_unsigned, false));
+ // -frelaxed-c-loc
+ if (args.hasArg(clang::options::OPT_relaxed_c_loc)) {
+ opts.features.Enable(Fortran::common::LanguageFeature::RelaxedCLoc);
+ }
+
// -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 d8f7b4f6e58e7..54c8931da17d3 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -139,6 +139,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
disable_.set(LanguageFeature::ImplicitNoneExternal);
disable_.set(LanguageFeature::DefaultSave);
disable_.set(LanguageFeature::SaveMainProgram);
+ disable_.set(LanguageFeature::RelaxedCLoc);
// These features, if enabled, conflict with valid standard usage,
// so there are disabled here by default.
disable_.set(LanguageFeature::BackslashEscapes);
@@ -213,6 +214,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
warnUsage_.set(UsageWarning::MisplacedIgnoreTKR);
warnUsage_.set(UsageWarning::ImpureFinalInPure);
warnUsage_.set(UsageWarning::IgnoredNoReallocateLHS);
+ warnUsage_.set(UsageWarning::CLoc);
warnLanguage_.set(LanguageFeature::OpenMPThreadprivateEquivalence);
}
diff --git a/flang/test/Semantics/c_loc01-relaxed.f90 b/flang/test/Semantics/c_loc01-relaxed.f90
new file mode 100644
index 0000000000000..c958a95e0949b
--- /dev/null
+++ b/flang/test/Semantics/c_loc01-relaxed.f90
@@ -0,0 +1,99 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -frelaxed-c-loc
+module m
+ use iso_c_binding
+ type haslen(L)
+ integer, len :: L
+ end type
+ integer, target :: targ
+ contains
+ subroutine subr
+ end
+ subroutine test(assumedType, poly, nclen, n)
+ type(*), target :: assumedType
+ class(*), target :: poly
+ type(c_ptr) cp
+ type(c_funptr) cfp
+ real notATarget
+ procedure(sin), pointer :: pptr
+ real, target :: arr(3)
+ type(hasLen(1)), target :: clen
+ type(hasLen(*)), target :: nclen
+ integer, intent(in) :: n
+ character(2), target :: ch
+ character(1,4), target :: unicode
+ real :: arr1(purefun1(c_loc(targ))) ! ok
+ real :: arr2(purefun2(c_funloc(subr))) ! ok
+ character(:), allocatable, target :: deferred
+ character(n), pointer :: p2ch
+ !WARNING: C_LOC() argument should be a data pointer or target [-Wc-loc]
+ cp = c_loc(notATarget)
+ !WARNING: C_LOC() argument should be a data pointer or target [-Wc-loc]
+ 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))
+ cp = c_loc(ch)
+ !WARNING: C_LOC() argument has non-interoperable intrinsic type or kind [-Winteroperability]
+ cp = c_loc(unicode)
+ cp = c_loc(ch(1:1)) ! ok
+ cp = c_loc(deferred) ! ok
+ cp = c_loc(p2ch) ! ok
+ !ERROR: alternate return specification may not appear on function reference
+666 cp = c_loc(*666)
+ !ERROR: PRIVATE name '__address' is accessible only within module '__fortran_builtins'
+ cp = c_ptr(0)
+ !ERROR: PRIVATE name '__address' is accessible only within module '__fortran_builtins'
+ cfp = c_funptr(0)
+ !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types TYPE(c_ptr) and TYPE(c_funptr)
+ cp = cfp
+ !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types TYPE(c_funptr) and TYPE(c_ptr)
+ cfp = cp
+ end
+ pure integer function purefun1(p)
+ type(c_ptr), intent(in) :: p
+ purefun1 = 1
+ end
+ pure integer function purefun2(p)
+ type(c_funptr), intent(in) :: p
+ purefun2 = 1
+ end
+end module
+
+module m2
+ use iso_c_binding
+ ! In this context (structure constructor from intrinsic module being used directly
+ ! in another module), emit only a warning, since this module might have originally
+ ! been a module file that was converted back into Fortran.
+ !WARNING: PRIVATE name '__address' is accessible only within module '__fortran_builtins'
+ type(c_ptr) :: p = c_ptr(0)
+end
+
+module m3
+ use iso_c_binding
+ implicit none
+ real, target :: modtarg
+ contains
+ subroutine helper()
+ end subroutine
+ subroutine test
+ implicit none
+ type(c_ptr) :: cp
+ real :: notATarget
+ real, target :: localtarg
+ procedure(helper), pointer :: pptr
+ cp = c_loc(modtarg) ! ok
+ cp = c_loc(localtarg) ! ok
+ !WARNING: C_LOC() argument should be a data pointer or target [-Wc-loc]
+ cp = c_loc(notATarget)
+ !WARNING: C_LOC() argument should be a data pointer or target [-Wc-loc]
+ cp = c_loc(pptr)
+ end subroutine
+end module
diff --git a/flang/test/Semantics/c_loc01.f90 b/flang/test/Semantics/c_loc01.f90
index 16f5618b6330f..2496027f4315b 100644
--- a/flang/test/Semantics/c_loc01.f90
+++ b/flang/test/Semantics/c_loc01.f90
@@ -48,6 +48,8 @@ subroutine test(assumedType, poly, nclen, n)
cp = c_loc(ch(1:1)) ! ok
cp = c_loc(deferred) ! ok
cp = c_loc(p2ch) ! ok
+ !ERROR: alternate return specification may not appear on function reference
+666 cp = c_loc(*666)
!ERROR: PRIVATE name '__address' is accessible only within module '__fortran_builtins'
cp = c_ptr(0)
!ERROR: PRIVATE name '__address' is accessible only within module '__fortran_builtins'
More information about the flang-commits
mailing list