[clang] [clang] add `-fimplicit-constexpr` flag (PR #136436)
Hana Dusíková via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 19 08:06:32 PDT 2025
https://github.com/hanickadot created https://github.com/llvm/llvm-project/pull/136436
Same as GCC's flag of the same name. If a function (constructor / destructor) doesn't have a `constexpr` nor `consteval` specifier. It will implicitly add `constexpr`.
This change doesn't touch variables. Only functions.
>From 697ec9a278e700d222a1c8a3e9c827bf08cfd8a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hana=20Dusi=CC=81kova=CC=81?= <hanicka at hanicka.net>
Date: Sat, 19 Apr 2025 16:52:33 +0200
Subject: [PATCH] [clang] add -fimplicit-constexpr flag
---
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Driver/Options.td | 6 +++
clang/include/clang/Sema/Sema.h | 1 +
clang/lib/Driver/ToolChains/Clang.cpp | 2 +
clang/lib/Sema/CMakeLists.txt | 1 +
clang/lib/Sema/SemaDecl.cpp | 10 +++++
clang/test/Sema/implicit-constexpr.cpp | 51 +++++++++++++++++++++++
7 files changed, 72 insertions(+)
create mode 100644 clang/test/Sema/implicit-constexpr.cpp
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 930c1c06d1a76..97527f7a0d1f3 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -413,6 +413,7 @@ BENIGN_LANGOPT(ArrowDepth, 32, 256,
"maximum number of operator->s to follow")
BENIGN_LANGOPT(InstantiationDepth, 32, 1024,
"maximum template instantiation depth")
+LANGOPT(ImplicitConstexpr, 1, 0, "evaluate everything as it is a constexpr enabled")
BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
"maximum constexpr call depth")
BENIGN_LANGOPT(ConstexprStepLimit, 32, 1048576,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 919c1c643d080..877235147a044 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1991,6 +1991,12 @@ defm constant_cfstrings : BoolFOption<"constant-cfstrings",
"Disable creation of CodeFoundation-type constant strings">,
PosFlag<SetFalse>>;
def fconstant_string_class_EQ : Joined<["-"], "fconstant-string-class=">, Group<f_Group>;
+def fimplicit_constexpr
+ : Joined<["-"], "fimplicit-constexpr">,
+ Group<f_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"All function declarations will be implicitly constexpr.">,
+ MarshallingInfoFlag<LangOpts<"ImplicitConstexpr">>;
def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum depth of recursive constexpr function calls">,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 96d81e618494a..603a44bbba910 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2826,6 +2826,7 @@ class Sema final : public SemaBase {
bool buildCoroutineParameterMoves(SourceLocation Loc);
VarDecl *buildCoroutinePromise(SourceLocation Loc);
void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body);
+ void AnalyseCoroutineBody(const CoroutineBodyStmt *);
// As a clang extension, enforces that a non-coroutine function must be marked
// with [[clang::coro_wrapper]] if it returns a type marked with
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index f2f5231933c88..27baf602e2703 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6612,6 +6612,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fimplicit_constexpr);
+
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter))
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 4b87004e4b8ea..c0e916440a5fd 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -46,6 +46,7 @@ add_clang_library(clangSema
SemaConcept.cpp
SemaConsumer.cpp
SemaCoroutine.cpp
+ SemaCoroutineFlow.cpp
SemaCUDA.cpp
SemaDirectX.cpp
SemaDecl.cpp
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 46933c5c43168..1d4328db4dc41 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10163,6 +10163,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
+
+ // Clang's option -fimplicit-constexpr will make functions without constexpr
+ // or consteval specifier implicitly constexpr (compatibility with GCC.)
+ if (ConstexprKind == ConstexprSpecKind::Unspecified &&
+ getLangOpts().ImplicitConstexpr) {
+
+ NewFD->setConstexprKind(ConstexprSpecKind::Constexpr);
+ ConstexprKind = ConstexprSpecKind::Constexpr;
+ }
+
if (ConstexprKind != ConstexprSpecKind::Unspecified) {
// C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
// are implicitly inline.
diff --git a/clang/test/Sema/implicit-constexpr.cpp b/clang/test/Sema/implicit-constexpr.cpp
new file mode 100644
index 0000000000000..4b1314c342361
--- /dev/null
+++ b/clang/test/Sema/implicit-constexpr.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -verify=normal,both -std=c++23 %s
+// RUN: %clang_cc1 -verify=implicit,both -fimplicit-constexpr -std=c++23 %s
+
+bool function_test() { // normal-note+ {{declared here}}
+ return true;
+}
+
+// const variables should work as before
+const auto cvar = function_test();
+
+constexpr auto constexpr_var = function_test(); // normal-error {{constexpr variable 'constexpr_var' must be initialized by a constant expression}}
+// normal-note at -1 {{non-constexpr function 'function_test' cannot be used in a constant expression}}
+
+static_assert(function_test()); // normal-error {{static assertion expression is not an integral constant expression}}
+// normal-note at -1 {{non-constexpr function 'function_test' cannot be used in a constant expression}}
+
+
+struct full_nonconstexpr_type {
+ full_nonconstexpr_type() { } // normal-note {{declared here}}
+ ~full_nonconstexpr_type() { }
+};
+
+constexpr bool constructor_destructor_test() {
+ full_nonconstexpr_type var{}; // normal-note {{non-constexpr constructor 'full_nonconstexpr_type' cannot be used in a constant expression}}
+ return true;
+}
+
+static_assert(constructor_destructor_test()); // normal-error {{static assertion expression is not an integral constant expression}}
+// normal-note at -1 {{in call to 'constructor_destructor_test()'}}
+
+
+struct only_destructor_type {
+ constexpr only_destructor_type() { }
+ ~only_destructor_type() { } // normal-note {{declared here}}
+};
+
+constexpr bool destructor_test() {
+ only_destructor_type var{}; // normal-note {{non-constexpr function '~only_destructor_type' cannot be used in a constant expression}}
+ return true;
+}
+
+static_assert(destructor_test()); // normal-error {{static assertion expression is not an integral constant expression}}
+// normal-note at -1 {{in call to 'destructor_test()'}}
+
+
+bool undefined_test(); // both-note {{declared here}}
+
+static_assert(undefined_test()); // both-error {{static assertion expression is not an integral constant expression}}
+// normal-note at -1 {{non-constexpr function 'undefined_test' cannot be used in a constant expressio}}
+// implicit-note at -2 {{undefined function 'undefined_test' cannot be used in a constant expression}}
+
More information about the cfe-commits
mailing list