Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,7 @@ Conditional ``explicit`` __cpp_conditional_explicit C++20
``if consteval`` __cpp_if_consteval C++23 C++20
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
Relaxing some constexpr restrictions __cpp_constexpr C++23 C++11
-------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Array & element qualification (N2607) C23 C89
Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ C++23 Feature Support
- Added a separate warning to warn the use of attributes on lambdas as a C++23 extension
in previous language versions: ``-Wc++23-lambda-attributes``.

- Implemented `P2448R2: Relaxing some constexpr restrictions <https://wg21.link/P2448R2>`_
as a conforming extension.

C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^

Expand Down
42 changes: 26 additions & 16 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2765,10 +2765,14 @@ def err_constexpr_tag : Error<
"cannot be marked %sub{select_constexpr_spec_kind}1">;
def err_constexpr_dtor : Error<
"destructor cannot be declared %sub{select_constexpr_spec_kind}0">;
def err_constexpr_dtor_subobject : Error<
"destructor cannot be declared %sub{select_constexpr_spec_kind}0 because "
def ext_constexpr_dtor_subobject : ExtWarn<
"destructor cannot be declared %sub{select_constexpr_spec_kind}0 before C++23 because "
"%select{data member %2|base class %3}1 does not have a "
"constexpr destructor">;
"constexpr destructor">, InGroup<CXX23>, DefaultError;
def warn_cxx23_compat_constexpr_dtor_subobject : ExtWarn<
"%sub{select_constexpr_spec_kind}0 destructor is incompatible with C++ standards before C++23 because "
"%select{data member %2|base class %3}1 does not have a "
"constexpr destructor">, InGroup<CXXPre23Compat>, DefaultIgnore;
def note_constexpr_dtor_subobject : Note<
"%select{data member %1|base class %2}0 declared here">;
def err_constexpr_wrong_decl_kind : Error<
Expand Down Expand Up @@ -2800,11 +2804,14 @@ def note_non_literal_incomplete : Note<
def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 "
"with virtual base %plural{1:class|:classes}1 is not a literal type">;
def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
def err_constexpr_non_literal_return : Error<
"%select{constexpr|consteval}0 function's return type %1 is not a literal type">;
def err_constexpr_non_literal_param : Error<
"%select{constexpr|consteval}2 %select{function|constructor}1's %ordinal0 parameter type %3 is "
"not a literal type">;
def ext_constexpr_non_literal_return : ExtWarn<
"%select{constexpr|consteval}0 function with non-literal return type %1 is a C++23 extension">, InGroup<CXX23>, DefaultError;
def warn_cxx23_compat_constexpr_non_literal_return : Warning<
"%select{constexpr|consteval}0 function with non-literal return type %1 is incompatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
def ext_constexpr_non_literal_param : ExtWarn<
"%select{constexpr|consteval}2 %select{function|constructor}1 with %ordinal0 non-literal parameter type %3 is a C++23 extension">, InGroup<CXX23>, DefaultError;
def warn_cxx23_compat_constexpr_non_literal_param : Warning<
"%select{constexpr|consteval}2 %select{function|constructor}1 with %ordinal0 non-literal parameter type %3 is not compatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
def err_constexpr_body_invalid_stmt : Error<
"statement not allowed in %select{constexpr|consteval}1 %select{function|constructor}0">;
def ext_constexpr_body_invalid_stmt : ExtWarn<
Expand Down Expand Up @@ -2865,8 +2872,11 @@ def warn_cxx17_compat_constexpr_local_var_no_init : Warning<
"is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_constexpr_function_never_constant_expr : ExtWarn<
"%select{constexpr|consteval}1 %select{function|constructor}0 never produces a "
"constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
"%select{constexpr|consteval}1 %select{function|constructor}0 that never produces a "
"constant expression is a C++23 extension">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
def warn_cxx23_compat_constexpr_function_never_constant_expr : Warning<
"%select{constexpr|consteval}1 %select{function|constructor}0 that never produces a "
"constant expression is incompatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
def err_attr_cond_never_constant_expr : Error<
"%0 attribute expression never produces a constant expression">;
def err_diagnose_if_invalid_diagnostic_type : Error<
Expand Down Expand Up @@ -9539,14 +9549,14 @@ def err_defaulted_special_member_copy_const_param : Error<
def err_defaulted_copy_assign_not_ref : Error<
"the parameter for an explicitly-defaulted copy assignment operator must be an "
"lvalue reference type">;
def err_incorrect_defaulted_constexpr : Error<
"defaulted definition of %sub{select_special_member_kind}0 "
"is not constexpr">;
def ext_incorrect_defaulted_constexpr : ExtWarn<
"defaulted definition of %sub{select_special_member_kind}0 that marked %select{constexpr|consteval}1 "
"but never produces a constant expression is a C++23 extension">, InGroup<CXX23>, DefaultError;
def warn_cxx23_compat_incorrect_defaulted_constexpr : Warning<
"defaulted definition of %sub{select_special_member_kind}0 that marked %select{constexpr|consteval}1 "
"but never produces a constant expression is incompatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
def err_incorrect_defaulted_constexpr_with_vb: Error<
"%sub{select_special_member_kind}0 cannot be 'constexpr' in a class with virtual base class">;
def err_incorrect_defaulted_consteval : Error<
"defaulted declaration of %sub{select_special_member_kind}0 "
"cannot be consteval because implicit definition is not constexpr">;
def warn_defaulted_method_deleted : Warning<
"explicitly defaulted %sub{select_special_member_kind}0 is implicitly "
"deleted">, InGroup<DefaultedFunctionDeleted>;
Expand Down
49 changes: 31 additions & 18 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1722,13 +1722,16 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
return true;

if (Kind == Sema::CheckConstexprKind::Diagnose) {
SemaRef.Diag(DD->getLocation(), diag::err_constexpr_dtor_subobject)
SemaRef.Diag(DD->getLocation(),
SemaRef.getLangOpts().CPlusPlus23
? diag::warn_cxx23_compat_constexpr_dtor_subobject
: diag::ext_constexpr_dtor_subobject)
<< static_cast<int>(DD->getConstexprKind()) << !FD
<< (FD ? FD->getDeclName() : DeclarationName()) << T;
SemaRef.Diag(Loc, diag::note_constexpr_dtor_subobject)
<< !FD << (FD ? FD->getDeclName() : DeclarationName()) << T;
}
return false;
return !!SemaRef.getLangOpts().CPlusPlus23;
};

const CXXRecordDecl *RD = DD->getParent();
Expand All @@ -1754,11 +1757,14 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
assert(PD && "null in a parameter list");
SourceLocation ParamLoc = PD->getLocation();
if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i,
diag::err_constexpr_non_literal_param, ArgIndex + 1,
PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
FD->isConsteval()))
return false;
if (CheckLiteralType(
SemaRef, Kind, ParamLoc, *i,
SemaRef.getLangOpts().CPlusPlus23
? diag::warn_cxx23_compat_constexpr_non_literal_param
: diag::ext_constexpr_non_literal_param,
ArgIndex + 1, PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
FD->isConsteval()))
return SemaRef.getLangOpts().CPlusPlus23;
}
return true;
}
Expand All @@ -1767,10 +1773,13 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
/// true. If not, produce a suitable diagnostic and return false.
static bool CheckConstexprReturnType(Sema &SemaRef, const FunctionDecl *FD,
Sema::CheckConstexprKind Kind) {
if (CheckLiteralType(SemaRef, Kind, FD->getLocation(), FD->getReturnType(),
diag::err_constexpr_non_literal_return,
FD->isConsteval()))
return false;
if (CheckLiteralType(
SemaRef, Kind, FD->getLocation(), FD->getReturnType(),
SemaRef.getLangOpts().CPlusPlus23
? diag::warn_cxx23_compat_constexpr_non_literal_return
: diag::ext_constexpr_non_literal_return,
FD->isConsteval()))
return SemaRef.getLangOpts().CPlusPlus23;
return true;
}

Expand Down Expand Up @@ -2458,8 +2467,11 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
SmallVector<PartialDiagnosticAt, 8> Diags;
if (Kind == Sema::CheckConstexprKind::Diagnose &&
!Expr::isPotentialConstantExpr(Dcl, Diags)) {
SemaRef.Diag(Dcl->getLocation(),
diag::ext_constexpr_function_never_constant_expr)
SemaRef.Diag(
Dcl->getLocation(),
SemaRef.getLangOpts().CPlusPlus23
? diag::warn_cxx23_compat_constexpr_function_never_constant_expr
: diag::ext_constexpr_function_never_constant_expr)
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
<< Dcl->getNameInfo().getSourceRange();
for (size_t I = 0, N = Diags.size(); I != N; ++I)
Expand Down Expand Up @@ -7851,14 +7863,15 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
<< CSM;
for (const auto &I : RD->vbases())
Diag(I.getBeginLoc(), diag::note_constexpr_virtual_base_here);
HadError = true;
} else {
Diag(MD->getBeginLoc(), MD->isConsteval()
? diag::err_incorrect_defaulted_consteval
: diag::err_incorrect_defaulted_constexpr)
<< CSM;
Diag(MD->getBeginLoc(),
getLangOpts().CPlusPlus23
? diag::warn_cxx23_compat_incorrect_defaulted_constexpr
: diag::ext_incorrect_defaulted_constexpr)
<< CSM << MD->isConsteval();
}
// FIXME: Explain why the special member can't be constexpr.
HadError = true;
}

if (First) {
Expand Down
24 changes: 6 additions & 18 deletions clang/test/AST/Interp/cxx23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,45 @@

/// FIXME: The new interpreter is missing all the 'control flows through...' diagnostics.

constexpr int f(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
constexpr int f(int n) { // ref20-error {{constexpr function that never produces a constant expression}}
static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a static variable}} \
// expected20-warning {{is a C++23 extension}}

return m;
}
constexpr int g(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
constexpr int g(int n) { // ref20-error {{constexpr function that never produces a constant expression}}
thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a thread_local variable}} \
// expected20-warning {{is a C++23 extension}}
return m;
}

constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
constexpr int c_thread_local(int n) { // ref20-error {{constexpr function that never produces a constant expression}}
static _Thread_local int m = 0; // ref20-note {{control flows through the definition of a thread_local variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a thread_local variable}} \
// expected20-warning {{is a C++23 extension}}
return m;
}


constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function that never produces a constant expression}}
static __thread int m = 0; // ref20-note {{control flows through the definition of a thread_local variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a thread_local variable}} \
// expected20-warning {{is a C++23 extension}}
return m;
}

constexpr int h(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
constexpr int h(int n) { // ref20-error {{constexpr function that never produces a constant expression}}
static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a static variable}} \
// expected20-warning {{is a C++23 extension}}
return &m - &m;
}

constexpr int i(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
constexpr int i(int n) { // ref20-error {{constexpr function that never produces a constant expression}}
thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a thread_local variable}} \
// expected20-warning {{is a C++23 extension}}
return &m - &m;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/Interp/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ namespace SizeOf {

#if __cplusplus >= 202002L
/// FIXME: The following code should be accepted.
consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}}
consteval int foo(int n) { // ref-error {{consteval function that never produces a constant expression}}
return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}}
}
constinit int var = foo(5); // ref-error {{not a constant expression}} \
Expand Down
8 changes: 4 additions & 4 deletions clang/test/AST/Interp/shifts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@


namespace shifts {
constexpr void test() { // ref-error {{constexpr function never produces a constant expression}} \
// ref-cxx17-error {{constexpr function never produces a constant expression}} \
// expected-error {{constexpr function never produces a constant expression}} \
// cxx17-error {{constexpr function never produces a constant expression}} \
constexpr void test() { // ref-error {{constexpr function that never produces a constant expression}} \
// ref-cxx17-error {{constexpr function that never produces a constant expression}} \
// expected-error {{constexpr function that never produces a constant expression}} \
// cxx17-error {{constexpr function that never produces a constant expression}} \

char c; // cxx17-warning {{uninitialized variable}} \
// ref-cxx17-warning {{uninitialized variable}}
Expand Down
Loading