https://github.com/llukito updated https://github.com/llvm/llvm-project/pull/179233
>From 6ab49ef74a8de1b59aadad09681cbe62c159e1f7 Mon Sep 17 00:00:00 2001 From: Luka Aladashvili <[email protected]> Date: Mon, 2 Feb 2026 17:38:34 +0400 Subject: [PATCH 1/4] [clang][diagnostics] Refactor constexpr diagnostics to use enum_select Replaces %select{function|constructor} with %enum_select to improve clarity and type safety. --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 807440c107897..4d55ef460c928 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -23,9 +23,9 @@ defm typename_outside_of_template : CXX11Compat<"'typename' outside of a templat // C++14 compatibility with C++11 and earlier. defm constexpr_type_definition : CXX14Compat< - "type definition in a constexpr %select{function|constructor}0 is">; + "type definition in a constexpr %enum_select<Function, Constructor>0 is">; defm constexpr_local_var : CXX14Compat< - "variable declaration in a constexpr %select{function|constructor}0 is">; + "variable declaration in a constexpr %enum_select<Function, Constructor>0 is">; defm constexpr_body_multiple_return : CXX14Compat< "multiple return statements in constexpr function is">; defm variable_template : CXX14Compat<"variable templates are">; @@ -38,9 +38,9 @@ defm inline_variable : CXX17Compat<"inline variables are">; defm decomp_decl_spec : CXX20Compat<"structured binding declaration declared '%0' is">; defm constexpr_local_var_no_init : CXX20Compat< - "uninitialized variable in a constexpr %select{function|constructor}0 is">; + "uninitialized variable in a constexpr %enum_select<Function, Constructor>0 is">; defm constexpr_function_try_block : CXX20Compat< - "function try block in constexpr %select{function|constructor}0 is">; + "function try block in constexpr %enum_select<Function, Constructor>0 is">; defm constexpr_union_ctor_no_init : CXX20Compat< "constexpr union constructor that does not initialize any member is">; defm constexpr_ctor_missing_init : CXX20Compat< @@ -56,7 +56,7 @@ defm implicit_typename // C++23 compatibility with C++20 and earlier. defm constexpr_static_var : CXX23Compat< "definition of a %select{static|thread_local}1 variable " - "in a constexpr %select{function|constructor}0 " + "in a constexpr %enum_select<Function, Constructor>0 " "is">; // C++26 compatibility with C++23 and earlier. @@ -65,7 +65,7 @@ defm decomp_decl_cond : CXX26Compat<"structured binding declaration in a conditi // Compatibility warnings duplicated across multiple language versions. foreach std = [14, 20, 23] in { defm cxx#std#_constexpr_body_invalid_stmt : CXXCompat< - "use of this statement in a constexpr %select{function|constructor}0 is", std>; + "use of this statement in a constexpr %enum_select<Function, Constructor>0 is", std>; } def note_previous_decl : Note<"%0 declared here">; >From 71e1f6b3df0179dcebec2fc5fa1771fb7ae4be9c Mon Sep 17 00:00:00 2001 From: Luka Aladashvili <[email protected]> Date: Mon, 2 Feb 2026 18:33:57 +0400 Subject: [PATCH 2/4] Fix constexpr indentation and logic --- clang/lib/Sema/SemaDeclCXX.cpp | 35 ++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5837ecd6b9163..3b20a254c4a60 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2073,33 +2073,39 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, // thread storage duration or [before C++2a] for which no // initialization is performed. const auto *VD = cast<VarDecl>(DclIt); + + // Define the enum UP HERE so it is visible to all the checks below + enum { Function, Constructor }; + if (VD->isThisDeclarationADefinition()) { if (VD->isStaticLocal()) { if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.DiagCompat(VD->getLocation(), diag_compat::constexpr_static_var) - << isa<CXXConstructorDecl>(Dcl) + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function) << (VD->getTLSKind() == VarDecl::TLS_Dynamic); } else if (!SemaRef.getLangOpts().CPlusPlus23) { return false; } } + if (SemaRef.LangOpts.CPlusPlus23) { CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(), diag::warn_cxx20_compat_constexpr_var, - isa<CXXConstructorDecl>(Dcl)); + isa<CXXConstructorDecl>(Dcl) ? Constructor + : Function); } else if (CheckLiteralType( SemaRef, Kind, VD->getLocation(), VD->getType(), diag::err_constexpr_local_var_non_literal_type, - isa<CXXConstructorDecl>(Dcl))) { + isa<CXXConstructorDecl>(Dcl) ? Constructor : Function)) { return false; } - if (!VD->getType()->isDependentType() && - !VD->hasInit() && !VD->isCXXForRangeDecl()) { + if (!VD->getType()->isDependentType() && !VD->hasInit() && + !VD->isCXXForRangeDecl()) { if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.DiagCompat(VD->getLocation(), diag_compat::constexpr_local_var_no_init) - << isa<CXXConstructorDecl>(Dcl); + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); } else if (!SemaRef.getLangOpts().CPlusPlus20) { return false; } @@ -2108,7 +2114,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, } if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.DiagCompat(VD->getLocation(), diag_compat::constexpr_local_var) - << isa<CXXConstructorDecl>(Dcl); + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); } else if (!SemaRef.getLangOpts().CPlusPlus14) { return false; } @@ -2382,6 +2388,10 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, // // This restriction is lifted in C++2a, as long as inner statements also // apply the general constexpr rules. + + // <--- START FIX + enum { Function, Constructor }; // Defined locally for this block + switch (Kind) { case Sema::CheckConstexprKind::CheckValid: if (!SemaRef.getLangOpts().CPlusPlus20) @@ -2391,11 +2401,12 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, case Sema::CheckConstexprKind::Diagnose: SemaRef.DiagCompat(Body->getBeginLoc(), diag_compat::constexpr_function_try_block) - << isa<CXXConstructorDecl>(Dcl); + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); break; } + // <--- END FIX } - + // - its function-body shall be [...] a compound-statement that contains only // [... list of cases ...] // @@ -2502,10 +2513,14 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, break; } } else if (ReturnStmts.size() > 1) { + // Define the enum locally again because the previous one is out of scope + enum { Function, Constructor }; + switch (Kind) { case Sema::CheckConstexprKind::Diagnose: SemaRef.DiagCompat(ReturnStmts.back(), - diag_compat::constexpr_body_multiple_return); + diag_compat::constexpr_body_multiple_return) + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) SemaRef.Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return); >From 374a0977cb76ef4c5828d6edb8b1c09bbe181aa8 Mon Sep 17 00:00:00 2001 From: Luka Aladashvili <[email protected]> Date: Mon, 2 Feb 2026 18:42:06 +0400 Subject: [PATCH 3/4] Fix remaining magic numbers --- clang/lib/Sema/SemaDeclCXX.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3b20a254c4a60..e8ef89e16878e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2049,10 +2049,11 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::CXXRecord: // C++1y allows types to be defined, not just declared. if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) { + enum { Function, Constructor }; // Define enum locally if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.DiagCompat(DS->getBeginLoc(), diag_compat::constexpr_type_definition) - << isa<CXXConstructorDecl>(Dcl); + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); } else if (!SemaRef.getLangOpts().CPlusPlus14) { return false; } @@ -2427,15 +2428,18 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, (Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) || (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17)) return false; - } else if (Cxx2bLoc.isValid()) { - SemaRef.DiagCompat(Cxx2bLoc, diag_compat::cxx23_constexpr_body_invalid_stmt) - << isa<CXXConstructorDecl>(Dcl); - } else if (Cxx2aLoc.isValid()) { - SemaRef.DiagCompat(Cxx2aLoc, diag_compat::cxx20_constexpr_body_invalid_stmt) - << isa<CXXConstructorDecl>(Dcl); - } else if (Cxx1yLoc.isValid()) { - SemaRef.DiagCompat(Cxx1yLoc, diag_compat::cxx14_constexpr_body_invalid_stmt) - << isa<CXXConstructorDecl>(Dcl); + } else { + enum { Function, Constructor }; + if (Cxx2bLoc.isValid()) { + SemaRef.DiagCompat(Cxx2bLoc, diag_compat::cxx23_constexpr_body_invalid_stmt) + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); + } else if (Cxx2aLoc.isValid()) { + SemaRef.DiagCompat(Cxx2aLoc, diag_compat::cxx20_constexpr_body_invalid_stmt) + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); + } else if (Cxx1yLoc.isValid()) { + SemaRef.DiagCompat(Cxx1yLoc, diag_compat::cxx14_constexpr_body_invalid_stmt) + << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); + } } if (const CXXConstructorDecl *Constructor >From a40e1d16471f0fe6e283bf6cc847d9951aba452a Mon Sep 17 00:00:00 2001 From: Luka Aladashvili <[email protected]> Date: Mon, 2 Feb 2026 18:58:11 +0400 Subject: [PATCH 4/4] [clang][diagnostics] Hoist enum definitions to function scope to fix magic numbers --- clang/lib/Sema/SemaDeclCXX.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e8ef89e16878e..2afe13d818dd2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2012,6 +2012,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, // C++11 [dcl.constexpr]p3 and p4: // The definition of a constexpr function(p3) or constructor(p4) [...] shall // contain only + enum { Function = 0, Constructor = 1 }; for (const auto *DclIt : DS->decls()) { switch (DclIt->getKind()) { case Decl::StaticAssert: @@ -2049,7 +2050,6 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::CXXRecord: // C++1y allows types to be defined, not just declared. if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) { - enum { Function, Constructor }; // Define enum locally if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.DiagCompat(DS->getBeginLoc(), diag_compat::constexpr_type_definition) @@ -2075,8 +2075,6 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, // initialization is performed. const auto *VD = cast<VarDecl>(DclIt); - // Define the enum UP HERE so it is visible to all the checks below - enum { Function, Constructor }; if (VD->isThisDeclarationADefinition()) { if (VD->isStaticLocal()) { @@ -2215,6 +2213,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, SourceLocation &Cxx2bLoc, Sema::CheckConstexprKind Kind) { // - its function-body shall be [...] a compound-statement that contains only + enum { Function = 0, Constructor = 1 }; switch (S->getStmtClass()) { case Stmt::NullStmtClass: // - null statements, @@ -2374,6 +2373,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *Body, Sema::CheckConstexprKind Kind) { + enum { Function = 0, Constructor = 1 }; SmallVector<SourceLocation, 4> ReturnStmts; if (isa<CXXTryStmt>(Body)) { @@ -2389,9 +2389,6 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, // // This restriction is lifted in C++2a, as long as inner statements also // apply the general constexpr rules. - - // <--- START FIX - enum { Function, Constructor }; // Defined locally for this block switch (Kind) { case Sema::CheckConstexprKind::CheckValid: @@ -2405,7 +2402,6 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); break; } - // <--- END FIX } // - its function-body shall be [...] a compound-statement that contains only @@ -2429,7 +2425,6 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17)) return false; } else { - enum { Function, Constructor }; if (Cxx2bLoc.isValid()) { SemaRef.DiagCompat(Cxx2bLoc, diag_compat::cxx23_constexpr_body_invalid_stmt) << (isa<CXXConstructorDecl>(Dcl) ? Constructor : Function); @@ -2516,10 +2511,7 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, return false; break; } - } else if (ReturnStmts.size() > 1) { - // Define the enum locally again because the previous one is out of scope - enum { Function, Constructor }; - + } else if (ReturnStmts.size() > 1) { switch (Kind) { case Sema::CheckConstexprKind::Diagnose: SemaRef.DiagCompat(ReturnStmts.back(), _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
