Skip to content

Disable constexpr function body checking in more situations #94347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ C++23 Feature Support
- Implemented `P1774R8: Portable assumptions <https://wg21.link/P1774R8>`_.

- Implemented `P2448R2: Relaxing some constexpr restrictions <https://wg21.link/P2448R2>`_.
Note, the ``-Winvalid-constexpr`` diagnostic is now disabled in C++23 mode,
but can be explicitly specified to retain the old diagnostic checking
behavior.

- Added a ``__reference_converts_from_temporary`` builtin, completing the necessary compiler support for
`P2255R2: Type trait to determine if a reference binds to a temporary <https://wg21.link/P2255R2>`_.
Expand Down Expand Up @@ -323,6 +326,17 @@ Non-comprehensive list of changes in this release
- Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may
now be used within constant expressions.

- When compiling a constexpr function, Clang will check to see whether the
function can *never* be used in a constant expression context and issues a
diagnostic under the ``-Winvalid-constexpr`` diagostic flag (which defaults
to an error). This check can be expensive because the mere presence of a
function marked ``constexpr`` will cause us to undergo constant expression
evaluation, even if the function is not called within the translation unit
being compiled. Due to the expense, Clang no longer checks constexpr function
bodies when the function is defined in a system header file or when
``-Winvalid-constexpr`` is not enabled for the function definition, which
should result in mild compile-time performance improvements.

New Compiler Flags
------------------
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,14 @@ COMPATIBLE_LANGOPT(IncrementalExtensions, 1, 0, " True if we want to process sta

BENIGN_LANGOPT(CheckNew, 1, 0, "Do not assume C++ operator new may not return NULL")

// FIXME: It would be better for us to find a way to encode the state of this
// diagnostic in tablegen so that we can specify a particular diagnostic option
// is disabled or enabled based on other language options or made it easier to
// do this from the compiler invocation without hitting option round-tripping
// issues.
BENIGN_LANGOPT(CheckConstexprFunctionBodies, 1, 1,
"Emit diagnostics for a constexpr function body that can never "
"be used in a constant expression.")
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,17 @@ multiclass BoolMOption<string flag_base, KeyPathAndMacro kpm,
Group<m_Group>;
}

/// Creates a BoolOption where both of the flags are prefixed with "W", are in
/// the Group<W_Group>.
/// Used for -cc1 frontend options. Driver-only options do not map to
/// CompilerInvocation.
multiclass BoolWOption<string flag_base, KeyPathAndMacro kpm,
Default default, FlagDef flag1, FlagDef flag2,
BothFlags both = BothFlags<[]>> {
defm NAME : BoolOption<"W", flag_base, kpm, default, flag1, flag2, both>,
Group<W_Group>;
}

// Works like BoolOption except without marshalling
multiclass BoolOptionWithoutMarshalling<string prefix = "", string spelling_base,
FlagDef flag1_base, FlagDef flag2_base,
Expand Down Expand Up @@ -606,6 +617,7 @@ defvar cpp11 = LangOpts<"CPlusPlus11">;
defvar cpp14 = LangOpts<"CPlusPlus14">;
defvar cpp17 = LangOpts<"CPlusPlus17">;
defvar cpp20 = LangOpts<"CPlusPlus20">;
defvar cpp23 = LangOpts<"CPlusPlus23">;
defvar c99 = LangOpts<"C99">;
defvar c23 = LangOpts<"C23">;
defvar lang_std = LangOpts<"LangStd">;
Expand Down Expand Up @@ -961,6 +973,12 @@ def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>,
HelpText<"Enable warnings for deprecated constructs and define __DEPRECATED">;
def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group<W_Group>,
Visibility<[ClangOption, CC1Option]>;
defm invalid_constexpr : BoolWOption<"invalid-constexpr",
LangOpts<"CheckConstexprFunctionBodies">,
Default<!strconcat("!", cpp23.KeyPath)>,
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Disable">,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
BothFlags<[], [ClangOption, CC1Option], " checking of constexpr function bodies for validity within a constant expression context">>;
def Wl_COMMA : CommaJoined<["-"], "Wl,">, Visibility<[ClangOption, FlangOption]>,
Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass the comma separated arguments in <arg> to the linker">,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,9 @@ void CompilerInvocationBase::GenerateDiagnosticArgs(
// This option is automatically generated from UndefPrefixes.
if (Warning == "undef-prefix")
continue;
// This option is automatically generated from CheckConstexprFunctionBodies.
if (Warning == "invalid-constexpr" || Warning == "no-invalid-constexpr")
continue;
Consumer(StringRef("-W") + Warning);
}

Expand Down
15 changes: 11 additions & 4 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2469,11 +2469,18 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
// base class sub-objects shall be a constexpr constructor.
//
// Note that this rule is distinct from the "requirements for a constexpr
// function", so is not checked in CheckValid mode.
// function", so is not checked in CheckValid mode. Because the check for
// constexpr potential is expensive, skip the check if the diagnostic is
// disabled, the function is declared in a system header, or we're in C++23
// or later mode (see https://wg21.link/P2448).
bool SkipCheck =
!SemaRef.getLangOpts().CheckConstexprFunctionBodies ||
SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
SemaRef.getDiagnostics().isIgnored(
diag::ext_constexpr_function_never_constant_expr, Dcl->getLocation());
SmallVector<PartialDiagnosticAt, 8> Diags;
if (Kind == Sema::CheckConstexprKind::Diagnose &&
!Expr::isPotentialConstantExpr(Dcl, Diags) &&
!SemaRef.getLangOpts().CPlusPlus23) {
if (Kind == Sema::CheckConstexprKind::Diagnose && !SkipCheck &&
!Expr::isPotentialConstantExpr(Dcl, Diags)) {
SemaRef.Diag(Dcl->getLocation(),
diag::ext_constexpr_function_never_constant_expr)
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
Expand Down
26 changes: 26 additions & 0 deletions clang/test/SemaCXX/constexpr-never-constant.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -fcxx-exceptions %s
// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Winvalid-constexpr -verify -fcxx-exceptions %s
// Note: for a diagnostic that defaults to an error, -Wno-foo -Wfoo will
// disable the diagnostic and then re-enable it *as a warning* rather than as
// an error. So we manually enable it as an error again with -Werror to keep
// the diagnostic checks consistent.
// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Wno-invalid-constexpr -Winvalid-constexpr -Werror=invalid-constexpr -verify -fcxx-exceptions %s

// RUN: %clang_cc1 -fsyntax-only -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
// RUN: %clang_cc1 -fsyntax-only -std=c++23 -verify=good -fcxx-exceptions %s
// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Winvalid-constexpr -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
// RUN: %clang_cc1 -fsyntax-only -Wno-invalid-constexpr -verify=good -fcxx-exceptions %s
// good-no-diagnostics

constexpr void func() { // expected-error {{constexpr function never produces a constant expression}}
throw 12; // expected-note {{subexpression not valid in a constant expression}}
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winvalid-constexpr"
constexpr void other_func() {
#pragma clang diagnostic pop

throw 12;
}
Loading