diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d3055fed208286..a272cb741270f8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2721,9 +2721,9 @@ def ext_constexpr_static_var : ExtWarn< "definition of a %select{static|thread_local}1 variable " "in a constexpr %select{function|constructor}0 " "is a C++2b extension">, InGroup; -def warn_cxx20_compat_constexpr_static_var : Warning< - "definition of a %select{static|thread_local}1 variable " - "in a constexpr %select{function|constructor}0 " +def warn_cxx20_compat_constexpr_var : Warning< + "definition of a %select{static variable|thread_local variable|variable " + "of non-literal type}1 in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++2b">, InGroup, DefaultIgnore; def err_constexpr_local_var_non_literal_type : Error< diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 48fb642ad15e18..0f56e6024f332f 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1893,7 +1893,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag(VD->getLocation(), SemaRef.getLangOpts().CPlusPlus2b - ? diag::warn_cxx20_compat_constexpr_static_var + ? diag::warn_cxx20_compat_constexpr_var : diag::ext_constexpr_static_var) << isa(Dcl) << (VD->getTLSKind() == VarDecl::TLS_Dynamic); @@ -1901,11 +1901,17 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, return false; } } - if (!SemaRef.LangOpts.CPlusPlus2b && - CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(), - diag::err_constexpr_local_var_non_literal_type, - isa(Dcl))) + if (SemaRef.LangOpts.CPlusPlus2b) { + CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(), + diag::warn_cxx20_compat_constexpr_var, + isa(Dcl), + /*variable of non-literal type*/ 2); + } else if (CheckLiteralType( + SemaRef, Kind, VD->getLocation(), VD->getType(), + diag::err_constexpr_local_var_non_literal_type, + isa(Dcl))) { return false; + } if (!VD->getType()->isDependentType() && !VD->hasInit() && !VD->isCXXForRangeDecl()) { if (Kind == Sema::CheckConstexprKind::Diagnose) { diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp index 671895b278bdf0..3ba5cbba79ce26 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp @@ -25,17 +25,18 @@ constexpr void h() { label:; // expected-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++2b}} } -struct NonLiteral { +struct NonLiteral { // expected-note 2 {{'NonLiteral' is not literal}} NonLiteral() {} }; constexpr void non_literal() { // expected-error {{constexpr function never produces a constant expression}} - NonLiteral n; // expected-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}} + NonLiteral n; // expected-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}} \ + // expected-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++2b}} } constexpr void non_literal2(bool b) { if (!b) - NonLiteral n; + NonLiteral n; // expected-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++2b}} } constexpr int c_thread_local(int n) { diff --git a/clang/test/SemaCXX/constant-expression-cxx2b.cpp b/clang/test/SemaCXX/constant-expression-cxx2b.cpp index 0657a35947ade6..5a5fe6c1b7ab25 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2b.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2b.cpp @@ -1,7 +1,8 @@ // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx2a %s -fcxx-exceptions -triple=x86_64-linux-gnu -Wno-c++2b-extensions // RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx2b %s -fcxx-exceptions -triple=x86_64-linux-gnu -Wpre-c++2b-compat -struct NonLiteral { // cxx2a-note {{'NonLiteral' is not literal}} +struct NonLiteral { // cxx2a-note {{'NonLiteral' is not literal}} \ + // cxx2b-note 2{{'NonLiteral' is not literal}} NonLiteral() {} }; @@ -96,7 +97,7 @@ constexpr int thread_local_constexpr() { // expected-error {{constexpr function constexpr int non_literal(bool b) { if (!b) return 0; - NonLiteral n; + NonLiteral n; // cxx2b-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++2b}} } constexpr int non_literal_1 = non_literal(false); @@ -164,7 +165,8 @@ int test_in_lambdas() { auto non_literal = [](bool b) constexpr { if (!b) NonLiteral n; // cxx2b-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}} \ - // cxx2a-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++2b}} + // cxx2a-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++2b}} \ + // cxx2b-warning {{definition of a variable of non-literal type in a constexpr function is incompatible with C++ standards before C++2b}} return 0; }; @@ -227,7 +229,7 @@ int test_lambdas_implicitly_constexpr() { } template -constexpr auto dependent_var_def_lambda(void) { +constexpr auto dependent_var_def_lambda() { return [](bool b) { // cxx2a-note {{declared here}} if (!b) T t; @@ -237,4 +239,4 @@ constexpr auto dependent_var_def_lambda(void) { constexpr auto non_literal_valid_in_cxx2b = dependent_var_def_lambda()(true); // \ // cxx2a-error {{constexpr variable 'non_literal_valid_in_cxx2b' must be initialized by a constant expression}} \ - // cxx2a-note {{non-constexpr function}} + // cxx2a-note {{non-constexpr function}}