https://github.com/hanickadot updated https://github.com/llvm/llvm-project/pull/136436
From f37eb75b71d2aa6433bc528b7b4532138ae4e62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hana=20Dusi=CC=81kova=CC=81?= <hani...@hanicka.net> Date: Sun, 20 Apr 2025 00:24:46 +0200 Subject: [PATCH 1/5] [clang] add -fimplicit-constexpr flag (with same behaviour as GCC) --- clang/include/clang/AST/Decl.h | 3 + .../include/clang/Basic/DiagnosticASTKinds.td | 2 + clang/include/clang/Basic/Features.def | 1 + clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/Options.td | 6 + clang/lib/AST/Decl.cpp | 21 ++++ clang/lib/AST/ExprConstant.cpp | 24 +++- clang/lib/Driver/ToolChains/Clang.cpp | 3 + clang/lib/Frontend/InitPreprocessor.cpp | 3 + clang/lib/Sema/SemaExpr.cpp | 6 +- clang/test/Sema/implicit-constexpr-basic.cpp | 112 ++++++++++++++++++ .../test/Sema/implicit-constexpr-features.cpp | 81 +++++++++++++ .../test/Sema/implicit-constexpr-members.cpp | 83 +++++++++++++ 13 files changed, 339 insertions(+), 7 deletions(-) create mode 100644 clang/test/Sema/implicit-constexpr-basic.cpp create mode 100644 clang/test/Sema/implicit-constexpr-features.cpp create mode 100644 clang/test/Sema/implicit-constexpr-members.cpp diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 3faf63e395a08..be37cb115b24b 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2418,6 +2418,9 @@ class FunctionDecl : public DeclaratorDecl, bool isConstexpr() const { return getConstexprKind() != ConstexprSpecKind::Unspecified; } + /// Support for `-fimplicit-constexpr` + bool isConstexprOrImplicitlyCanBe(const LangOptions &LangOpts, + bool MustBeInlined = true) const; void setConstexprKind(ConstexprSpecKind CSK) { FunctionDeclBits.ConstexprKind = static_cast<uint64_t>(CSK); } diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index f73963752bb67..57d58a735db85 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -32,6 +32,8 @@ def note_constexpr_lshift_discards : Note<"signed left shift discards bits">; def note_constexpr_invalid_function : Note< "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot " "be used in a constant expression">; +def note_constexpr_implicit_constexpr_must_be_inlined + : Note<"non-inline function %0 is not implicitly constexpr">; def note_constexpr_invalid_inhctor : Note< "constructor inherited from base class %0 cannot be used in a " "constant expression; derived class cannot be implicitly initialized">; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 14bff8a68846d..2fe9ed3419ee9 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -316,6 +316,7 @@ EXTENSION(matrix_types, LangOpts.MatrixTypes) EXTENSION(matrix_types_scalar_division, true) EXTENSION(cxx_attributes_on_using_declarations, LangOpts.CPlusPlus11) EXTENSION(datasizeof, LangOpts.CPlusPlus) +EXTENSION(cxx_implicit_constexpr, LangOpts.ImplicitConstexpr) FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 930c1c06d1a76..97a271b200976 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") +COMPATIBLE_LANGOPT(ImplicitConstexpr, 1, 0, "make functions implicitly 'constexpr'") 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/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index ad1cb01592e9b..1a595dfc3daeb 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3242,6 +3242,27 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition, return false; } +bool FunctionDecl::isConstexprOrImplicitlyCanBe(const LangOptions &LangOpts, + bool MustBeInlined) const { + if (isConstexpr()) + return true; + + if (!LangOpts.ImplicitConstexpr) + return false; + + // Constexpr function in C++11 couldn't contain anything other then return + // expression. It wouldn't make sense to allow it (GCC doesn't do it neither). + if (!LangOpts.CPlusPlus14) + return false; + + // Free functions must be inlined, but sometimes we want to skip this check. + // And in order to keep logic on one place, the check is here. + if (MustBeInlined) + return isInlined(); + + return true; +} + Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { if (!hasBody(Definition)) return nullptr; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index b14ff21a8ebc2..6cfb67ad1d719 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5968,8 +5968,9 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, // Can we evaluate this function call? if (Definition && Body && - (Definition->isConstexpr() || (Info.CurrentCall->CanEvalMSConstexpr && - Definition->hasAttr<MSConstexprAttr>()))) + (Definition->isConstexprOrImplicitlyCanBe(Info.Ctx.getLangOpts()) || + (Info.CurrentCall->CanEvalMSConstexpr && + Definition->hasAttr<MSConstexprAttr>()))) return true; if (Info.getLangOpts().CPlusPlus11) { @@ -5987,12 +5988,25 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, // FIXME: If DiagDecl is an implicitly-declared special member function // or an inheriting constructor, we should be much more explicit about why // it's not constexpr. - if (CD && CD->isInheritingConstructor()) + if (CD && CD->isInheritingConstructor()) { Info.FFDiag(CallLoc, diag::note_constexpr_invalid_inhctor, 1) << CD->getInheritedConstructor().getConstructor()->getParent(); - else + + } else if (Definition && !DiagDecl->isInlined() && + Info.Ctx.getLangOpts().ImplicitConstexpr) { + Info.FFDiag(CallLoc, + diag::note_constexpr_implicit_constexpr_must_be_inlined) + << DiagDecl; + + } else { + // Using implicit constexpr check here, so we see a missing body as main + // problem and not missing constexpr with -fimplicit-constexpr. Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1) - << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; + << DiagDecl->isConstexprOrImplicitlyCanBe(Info.Ctx.getLangOpts(), + false) + << (bool)CD << DiagDecl; + } + Info.Note(DiagDecl->getLocation(), diag::note_declared_at); } else { Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f2f5231933c88..e33d0b72ed04d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6612,6 +6612,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ); Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ); + if (types::isCXX(InputType)) + 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/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 1f297f228fc1b..f0fdf81272fb3 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -779,6 +779,9 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, // TODO: Final number? Builder.defineMacro("__cpp_type_aware_allocators", "202500L"); + + if (LangOpts.ImplicitConstexpr) // same value as GCC + Builder.defineMacro("__cpp_implicit_constexpr", "20211111"); } /// InitializeOpenCLFeatureTestMacros - Define OpenCL macros based on target diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 01a021443c94f..82c2c61363e3b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -18384,16 +18384,18 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, } if (FirstInstantiation || TSK != TSK_ImplicitInstantiation || - Func->isConstexpr()) { + Func->isConstexprOrImplicitlyCanBe(getLangOpts())) { if (isa<CXXRecordDecl>(Func->getDeclContext()) && cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() && CodeSynthesisContexts.size()) PendingLocalImplicitInstantiations.push_back( std::make_pair(Func, PointOfInstantiation)); - else if (Func->isConstexpr()) + else if (Func->isConstexprOrImplicitlyCanBe(getLangOpts())) // Do not defer instantiations of constexpr functions, to avoid the // expression evaluator needing to call back into Sema if it sees a // call to such a function. + // (When -fimplicit-instantiation is enabled, all functions are + // implicitly constexpr) InstantiateFunctionDefinition(PointOfInstantiation, Func); else { Func->setInstantiationIsPending(true); diff --git a/clang/test/Sema/implicit-constexpr-basic.cpp b/clang/test/Sema/implicit-constexpr-basic.cpp new file mode 100644 index 0000000000000..9f17a344125dc --- /dev/null +++ b/clang/test/Sema/implicit-constexpr-basic.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL14,BOTH14,ALL_PRE20,ALLNORMAL,NORMAL_PRE20,ALL -std=c++14 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_PRE20,BOTH14,ALL_PRE20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++14 %s -fcolor-diagnostics + +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL17,BOTH17,ALL_PRE20,ALLNORMAL,NORMAL_PRE20,ALL -std=c++17 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_PRE20,BOTH17,ALL_PRE20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++17 %s -fcolor-diagnostics + +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL20,BOTH20,ALLNORMAL,ALL -std=c++20 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++20 %s -fcolor-diagnostics + +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL23,BOTH23,ALLNORMAL,ALL -std=c++23 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics + + + + +// ============================================= +// 1) simple uninlined function + +bool noinline_fnc() { +// ALL-note@-1 {{declared here}} + return true; +} + +constexpr bool result_noinline_fnc = noinline_fnc(); +// ALL-error@-1 {{constexpr variable 'result_noinline_fnc' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'noinline_fnc' cannot be used in a constant expression}} +// ALLIMPLICIT-note@-3 {{non-inline function 'noinline_fnc' is not implicitly constexpr}} + + +// ============================================= +// 2) simple inlined function + +inline bool inline_fnc() { +// ALLNORMAL-note@-1 {{declared here}} + return true; +} + +constexpr bool result_inline_fnc = inline_fnc(); +// ALLNORMAL-error@-1 {{constexpr variable 'result_inline_fnc' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'inline_fnc' cannot be used in a constant expression}} + + +// ============================================= +// 3) undefined uninlined function + +bool noinline_undefined_fnc(); +// ALL-note@-1 {{declared here}} + +constexpr bool result_noinline_undefined_fnc = noinline_undefined_fnc(); +// ALL-error@-1 {{constexpr variable 'result_noinline_undefined_fnc' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'noinline_undefined_fnc' cannot be used in a constant expression}} +// ALLIMPLICIT-note@-3 {{undefined function 'noinline_undefined_fnc' cannot be used in a constant expression}} + + +// ============================================= +// 4) undefined inline function + +inline bool inline_undefined_fnc(); +// ALL-note@-1 {{declared here}} + +constexpr bool result_inline_undefined_fnc = inline_undefined_fnc(); +// ALL-error@-1 {{constexpr variable 'result_inline_undefined_fnc' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'inline_undefined_fnc' cannot be used in a constant expression}} +// ALLIMPLICIT-note@-3 {{undefined function 'inline_undefined_fnc' cannot be used in a constant expression}} + +// ============================================= +// 5) lambda function + +auto lambda = [](int x) { return x > 0; }; +// NORMAL14-note@-1 {{declared here}} + +constexpr bool result_lambda = lambda(10); +// NORMAL14-error@-1 {{constexpr variable 'result_lambda' must be initialized by a constant expression}} +// NORMAL14-note@-2 {{non-constexpr function 'operator()' cannot be used in a constant expression}} + + +// ============================================= +// 6) virtual functions + +struct type { + virtual bool dispatch() const noexcept { + return false; + } +}; + +struct child_of_type: type { + bool dispatch() const noexcept override { +// NORMAL20-note@-1 {{declared here}} +// NORMAL23-note@-2 {{declared here}} + return true; + } +}; + +constexpr bool result_virtual = static_cast<const type &>(child_of_type{}).dispatch(); +// ALL_NORMAL-error@-1 {{constexpr variable 'result_virtual' must be initialized by a constant expression}} +// NORMAL_PRE20-note@-2 {{cannot evaluate call to virtual function in a constant expression in C++ standards before C++20}} +// IMPLICIT_PRE20-error@-3 {{constexpr variable 'result_virtual' must be initialized by a constant expression}} +// IMPLICIT_PRE20-note@-4 {{cannot evaluate call to virtual function in a constant expression in C++ standards before C++20}} +// NORMAL20-note@-5 {{non-constexpr function 'dispatch' cannot be used in a constant expression}} +// NORMAL20-note@-6 {{declared here}} +// NORMAL23-note@-7 {{non-constexpr function 'dispatch' cannot be used in a constant expression}} +// NORMAL23-note@-8 {{declared here}} + + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201907L +static_assert(result_virtual == true, "virtual should work"); +// ALL_NORMAL-error@-1 {{static assertion expression is not an integral constant expression}} +// ALL_NORMAL-note@-2 {{initializer of 'result_virtual' is not a constant expression}} +// IMPLICIT_PRE20-note@-3 {{initializer of 'result_virtual' is not a constant expression}} +#endif + + diff --git a/clang/test/Sema/implicit-constexpr-features.cpp b/clang/test/Sema/implicit-constexpr-features.cpp new file mode 100644 index 0000000000000..ab8a50ecdb147 --- /dev/null +++ b/clang/test/Sema/implicit-constexpr-features.cpp @@ -0,0 +1,81 @@ +// RUN: %clang_cc1 -verify=NORMAL14,NORMAL_ALL -std=c++14 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL17,NORMAL_ALL -std=c++17 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL20,NORMAL_ALL -std=c++20 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL23,NORMAL_ALL -std=c++23 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL26,NORMAL_ALL -std=c++26 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= + +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_ALL -std=c++14 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_ALL -std=c++17 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT20,IMPLICIT_ALL -std=c++20 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT23,IMPLICIT_ALL -std=c++23 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT26,IMPLICIT_ALL -std=c++26 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr + +// RUN: %clang_cc1 -verify=CONSTEXPR14,CONSTEXPR_BEFORE23,CONSTEXPR_BEFORE20,CONSTEXPR_ALL -std=c++14 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR17,CONSTEXPR_BEFORE23,CONSTEXPR_BEFORE20,CONSTEXPR_ALL -std=c++17 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR20,CONSTEXPR_BEFORE23,CONSTEXPR_ALL -std=c++20 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR23,CONSTEXPR_ALL -std=c++23 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR26,CONSTEXPR_ALL -std=c++26 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr + +// Objective is to make sure features like allocation / throwing won't fail code by just adding implicit constexpr +// in an unevaluated code. + +// NORMAL_ALL-no-diagnostics +// IMPLICIT_ALL-no-diagnostics +// CONSTEXPR23-no-diagnostics +// CONSTEXPR26-no-diagnostics + +CONSTEXPR inline bool function_with_goto(int v) { + if (v == 0) { + return true; + } + + goto label; + // CONSTEXPR_BEFORE23-warning@-1 {{use of this statement in a constexpr function is a C++23 extension}} + + label: + return false; +} + +CONSTEXPR inline bool function_with_label(int v) { + label: + // CONSTEXPR_BEFORE23-warning@-1 {{use of this statement in a constexpr function is a C++23 extension}} + if (v > 0) { + return true; + } + v++; + goto label; +} + +CONSTEXPR inline bool function_with_try_catch(int v) { + try { + // CONSTEXPR_BEFORE20-warning@-1 {{use of this statement in a constexpr function is a C++20 extension}} + return v; + } catch (int) { + return -v; + } +} + +CONSTEXPR inline bool function_with_inline_asm(int v) { + if (v > 0) { + asm(""); + // CONSTEXPR_BEFORE20-warning@-1 {{use of this statement in a constexpr function is a C++20 extension}} + } + + return v; +} + +struct easy_type { + // CONSTEXPR_BEFORE20-note@-1 {{declared here}} + int * x; +}; + +CONSTEXPR inline bool function_with_no_initializer_variable(int v) { + // CONSTEXPR_BEFORE20-error@-1 {{constexpr function never produces a constant expression}} + easy_type easy; + // CONSTEXPR_BEFORE20-note@-1 {{non-constexpr constructor 'easy_type' cannot be used in a constant expression}} + return v; +} + + + + diff --git a/clang/test/Sema/implicit-constexpr-members.cpp b/clang/test/Sema/implicit-constexpr-members.cpp new file mode 100644 index 0000000000000..c68df52677dff --- /dev/null +++ b/clang/test/Sema/implicit-constexpr-members.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -verify=NORMAL14,BOTH14,ALLNORMAL,ALL -std=c++14 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT14,BOTH14,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++14 %s -fcolor-diagnostics + +// RUN: %clang_cc1 -verify=NORMAL17,BOTH20,ALLNORMAL,ALL -std=c++17 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT17,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++17 %s -fcolor-diagnostics + +// RUN: %clang_cc1 -verify=NORMAL20,BOTH20,ALLNORMAL,ALL -std=c++20 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++20 %s -fcolor-diagnostics + +// RUN: %clang_cc1 -verify=NORMAL23,BOTH23,ALLNORMAL,ALL -std=c++23 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics + + +// ============================================= +// 1) simple member function + +struct simple_type { + bool test() const { + // ALLNORMAL-note@-1 {{declared here}} + return true; + } +}; + +constexpr bool result_simple_type = simple_type{}.test(); +// ALLNORMAL-error@-1 {{constexpr variable 'result_simple_type' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'test' cannot be used in a constant expression}} + +#ifdef __cpp_implicit_constexpr +static_assert(result_simple_type == true, "simple member function must work"); +#endif + + +// ============================================= +// 2) simple member function inside a template + +template <typename T> struct template_type { + bool test() const { + // ALLNORMAL-note@-1 {{declared here}} + return true; + } +}; + +constexpr bool result_template_type = template_type<int>{}.test(); +// ALLNORMAL-error@-1 {{constexpr variable 'result_template_type' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'test' cannot be used in a constant expression}} + + +// ============================================= +// 3) template member function inside a template + +template <typename T> struct template_template_type { + template <typename Y> bool test() const { + // ALLNORMAL-note@-1 {{declared here}} + return true; + } +}; + +constexpr bool result_template_template_type = template_template_type<int>{}.template test<long>(); +// ALLNORMAL-error@-1 {{constexpr variable 'result_template_template_type' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'test<long>' cannot be used in a constant expression}} + + +#if defined(__cpp_explicit_this_parameter) && __cpp_explicit_this_parameter >= 202110L + +// ============================================= +// 3) explicit "this" function + +struct explicit_this { + template <typename Self> bool test(this const Self & self) const { + // ALLNORMAL-note@-1 {{declared here}} + return self.ok; + } +}; + +struct child: explicit_this { + static constexpr bool ok = true; +}; + +constexpr bool result_explicit_this = child{}.test(); +// ALLNORMAL-error@-1 {{constexpr variable 'result_explicit_this' must be initialized by a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'test' cannot be used in a constant expression}} + +#endif From a486edc7562ba44e67a50eee3217c39fd9405d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hana=20Dusi=CC=81kova=CC=81?= <hani...@hanicka.net> Date: Sun, 20 Apr 2025 00:33:05 +0200 Subject: [PATCH 2/5] [clang] `-fimplicit-constexpr` release notes. --- clang/docs/ReleaseNotes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f5cd1fbeabcfe..be8a7e164e529 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -211,6 +211,8 @@ New Compiler Flags The feature has `existed <https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#running-the-instrumented-program>`_) for a while and this is just a user facing option. +- New option ``-fimplicit-constexpr`` which implicitly makes all inlined and defined functions ``constexpr``. + Deprecated Compiler Flags ------------------------- From 00621633d36fe9d6c5efb7728146788e3637a65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hana=20Dusi=CC=81kova=CC=81?= <hani...@hanicka.net> Date: Sun, 20 Apr 2025 10:38:43 +0200 Subject: [PATCH 3/5] [clang] `-fimplicit-constexpr` fix test (forgot to push fixed version before) --- clang/test/Sema/implicit-constexpr-members.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/Sema/implicit-constexpr-members.cpp b/clang/test/Sema/implicit-constexpr-members.cpp index c68df52677dff..498f8325c4234 100644 --- a/clang/test/Sema/implicit-constexpr-members.cpp +++ b/clang/test/Sema/implicit-constexpr-members.cpp @@ -10,6 +10,7 @@ // RUN: %clang_cc1 -verify=NORMAL23,BOTH23,ALLNORMAL,ALL -std=c++23 %s -fcolor-diagnostics // RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics +// ALLIMPLICIT-no-diagnostics // ============================================= // 1) simple member function @@ -66,7 +67,7 @@ constexpr bool result_template_template_type = template_template_type<int>{}.tem // 3) explicit "this" function struct explicit_this { - template <typename Self> bool test(this const Self & self) const { + template <typename Self> bool test(this const Self & self) { // ALLNORMAL-note@-1 {{declared here}} return self.ok; } @@ -78,6 +79,6 @@ struct child: explicit_this { constexpr bool result_explicit_this = child{}.test(); // ALLNORMAL-error@-1 {{constexpr variable 'result_explicit_this' must be initialized by a constant expression}} -// ALLNORMAL-note@-2 {{non-constexpr function 'test' cannot be used in a constant expression}} +// ALLNORMAL-note@-2 {{non-constexpr function 'test<child>' cannot be used in a constant expression}} #endif From 77403d7e5a3a1e2c26f859c72d7f42fa0a89f9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hana=20Dusi=CC=81kova=CC=81?= <hani...@hanicka.net> Date: Mon, 21 Apr 2025 20:53:17 +0200 Subject: [PATCH 4/5] [clang] add -fimplicit-constexpr flag (for new constexpr interpret) --- clang/lib/AST/ByteCode/ByteCodeEmitter.cpp | 7 +-- clang/lib/AST/ByteCode/Interp.cpp | 24 +++++++--- clang/test/Sema/implicit-constexpr-basic.cpp | 37 +++++++++++++--- .../test/Sema/implicit-constexpr-features.cpp | 44 ++++++++++++------- .../test/Sema/implicit-constexpr-members.cpp | 28 +++++++++--- 5 files changed, 103 insertions(+), 37 deletions(-) diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index d91d5f16fc7a9..26ca0f6fb1b87 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -70,9 +70,10 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, Func->setDefined(true); // Lambda static invokers are a special case that we emit custom code for. - bool IsEligibleForCompilation = Func->isLambdaStaticInvoker() || - FuncDecl->isConstexpr() || - FuncDecl->hasAttr<MSConstexprAttr>(); + bool IsEligibleForCompilation = + Func->isLambdaStaticInvoker() || + FuncDecl->isConstexprOrImplicitlyCanBe(Ctx.getLangOpts()) || + FuncDecl->hasAttr<MSConstexprAttr>(); // Compile the function body. if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) { diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index b755a072fec88..ee46622ee49ef 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -827,7 +827,8 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { return false; if (F->isConstexpr() && F->hasBody() && - (F->getDecl()->isConstexpr() || F->getDecl()->hasAttr<MSConstexprAttr>())) + (F->getDecl()->isConstexprOrImplicitlyCanBe(S.getLangOpts()) || + F->getDecl()->hasAttr<MSConstexprAttr>())) return true; // Implicitly constexpr. @@ -846,7 +847,7 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); if (CD && CD->isInheritingConstructor()) { const auto *Inherited = CD->getInheritedConstructor().getConstructor(); - if (!Inherited->isConstexpr()) + if (!Inherited->isConstexprOrImplicitlyCanBe(S.getLangOpts())) DiagDecl = CD = Inherited; } @@ -868,19 +869,28 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { // for a constant expression. It might be defined at the point we're // actually calling it. bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; - if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() && + if (!DiagDecl->isDefined() && !IsExtern && + DiagDecl->isConstexprOrImplicitlyCanBe(S.getLangOpts()) && S.checkingPotentialConstantExpression()) return false; // If the declaration is defined, declared 'constexpr' _and_ has a body, // the below diagnostic doesn't add anything useful. - if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && + if (DiagDecl->isDefined() && + DiagDecl->isConstexprOrImplicitlyCanBe(S.getLangOpts()) && DiagDecl->hasBody()) return false; - S.FFDiag(S.Current->getLocation(OpPC), - diag::note_constexpr_invalid_function, 1) - << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; + if (F->getDecl()->isConstexprOrImplicitlyCanBe(S.getLangOpts(), false)) { + S.FFDiag(S.Current->getLocation(OpPC), + diag::note_constexpr_implicit_constexpr_must_be_inlined, 1) + << DiagDecl; + } else { + S.FFDiag(S.Current->getLocation(OpPC), + diag::note_constexpr_invalid_function, 1) + << DiagDecl->isConstexprOrImplicitlyCanBe(S.getLangOpts()) + << (bool)CD << DiagDecl; + } if (DiagDecl->getDefinition()) S.Note(DiagDecl->getDefinition()->getLocation(), diff --git a/clang/test/Sema/implicit-constexpr-basic.cpp b/clang/test/Sema/implicit-constexpr-basic.cpp index 9f17a344125dc..1a43c8c15d0a3 100644 --- a/clang/test/Sema/implicit-constexpr-basic.cpp +++ b/clang/test/Sema/implicit-constexpr-basic.cpp @@ -1,14 +1,36 @@ +<<<<<<< HEAD +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL14,BOTH14,ALL_PRE20,ALLNORMAL,NORMAL_PRE20,ALL -std=c++14 %s +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_PRE20,BOTH14,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++14 %s +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_PRE20,BOTH14,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++14 %s -fexperimental-new-constant-interpreter + +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL17,BOTH17,ALL_PRE20,ALLNORMAL,NORMAL_PRE20,ALL -std=c++17 %s +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_PRE20,BOTH17,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++17 %s +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_PRE20,BOTH17,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++17 %s -fexperimental-new-constant-interpreter + +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL20,BOTH20,ALLNORMAL,ALL -std=c++20 %s +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++20 %s +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++20 %s -fexperimental-new-constant-interpreter + +// RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL23,BOTH23,ALLNORMAL,ALL -std=c++23 %s +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++23 %s +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++23 %s -fexperimental-new-constant-interpreter +======= // RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL14,BOTH14,ALL_PRE20,ALLNORMAL,NORMAL_PRE20,ALL -std=c++14 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_PRE20,BOTH14,ALL_PRE20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++14 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_PRE20,BOTH14,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++14 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_PRE20,BOTH14,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++14 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL17,BOTH17,ALL_PRE20,ALLNORMAL,NORMAL_PRE20,ALL -std=c++17 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_PRE20,BOTH17,ALL_PRE20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++17 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_PRE20,BOTH17,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++17 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_PRE20,BOTH17,ALL_PRE20,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++17 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL20,BOTH20,ALLNORMAL,ALL -std=c++20 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++20 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++20 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++20 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -verify=ALL_NORMAL,NORMAL23,BOTH23,ALLNORMAL,ALL -std=c++23 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALLIMPLICITOLD,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALLIMPLICITNEW,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter +>>>>>>> bcd8b8924468 (snapshot) @@ -49,8 +71,8 @@ bool noinline_undefined_fnc(); constexpr bool result_noinline_undefined_fnc = noinline_undefined_fnc(); // ALL-error@-1 {{constexpr variable 'result_noinline_undefined_fnc' must be initialized by a constant expression}} // ALLNORMAL-note@-2 {{non-constexpr function 'noinline_undefined_fnc' cannot be used in a constant expression}} -// ALLIMPLICIT-note@-3 {{undefined function 'noinline_undefined_fnc' cannot be used in a constant expression}} - +// ALLIMPLICITOLD-note@-3 {{undefined function 'noinline_undefined_fnc' cannot be used in a constant expression}} +// ALLIMPLICITNEW-note@-4 {{non-inline function 'noinline_undefined_fnc' is not implicitly constexpr}} // ============================================= // 4) undefined inline function @@ -61,7 +83,8 @@ inline bool inline_undefined_fnc(); constexpr bool result_inline_undefined_fnc = inline_undefined_fnc(); // ALL-error@-1 {{constexpr variable 'result_inline_undefined_fnc' must be initialized by a constant expression}} // ALLNORMAL-note@-2 {{non-constexpr function 'inline_undefined_fnc' cannot be used in a constant expression}} -// ALLIMPLICIT-note@-3 {{undefined function 'inline_undefined_fnc' cannot be used in a constant expression}} +// ALLIMPLICITOLD-note@-3 {{undefined function 'inline_undefined_fnc' cannot be used in a constant expression}} +// ALLIMPLICITNEW-note@-4 {{non-inline function 'inline_undefined_fnc' is not implicitly constexpr}} // ============================================= // 5) lambda function diff --git a/clang/test/Sema/implicit-constexpr-features.cpp b/clang/test/Sema/implicit-constexpr-features.cpp index ab8a50ecdb147..3ec8bcfdc2be5 100644 --- a/clang/test/Sema/implicit-constexpr-features.cpp +++ b/clang/test/Sema/implicit-constexpr-features.cpp @@ -1,20 +1,34 @@ -// RUN: %clang_cc1 -verify=NORMAL14,NORMAL_ALL -std=c++14 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -// RUN: %clang_cc1 -verify=NORMAL17,NORMAL_ALL -std=c++17 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -// RUN: %clang_cc1 -verify=NORMAL20,NORMAL_ALL -std=c++20 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -// RUN: %clang_cc1 -verify=NORMAL23,NORMAL_ALL -std=c++23 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -// RUN: %clang_cc1 -verify=NORMAL26,NORMAL_ALL -std=c++26 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL14,NORMAL_ALL -std=c++14 %s -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL17,NORMAL_ALL -std=c++17 %s -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL20,NORMAL_ALL -std=c++20 %s -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL23,NORMAL_ALL -std=c++23 %s -fcxx-exceptions -DCONSTEXPR= +// RUN: %clang_cc1 -verify=NORMAL26,NORMAL_ALL -std=c++26 %s -fcxx-exceptions -DCONSTEXPR= -// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_ALL -std=c++14 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_ALL -std=c++17 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -// RUN: %clang_cc1 -verify=IMPLICIT20,IMPLICIT_ALL -std=c++20 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -// RUN: %clang_cc1 -verify=IMPLICIT23,IMPLICIT_ALL -std=c++23 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -// RUN: %clang_cc1 -verify=IMPLICIT26,IMPLICIT_ALL -std=c++26 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +<<<<<<< HEAD +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_ALL -std=c++14 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_ALL -std=c++17 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT20,IMPLICIT_ALL -std=c++20 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT23,IMPLICIT_ALL -std=c++23 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +// RUN: %clang_cc1 -verify=IMPLICIT26,IMPLICIT_ALL -std=c++26 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr +======= +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_ALL -std=c++14 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_ALL -std=c++17 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT20,IMPLICIT_ALL -std=c++20 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT23,IMPLICIT_ALL -std=c++23 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT26,IMPLICIT_ALL -std=c++26 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +>>>>>>> bcd8b8924468 (snapshot) -// RUN: %clang_cc1 -verify=CONSTEXPR14,CONSTEXPR_BEFORE23,CONSTEXPR_BEFORE20,CONSTEXPR_ALL -std=c++14 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr -// RUN: %clang_cc1 -verify=CONSTEXPR17,CONSTEXPR_BEFORE23,CONSTEXPR_BEFORE20,CONSTEXPR_ALL -std=c++17 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr -// RUN: %clang_cc1 -verify=CONSTEXPR20,CONSTEXPR_BEFORE23,CONSTEXPR_ALL -std=c++20 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr -// RUN: %clang_cc1 -verify=CONSTEXPR23,CONSTEXPR_ALL -std=c++23 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr -// RUN: %clang_cc1 -verify=CONSTEXPR26,CONSTEXPR_ALL -std=c++26 %s -fcolor-diagnostics -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=IMPLICIT14,IMPLICIT_ALL -std=c++14 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT17,IMPLICIT_ALL -std=c++17 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT20,IMPLICIT_ALL -std=c++20 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT23,IMPLICIT_ALL -std=c++23 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -verify=IMPLICIT26,IMPLICIT_ALL -std=c++26 %s -fcxx-exceptions -DCONSTEXPR= -fimplicit-constexpr -fexperimental-new-constant-interpreter + +// RUN: %clang_cc1 -verify=CONSTEXPR14,CONSTEXPR_BEFORE23,CONSTEXPR_BEFORE20,CONSTEXPR_ALL -std=c++14 %s -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR17,CONSTEXPR_BEFORE23,CONSTEXPR_BEFORE20,CONSTEXPR_ALL -std=c++17 %s -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR20,CONSTEXPR_BEFORE23,CONSTEXPR_ALL -std=c++20 %s -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR23,CONSTEXPR_ALL -std=c++23 %s -fcxx-exceptions -DCONSTEXPR=constexpr +// RUN: %clang_cc1 -verify=CONSTEXPR26,CONSTEXPR_ALL -std=c++26 %s -fcxx-exceptions -DCONSTEXPR=constexpr // Objective is to make sure features like allocation / throwing won't fail code by just adding implicit constexpr // in an unevaluated code. diff --git a/clang/test/Sema/implicit-constexpr-members.cpp b/clang/test/Sema/implicit-constexpr-members.cpp index 498f8325c4234..6899d99ce36f1 100644 --- a/clang/test/Sema/implicit-constexpr-members.cpp +++ b/clang/test/Sema/implicit-constexpr-members.cpp @@ -1,14 +1,32 @@ -// RUN: %clang_cc1 -verify=NORMAL14,BOTH14,ALLNORMAL,ALL -std=c++14 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT14,BOTH14,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++14 %s -fcolor-diagnostics +<<<<<<< HEAD +// RUN: %clang_cc1 -verify=NORMAL14,BOTH14,ALLNORMAL,ALL -std=c++14 %s +// RUN: %clang_cc1 -verify=IMPLICIT14,BOTH14,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++14 %s +// RUN: %clang_cc1 -verify=IMPLICIT14,BOTH14,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++14 %s -fexperimental-new-constant-interpreter + +// RUN: %clang_cc1 -verify=NORMAL17,BOTH20,ALLNORMAL,ALL -std=c++17 %s +// RUN: %clang_cc1 -verify=IMPLICIT17,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++17 %s +// RUN: %clang_cc1 -verify=IMPLICIT17,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++17 %s -fexperimental-new-constant-interpreter + +// RUN: %clang_cc1 -verify=NORMAL20,BOTH20,ALLNORMAL,ALL -std=c++20 %s +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++20 %s +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++20 %s -fexperimental-new-constant-interpreter + +// RUN: %clang_cc1 -verify=NORMAL23,BOTH23,ALLNORMAL,ALL -std=c++23 %s +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s -fexperimental-new-constant-interpreter +======= +// RUN: %clang_cc1 -verify=NORMAL14,BOTH14,ALLNORMAL,ALL -std=c++14 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT14,BOTH14,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++14 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -verify=NORMAL17,BOTH20,ALLNORMAL,ALL -std=c++17 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT17,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++17 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT17,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++17 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -verify=NORMAL20,BOTH20,ALLNORMAL,ALL -std=c++20 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++20 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT20,BOTH20,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++20 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -verify=NORMAL23,BOTH23,ALLNORMAL,ALL -std=c++23 %s -fcolor-diagnostics -// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics +// RUN: %clang_cc1 -verify=IMPLICIT23,BOTH23,ALLIMPLICIT,ALL -fimplicit-constexpr -std=c++23 %s -fcolor-diagnostics -fexperimental-new-constant-interpreter +>>>>>>> bcd8b8924468 (snapshot) // ALLIMPLICIT-no-diagnostics From f2d5bfa629784132bf8176e137de9bedc3c19a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hana=20Dusi=CC=81kova=CC=81?= <hani...@hanicka.net> Date: Mon, 21 Apr 2025 22:57:37 +0200 Subject: [PATCH 5/5] [clang] add -fimplicit-constexpr flag: add more tests --- clang/test/Sema/implicit-constexpr-chain.cpp | 88 ++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 clang/test/Sema/implicit-constexpr-chain.cpp diff --git a/clang/test/Sema/implicit-constexpr-chain.cpp b/clang/test/Sema/implicit-constexpr-chain.cpp new file mode 100644 index 0000000000000..564c74af34839 --- /dev/null +++ b/clang/test/Sema/implicit-constexpr-chain.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -verify=BEFORE -std=c++23 %s +// RUN: %clang_cc1 -verify=AFTER -std=c++23 %s -fimplicit-constexpr + +// AFTER-no-diagnostics + +// FOLLOWING TWO EXAMPLES ESTABLISH THE `-fimplicit-constexpr` allows enter to constant evaluation for functions +// which would be disabled based on: +// [expr.const]#10.3 "an invocation of a non-constexpr function" (is not allowed) + +// ------------------- + +inline int normal_function() { + // BEFORE-note@-1 {{declared here}} + return 42; +} + +constinit auto cinit = normal_function(); +// BEFORE-error@-1 {{variable does not have a constant initializer}} +// BEFORE-note@-2 {{required by 'constinit' specifier here}} +// BEFORE-note@-3 {{non-constexpr function 'normal_function' cannot be used in a constant expression}} + +// ------------------- + +inline int still_normal_function() { + // BEFORE-note@-1 {{declared here}} + return 42; +} + +constexpr auto cxpr = still_normal_function(); +// BEFORE-error@-1 {{constexpr variable 'cxpr' must be initialized by a constant expression}} +// BEFORE-note@-2 {{non-constexpr function 'still_normal_function' cannot be used in a constant expression}} + +// ------------------- + +// Following example shows calling non-constexpr marked function in +// constant evaluated context is no longer an error. + +struct type_with_nonconstexpr_static_function { + static /* non-constexpr */ int square(int v) { + // BEFORE-note@-1 {{declared here}} + return v*v; + } + + int value; + constexpr type_with_nonconstexpr_static_function(int x): value{square(x)} { } + // BEFORE-note@-1 {{non-constexpr function 'square' cannot be used in a constant expression}} + // ^ (Hana's note: during evaluation) +}; + +constexpr auto force_ce = type_with_nonconstexpr_static_function{4}; +// BEFORE-error@-1 {{constexpr variable 'force_ce' must be initialized by a constant expression}} +// BEFORE-note@-2 {{in call to 'type_with_nonconstexpr_static_function(4)'}} + + +// this is fine: as it's in runtime, where the constructor +// is called in runtime, like a normal function, so it doesn't matter `square` is not constexpr +static auto static_var = type_with_nonconstexpr_static_function{4}; + + + +// ------------------- + +// Following example shows now you can call non-constexpr marked even +// from consteval function initiated constant evaluation. + +inline int runtime_only_function() { + // BEFORE-note@-1 {{declared here}} + return 11; +} + +constexpr int constexpr_function() { + return runtime_only_function(); + // BEFORE-note@-1 {{non-constexpr function 'runtime_only_function' cannot be used in a constant expression}} +} + +consteval int consteval_function() { + return constexpr_function(); + // BEFORE-note@-1 {{in call to 'constexpr_function()'}} +} + +static int noncalled_runtime_function() { + // we enter consteval context here to replace `consteval_function()` with a constant. + // this is happen during parsing!! + return consteval_function(); + // BEFORE-error@-1 {{call to consteval function 'consteval_function' is not a constant expression}} + // BEFORE-note@-2 {{in call to 'consteval_function()'}} +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits