https://github.com/Tsche updated https://github.com/llvm/llvm-project/pull/204682
>From 7308208bd27ab123bd6f3bcd97f15581f2e05d1e Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Thu, 18 Jun 2026 22:57:28 +0200 Subject: [PATCH 1/4] [clang] improve diagnostics for enums --- clang/lib/AST/StmtPrinter.cpp | 15 +++++++++++++++ .../test/Misc/diag-template-diffing-cxx11.cpp | 2 +- clang/test/SemaCXX/static-assert.cpp | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 9a97d52fd3020..938aca6b01380 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1882,6 +1882,21 @@ void StmtPrinter::VisitMatrixElementExpr(MatrixElementExpr *Node) { } void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { + // special case enums to avoid producing cast expressions when naming + // an enumerator would suffice + if (QualType T = Node->getType(); T->isEnumeralType()) { + const auto *IL = dyn_cast<IntegerLiteral>(Node->getSubExpr()); + const auto *ED = T->getAsEnumDecl(); + if (IL && ED) { + llvm::APInt Val = IL->getValue(); + for (const EnumConstantDecl *ECD : ED->enumerators()) { + if (llvm::APInt::isSameValue(ECD->getInitVal(), Val)) { + ECD->printQualifiedName(OS, Policy); + return; + } + } + } + } OS << '('; Node->getTypeAsWritten().print(OS, Policy); OS << ')'; diff --git a/clang/test/Misc/diag-template-diffing-cxx11.cpp b/clang/test/Misc/diag-template-diffing-cxx11.cpp index 0b145475fe191..e543a3a132489 100644 --- a/clang/test/Misc/diag-template-diffing-cxx11.cpp +++ b/clang/test/Misc/diag-template-diffing-cxx11.cpp @@ -1451,7 +1451,7 @@ void run() { D<X::X1>(VectorType<X::X2>()); } // CHECK-ELIDE-NOTREE: error: no matching function for call to 'D' -// CHECK-ELIDE-NOTREE: note: candidate function template not viable: no known conversion from 'VectorType<X::X2>' to 'const VectorType<(X)0>' for 1st argument +// CHECK-ELIDE-NOTREE: note: candidate function template not viable: no known conversion from 'VectorType<X::X2>' to 'const VectorType<TypeAlias::X::X1>' for 1st argument } namespace TypeAlias2 { diff --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp index c48791203733b..d3f139ad625c2 100644 --- a/clang/test/SemaCXX/static-assert.cpp +++ b/clang/test/SemaCXX/static-assert.cpp @@ -363,4 +363,22 @@ namespace Diagnostics { // expected-note {{evaluates to '1 == 2'}} static_assert(1 << 3 != 8, ""); // expected-error {{failed}} \ // expected-note {{evaluates to '8 != 8'}} + enum class TestEnum { + A = 0, + B = 1 + }; + + template<TestEnum E> struct EnumTemplate { + static_assert(E == TestEnum::B, ""); // #enum-assert + }; + + EnumTemplate<TestEnum::A> test1; + // expected-error@#enum-assert {{static assertion failed due to requirement 'Diagnostics::TestEnum::A == Diagnostics::TestEnum::B': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnum::A>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '0 == 1'}} + + EnumTemplate<TestEnum(42)> test2; + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::TestEnum)42 == Diagnostics::TestEnum::B': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<42>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '42 == 1'}} } >From 93acdf5a12a3e8fbc80d25c59bcfe2a7a16ccb81 Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Tue, 23 Jun 2026 23:11:34 +0200 Subject: [PATCH 2/4] add tests, move comment --- clang/lib/AST/StmtPrinter.cpp | 5 ++- clang/test/SemaCXX/static-assert.cpp | 66 +++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 938aca6b01380..8a70fa51c07b1 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1882,9 +1882,10 @@ void StmtPrinter::VisitMatrixElementExpr(MatrixElementExpr *Node) { } void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { - // special case enums to avoid producing cast expressions when naming - // an enumerator would suffice if (QualType T = Node->getType(); T->isEnumeralType()) { + // special case enums to avoid producing cast expressions when naming + // an enumerator would suffice + const auto *IL = dyn_cast<IntegerLiteral>(Node->getSubExpr()); const auto *ED = T->getAsEnumDecl(); if (IL && ED) { diff --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp index d3f139ad625c2..d17b50f730f5f 100644 --- a/clang/test/SemaCXX/static-assert.cpp +++ b/clang/test/SemaCXX/static-assert.cpp @@ -368,17 +368,63 @@ namespace Diagnostics { B = 1 }; - template<TestEnum E> struct EnumTemplate { - static_assert(E == TestEnum::B, ""); // #enum-assert + enum class WithUnderlying : unsigned{ + A = 0, + B = 1 + }; + + enum TestEnumUnscoped { + TEST_A = 0, + TEST_B = 1, + TEST_C = 3 }; - EnumTemplate<TestEnum::A> test1; - // expected-error@#enum-assert {{static assertion failed due to requirement 'Diagnostics::TestEnum::A == Diagnostics::TestEnum::B': }} \ - // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnum::A>' requested here}} \ - // expected-note@#enum-assert {{evaluates to '0 == 1'}} + enum WithUnderlyingUnscoped : unsigned { + TEST2_A = 0, + TEST2_B = 1 + }; + + template<typename T, T E> struct EnumTemplate { + static_assert(E == (T)0, ""); // #enum-assert + }; - EnumTemplate<TestEnum(42)> test2; - // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::TestEnum)42 == Diagnostics::TestEnum::B': }} \ - // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<42>' requested here}} \ - // expected-note@#enum-assert {{evaluates to '42 == 1'}} + EnumTemplate<TestEnum, TestEnum::B> test1; + // expected-error@#enum-assert {{static assertion failed due to requirement 'Diagnostics::TestEnum::B == Diagnostics::TestEnum::A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnum, Diagnostics::TestEnum::B>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '1 == 0'}} + + EnumTemplate<TestEnum, TestEnum(42)> test2; + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::TestEnum)42 == Diagnostics::TestEnum::A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnum, (Diagnostics::TestEnum)42>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '42 == 0'}} + + EnumTemplate<WithUnderlying, WithUnderlying::B> test3; + // expected-error@#enum-assert {{static assertion failed due to requirement 'Diagnostics::WithUnderlying::B == Diagnostics::WithUnderlying::A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlying, Diagnostics::WithUnderlying::B>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '1 == 0'}} + + EnumTemplate<WithUnderlying, WithUnderlying(42)> test6; + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::WithUnderlying)42 == Diagnostics::WithUnderlying::A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlying, (Diagnostics::WithUnderlying)42>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '42 == 0'}} + + EnumTemplate<TestEnumUnscoped, TestEnumUnscoped::TEST_B> test4; + // expected-error@#enum-assert {{static assertion failed due to requirement 'Diagnostics::TEST_B == Diagnostics::TEST_A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnumUnscoped, Diagnostics::TEST_B>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '1 == 0'}} + + EnumTemplate<TestEnumUnscoped, TestEnumUnscoped(2)> test7; + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::TestEnumUnscoped)2 == Diagnostics::TEST_A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnumUnscoped, (Diagnostics::TestEnumUnscoped)2>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '2 == 0'}} + + EnumTemplate<WithUnderlyingUnscoped, WithUnderlyingUnscoped::TEST2_B> test5; + // expected-error@#enum-assert {{static assertion failed due to requirement 'Diagnostics::TEST2_B == Diagnostics::TEST2_A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlyingUnscoped, Diagnostics::TEST2_B>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '1 == 0'}} + + EnumTemplate<WithUnderlyingUnscoped, WithUnderlyingUnscoped(42)> test8; + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::WithUnderlyingUnscoped)42 == Diagnostics::TEST2_A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlyingUnscoped, (Diagnostics::WithUnderlyingUnscoped)42>' requested here}} \ + // expected-note@#enum-assert {{evaluates to '42 == 0'}} } >From 161eb562a0898d883bcf9685007f8f3d75896518 Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Sun, 19 Jul 2026 03:48:59 +0200 Subject: [PATCH 3/4] disable enum pretty printing in ast-print mode --- clang/include/clang/AST/PrettyPrinter.h | 7 ++++++- clang/lib/AST/StmtPrinter.cpp | 14 ++++++++------ clang/lib/Frontend/ASTConsumers.cpp | 1 + clang/test/AST/ast-print-enum-decl.c | 3 +++ clang/test/SemaCXX/static-assert.cpp | 14 +++++++------- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index f95d54c0f05b9..c6555215ce20a 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -93,7 +93,7 @@ struct PrintingPolicy { PrintAsCanonical(false), PrintInjectedClassNameWithArguments(true), UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false), CleanUglifiedParameters(false), EntireContentsOfLargeArray(true), - UseEnumerators(true), UseHLSLTypes(LO.HLSL), + PrettyEnums(true), UseEnumerators(true), UseHLSLTypes(LO.HLSL), SuppressDeclAttributes(false), SuppressLambdaBody(false) {} /// Adjust this printing policy for cases where it's known that we're @@ -357,6 +357,11 @@ struct PrintingPolicy { LLVM_PREFERRED_TYPE(bool) unsigned EntireContentsOfLargeArray : 1; + /// Whether to print enumerators with a matching enumerator name or via cast + // of an integer. + LLVM_PREFERRED_TYPE(bool) + unsigned PrettyEnums : 1; + /// Whether to print enumerator non-type template parameters with a matching /// enumerator name or via cast of an integer. LLVM_PREFERRED_TYPE(bool) diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 8a70fa51c07b1..4b709156cecad 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1882,7 +1882,7 @@ void StmtPrinter::VisitMatrixElementExpr(MatrixElementExpr *Node) { } void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { - if (QualType T = Node->getType(); T->isEnumeralType()) { + if (QualType T = Node->getType(); Policy.PrettyEnums && T->isEnumeralType()) { // special case enums to avoid producing cast expressions when naming // an enumerator would suffice @@ -1890,11 +1890,13 @@ void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { const auto *ED = T->getAsEnumDecl(); if (IL && ED) { llvm::APInt Val = IL->getValue(); - for (const EnumConstantDecl *ECD : ED->enumerators()) { - if (llvm::APInt::isSameValue(ECD->getInitVal(), Val)) { - ECD->printQualifiedName(OS, Policy); - return; - } + const auto ECD = + llvm::find_if(ED->enumerators(), [&](const EnumConstantDecl *ECD) { + return llvm::APInt::isSameValue(ECD->getInitVal(), Val); + }); + if (ECD != ED->enumerator_end()) { + ECD->printQualifiedName(OS, Policy); + return; } } } diff --git a/clang/lib/Frontend/ASTConsumers.cpp b/clang/lib/Frontend/ASTConsumers.cpp index ec678a71539d5..40995e32b67fa 100644 --- a/clang/lib/Frontend/ASTConsumers.cpp +++ b/clang/lib/Frontend/ASTConsumers.cpp @@ -99,6 +99,7 @@ namespace { } else if (OutputKind == Print) { PrintingPolicy Policy(D->getASTContext().getLangOpts()); Policy.IncludeTagDefinition = true; + Policy.PrettyEnums = false; D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true); } else if (OutputKind != None) { D->dump(Out, OutputKind == DumpFull, OutputFormat); diff --git a/clang/test/AST/ast-print-enum-decl.c b/clang/test/AST/ast-print-enum-decl.c index 411467348fb11..f88af682a00f5 100644 --- a/clang/test/AST/ast-print-enum-decl.c +++ b/clang/test/AST/ast-print-enum-decl.c @@ -108,3 +108,6 @@ enum fixedEnum : int { fixedEnumerator }; // PRINT-LABEL: enum fixedEnum : int { // PRINT-NEXT: fixedEnumerator // PRINT-NEXT: }; + +enum fixedEnum fixedEnumVar = (enum fixedEnum)0; +//PRINT-LABEL: enum fixedEnum fixedEnumVar = (enum fixedEnum)0; diff --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp index d17b50f730f5f..dcaaaafd82445 100644 --- a/clang/test/SemaCXX/static-assert.cpp +++ b/clang/test/SemaCXX/static-assert.cpp @@ -395,7 +395,7 @@ namespace Diagnostics { EnumTemplate<TestEnum, TestEnum(42)> test2; // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::TestEnum)42 == Diagnostics::TestEnum::A': }} \ - // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnum, (Diagnostics::TestEnum)42>' requested here}} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnum, 42>' requested here}} \ // expected-note@#enum-assert {{evaluates to '42 == 0'}} EnumTemplate<WithUnderlying, WithUnderlying::B> test3; @@ -404,8 +404,8 @@ namespace Diagnostics { // expected-note@#enum-assert {{evaluates to '1 == 0'}} EnumTemplate<WithUnderlying, WithUnderlying(42)> test6; - // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::WithUnderlying)42 == Diagnostics::WithUnderlying::A': }} \ - // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlying, (Diagnostics::WithUnderlying)42>' requested here}} \ + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::WithUnderlying)42U == Diagnostics::WithUnderlying::A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlying, 42>' requested here}} \ // expected-note@#enum-assert {{evaluates to '42 == 0'}} EnumTemplate<TestEnumUnscoped, TestEnumUnscoped::TEST_B> test4; @@ -414,8 +414,8 @@ namespace Diagnostics { // expected-note@#enum-assert {{evaluates to '1 == 0'}} EnumTemplate<TestEnumUnscoped, TestEnumUnscoped(2)> test7; - // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::TestEnumUnscoped)2 == Diagnostics::TEST_A': }} \ - // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnumUnscoped, (Diagnostics::TestEnumUnscoped)2>' requested here}} \ + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::TestEnumUnscoped)2U == Diagnostics::TEST_A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::TestEnumUnscoped, 2>' requested here}} \ // expected-note@#enum-assert {{evaluates to '2 == 0'}} EnumTemplate<WithUnderlyingUnscoped, WithUnderlyingUnscoped::TEST2_B> test5; @@ -424,7 +424,7 @@ namespace Diagnostics { // expected-note@#enum-assert {{evaluates to '1 == 0'}} EnumTemplate<WithUnderlyingUnscoped, WithUnderlyingUnscoped(42)> test8; - // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::WithUnderlyingUnscoped)42 == Diagnostics::TEST2_A': }} \ - // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlyingUnscoped, (Diagnostics::WithUnderlyingUnscoped)42>' requested here}} \ + // expected-error@#enum-assert {{static assertion failed due to requirement '(Diagnostics::WithUnderlyingUnscoped)42U == Diagnostics::TEST2_A': }} \ + // expected-note@-1 {{in instantiation of template class 'Diagnostics::EnumTemplate<Diagnostics::WithUnderlyingUnscoped, 42>' requested here}} \ // expected-note@#enum-assert {{evaluates to '42 == 0'}} } >From 3fe480f148565b07ac28a59cfdce07aaa133b951 Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Sun, 19 Jul 2026 04:04:02 +0200 Subject: [PATCH 4/4] re-add release note --- clang/docs/ReleaseNotes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index a39bc2dfc5b6d..a67342be595c7 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -290,6 +290,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the against or converted to a null pointer, the same as a bare function name. (#GH46362) +- Clang now attempts to print enumerator names rather than C-style cast expressions + in more diagnostics. + ### Improvements to Clang's time-trace _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
