https://github.com/AaronBallman updated https://github.com/llvm/llvm-project/pull/147802
>From e65fa6bdd251ceef52e11ff8ee856058e8e3c47a Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Wed, 9 Jul 2025 14:40:00 -0400 Subject: [PATCH 1/8] [C23] Accept an _Atomic underlying type The underlying type of an enumeration is the non-atomic, unqualified version of the specified type. Clang was rejecting such enumerations, but now accepts them. Because we expose _Atomic in C++, the same behavior is carried over. Fixes #147736 --- clang/docs/ReleaseNotes.rst | 3 +++ clang/lib/Sema/SemaDecl.cpp | 20 +++++++++++++++++++ .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 10 ++++++++-- clang/test/C/C23/n3030_1.c | 13 ++++++++++++ clang/test/SemaCXX/enum-scoped.cpp | 13 ++++++++++++ 5 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 clang/test/C/C23/n3030_1.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 57a94242c9e61..4fc74f430e768 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -310,6 +310,9 @@ C23 Feature Support `WG14 N2975 <https://open-std.org/JTC1/SC22/WG14/www/docs/n2975.pdf>`_ - Fixed a bug with handling the type operand form of ``typeof`` when it is used to specify a fixed underlying type for an enumeration. #GH146351 +- Fixed a rejects-valid bug where Clang would reject an enumeration with an + ``_Atomic`` underlying type. The underlying type is the non-atomic, + unqualified version of the specified type. (#GH147736) C11 Feature Support ^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 11cbda412667f..e2c99e1bb0cb2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17152,6 +17152,13 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); QualType T = TI->getType(); + // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an + // integral type; any cv-qualification is ignored. + // C23 6.7.3.3p5: The underlying type of the enumeration is the unqualified, + // non-atomic version of the type specified by the type specifiers in the + // specifier qualifier list. + T = T.getAtomicUnqualifiedType(); + if (T->isDependentType()) return false; @@ -17551,6 +17558,9 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, } else if (UnderlyingType.get()) { // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an // integral type; any cv-qualification is ignored. + // C23 6.7.3.3p5: The underlying type of the enumeration is the + // unqualified, non-atomic version of the type specified by the type + // specifiers in the specifier qualifier list. TypeSourceInfo *TI = nullptr; GetTypeFromParser(UnderlyingType.get(), &TI); EnumUnderlying = TI; @@ -17563,6 +17573,16 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, UPPC_FixedUnderlyingType)) EnumUnderlying = Context.IntTy.getTypePtr(); + // If the underlying type is atomic, we need to adjust the type before + // continuing. This only happens in the case we stored a TypeSourceInfo + // into EnumUnderlying because the other cases are error recovery up to + // this point. But because it's not possible to gin up a TypeSourceInfo + // for a non-atomic type from an atomic one, we'll store into the Type + // field instead. + if (TypeSourceInfo *TI = dyn_cast<TypeSourceInfo *>(EnumUnderlying); + TI && TI->getType()->isAtomicType()) + EnumUnderlying = TI->getType().getAtomicUnqualifiedType().getTypePtr(); + } else if (Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) { // For MSVC ABI compatibility, unfixed enums must use an underlying type // of 'int'. However, if this is an unfixed forward declaration, don't set diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 70a4c159f9805..1608232f4553e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2022,8 +2022,14 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { DeclarationName()); if (!NewTI || SemaRef.CheckEnumUnderlyingType(NewTI)) Enum->setIntegerType(SemaRef.Context.IntTy); - else - Enum->setIntegerTypeSourceInfo(NewTI); + else { + // If the underlying type is atomic, we need to adjust the type before + // continuing. See C23 6.7.3.3p5 and Sema::ActOnTag(). + if (NewTI->getType()->isAtomicType()) + Enum->setIntegerType(NewTI->getType().getAtomicUnqualifiedType()); + else + Enum->setIntegerTypeSourceInfo(NewTI); + } // C++23 [conv.prom]p4 // if integral promotion can be applied to its underlying type, a prvalue diff --git a/clang/test/C/C23/n3030_1.c b/clang/test/C/C23/n3030_1.c new file mode 100644 index 0000000000000..4acfc007709ac --- /dev/null +++ b/clang/test/C/C23/n3030_1.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c23 -ast-dump %s | FileCheck %s + +// The underlying type is the unqualified, non-atomic version of the type +// specified. +enum const_enum : const short { ConstE }; +// CHECK: EnumDecl {{.*}} const_enum 'short' + +// These were previously being diagnosed as invalid underlying types. They +// are valid; the _Atomic is stripped from the underlying type. +enum atomic_enum1 : _Atomic(int) { AtomicE1 }; +// CHECK: EnumDecl {{.*}} atomic_enum1 'int' +enum atomic_enum2 : _Atomic long long { AtomicE2 }; +// CHECK: EnumDecl {{.*}} atomic_enum2 'long long' diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp index d7b7923430aff..f287d47107bc9 100644 --- a/clang/test/SemaCXX/enum-scoped.cpp +++ b/clang/test/SemaCXX/enum-scoped.cpp @@ -349,3 +349,16 @@ enum class B; A a; B b{a}; // expected-error {{cannot initialize}} } + +namespace GH147736 { +template <typename Ty> +struct S { + enum OhBoy : Ty { + Unimportant + } e; +}; + +// Okay, was previously rejected. The underlying type is int. +S<_Atomic(int)> s; // expected-warning {{'_Atomic' is a C11 extension}} +static_assert(__is_same(__underlying_type(S<_Atomic(long long)>::OhBoy), long long), ""); // expected-warning {{'_Atomic' is a C11 extension}} +} >From 8f5ce3496d2b8ab70470ca627a277f7bea7dac8a Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Wed, 9 Jul 2025 15:02:46 -0400 Subject: [PATCH 2/8] Move conversion to after the check for type dependence --- clang/lib/Sema/SemaDecl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e2c99e1bb0cb2..f77a6c88b3598 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17152,6 +17152,9 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); QualType T = TI->getType(); + if (T->isDependentType()) + return false; + // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an // integral type; any cv-qualification is ignored. // C23 6.7.3.3p5: The underlying type of the enumeration is the unqualified, @@ -17159,9 +17162,6 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { // specifier qualifier list. T = T.getAtomicUnqualifiedType(); - if (T->isDependentType()) - return false; - // This doesn't use 'isIntegralType' despite the error message mentioning // integral type because isIntegralType would also allow enum types in C. if (const BuiltinType *BT = T->getAs<BuiltinType>()) >From 1df979f8a8adb86af5a09e9f959eb594fcab3820 Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Wed, 9 Jul 2025 15:15:55 -0400 Subject: [PATCH 3/8] Add a codegen test --- clang/test/CodeGen/enum3.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 clang/test/CodeGen/enum3.c diff --git a/clang/test/CodeGen/enum3.c b/clang/test/CodeGen/enum3.c new file mode 100644 index 0000000000000..b06d0b7ca22ac --- /dev/null +++ b/clang/test/CodeGen/enum3.c @@ -0,0 +1,26 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c23 %s -emit-llvm -o - | FileCheck %s + +// Ensure that an "atomic" underlying type has no actual atomic semantics +// because the qualifier is stripped. + +enum E : _Atomic(int) { + Foo +}; + +// CHECK-LABEL: define {{.*}} void @test( +// CHECK-SAME: i32 noundef [[E:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[E_ADDR:%.*]] = alloca i32 +// CHECK-NEXT: [[X:%.*]] = alloca i32 +// CHECK-NEXT: store i32 [[E]], ptr [[E_ADDR]] +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[E_ADDR]] +// CHECK-NEXT: store i32 [[TMP0]], ptr [[X]] +// CHECK-NEXT: store i32 0, ptr [[E_ADDR]] +// CHECK-NEXT: ret void +// +void test(enum E e) { + int x = e; + e = Foo; +} + >From 9ba10c7a0074de8adbda7e3101ad269b846a1a5b Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Thu, 10 Jul 2025 08:09:12 -0400 Subject: [PATCH 4/8] Add a diagnostic --- clang/docs/ReleaseNotes.rst | 4 +++- clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/Sema/SemaDecl.cpp | 5 +++++ clang/test/C/C23/n3030.c | 4 ++++ clang/test/SemaCXX/enum-scoped.cpp | 4 +++- 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4fc74f430e768..50853ea894a0c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -312,7 +312,9 @@ C23 Feature Support to specify a fixed underlying type for an enumeration. #GH146351 - Fixed a rejects-valid bug where Clang would reject an enumeration with an ``_Atomic`` underlying type. The underlying type is the non-atomic, - unqualified version of the specified type. (#GH147736) + unqualified version of the specified type. Due to the perhaps surprising lack + of atomic behavior, this is diagnosed under ``-Watomic-qualifier-ignored``. + (#GH147736) C11 Feature Support ^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0b2553d82153c..d9fca37f74b03 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9364,6 +9364,10 @@ def warn_atomic_implicit_seq_cst : Warning< InGroup<DiagGroup<"atomic-implicit-seq-cst">>, DefaultIgnore; def err_atomic_unsupported : Error< "atomic types are not supported in '%0'">; +def warn_atomic_stripped_in_enum : Warning< + "'_Atomic' qualifier ignored; operations involving the enumeration type will " + "be non-atomic">, + InGroup<DiagGroup<"atomic-qualifier-ignored">>; def err_overflow_builtin_must_be_int : Error< "operand argument to %select{overflow builtin|checked integer operation}0 " diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f77a6c88b3598..24423e9de8e37 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17160,6 +17160,11 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { // C23 6.7.3.3p5: The underlying type of the enumeration is the unqualified, // non-atomic version of the type specified by the type specifiers in the // specifier qualifier list. + // Because of how odd C's rule is, we'll let the user know that operations + // involving the enumeration type will be non-atomic. + if (T->isAtomicType()) + Diag(UnderlyingLoc, diag::warn_atomic_stripped_in_enum); + T = T.getAtomicUnqualifiedType(); // This doesn't use 'isIntegralType' despite the error message mentioning diff --git a/clang/test/C/C23/n3030.c b/clang/test/C/C23/n3030.c index 17084bbb55f50..6ac7d64a9ca4d 100644 --- a/clang/test/C/C23/n3030.c +++ b/clang/test/C/C23/n3030.c @@ -91,3 +91,7 @@ enum e : short f = 0; // expected-error {{non-defining declaration of enumeratio enum g : short { yyy } h = yyy; enum ee2 : typeof ((enum ee3 : short { A })0, (short)0); + +enum not_actually_atomic : _Atomic(short) { // expected-warning {{'_Atomic' qualifier ignored; operations involving the enumeration type will be non-atomic}} + Surprise +}; diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp index f287d47107bc9..dbb4e6ae3948e 100644 --- a/clang/test/SemaCXX/enum-scoped.cpp +++ b/clang/test/SemaCXX/enum-scoped.cpp @@ -353,12 +353,14 @@ B b{a}; // expected-error {{cannot initialize}} namespace GH147736 { template <typename Ty> struct S { - enum OhBoy : Ty { + enum OhBoy : Ty { // expected-warning 2 {{'_Atomic' qualifier ignored; operations involving the enumeration type will be non-atomic}} Unimportant } e; }; // Okay, was previously rejected. The underlying type is int. S<_Atomic(int)> s; // expected-warning {{'_Atomic' is a C11 extension}} + // expected-note@-1 {{in instantiation of template class 'GH147736::S<_Atomic(int)>' requested here}} static_assert(__is_same(__underlying_type(S<_Atomic(long long)>::OhBoy), long long), ""); // expected-warning {{'_Atomic' is a C11 extension}} + // expected-note@-1 {{in instantiation of template class 'GH147736::S<_Atomic(long long)>' requested here}} } >From 45517caae9ced06dab4aea251c44dd044e415fed Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Thu, 10 Jul 2025 09:45:06 -0400 Subject: [PATCH 5/8] Add some FIXMEs --- clang/lib/Sema/SemaDecl.cpp | 4 +++- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 24423e9de8e37..bb1840d2b2695 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17583,7 +17583,9 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // into EnumUnderlying because the other cases are error recovery up to // this point. But because it's not possible to gin up a TypeSourceInfo // for a non-atomic type from an atomic one, we'll store into the Type - // field instead. + // field instead. FIXME: it would be nice to have an easy way to get a + // derived TypeSourceInfo which strips qualifiers including the weird + // ones like _Atomic where it forms a different type. if (TypeSourceInfo *TI = dyn_cast<TypeSourceInfo *>(EnumUnderlying); TI && TI->getType()->isAtomicType()) EnumUnderlying = TI->getType().getAtomicUnqualifiedType().getTypePtr(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1608232f4553e..e2c3cdcd536bc 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2024,7 +2024,10 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { Enum->setIntegerType(SemaRef.Context.IntTy); else { // If the underlying type is atomic, we need to adjust the type before - // continuing. See C23 6.7.3.3p5 and Sema::ActOnTag(). + // continuing. See C23 6.7.3.3p5 and Sema::ActOnTag(). FIXME: same as + // within ActOnTag(), it would be nice to have an easy way to get a + // derived TypeSourceInfo which strips qualifiers including the weird + // ones like _Atomic where it forms a different type. if (NewTI->getType()->isAtomicType()) Enum->setIntegerType(NewTI->getType().getAtomicUnqualifiedType()); else >From 358175baaecc69fcd210e915fe16c5b9f101aeee Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Thu, 10 Jul 2025 12:00:06 -0400 Subject: [PATCH 6/8] Warn on cv-qualifiers, default to error for _Atomic --- clang/docs/ReleaseNotes.rst | 8 ++++++-- clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 +++++- clang/lib/Sema/SemaDecl.cpp | 11 +++++++++++ clang/test/C/C23/n3030.c | 14 +++++++++++++- clang/test/C/C23/n3030_1.c | 2 +- clang/test/CodeGen/enum3.c | 2 +- clang/test/SemaCXX/enum-scoped.cpp | 2 +- 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 50853ea894a0c..a90306f2ba6c9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -313,8 +313,12 @@ C23 Feature Support - Fixed a rejects-valid bug where Clang would reject an enumeration with an ``_Atomic`` underlying type. The underlying type is the non-atomic, unqualified version of the specified type. Due to the perhaps surprising lack - of atomic behavior, this is diagnosed under ``-Watomic-qualifier-ignored``. - (#GH147736) + of atomic behavior, this is diagnosed under + ``-Wunderlying-atomic-qualifier-ignored``, which defaults to an error. This + can be downgraded with ``-Wno-underlying-atomic-qualifier-ignored`` or + ``-Wno-error=underlying-atomic-qualifier-ignored``. Clang now also diagnoses + cv-qualifiers as being ignored, but that warning does not default to an error. + It can be controlled by ``-Wunderlying-cv-qualifier-ignore``. (#GH147736) C11 Feature Support ^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d9fca37f74b03..e0378f9a1d928 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9364,10 +9364,14 @@ def warn_atomic_implicit_seq_cst : Warning< InGroup<DiagGroup<"atomic-implicit-seq-cst">>, DefaultIgnore; def err_atomic_unsupported : Error< "atomic types are not supported in '%0'">; +def warn_cv_stripped_in_enum : Warning< + "%select{'const' and 'volatile' qualifiers|'const' qualifier|'volatile' " + "qualifier}0 in enumeration underlying type ignored">, + InGroup<DiagGroup<"underlying-cv-qualifier-ignored">>; def warn_atomic_stripped_in_enum : Warning< "'_Atomic' qualifier ignored; operations involving the enumeration type will " "be non-atomic">, - InGroup<DiagGroup<"atomic-qualifier-ignored">>; + InGroup<DiagGroup<"underlying-atomic-qualifier-ignored">>, DefaultError; def err_overflow_builtin_must_be_int : Error< "operand argument to %select{overflow builtin|checked integer operation}0 " diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index bb1840d2b2695..b153ddb97a68d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17164,6 +17164,17 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { // involving the enumeration type will be non-atomic. if (T->isAtomicType()) Diag(UnderlyingLoc, diag::warn_atomic_stripped_in_enum); + Qualifiers Q = T.getQualifiers(); + int QualSelect = -1; + if (Q.hasConst() && Q.hasVolatile()) { + QualSelect = 0; + } else if (Q.hasConst()) { + QualSelect = 1; + } else if (Q.hasVolatile()) { + QualSelect = 2; + } + if (QualSelect != -1) + Diag(UnderlyingLoc, diag::warn_cv_stripped_in_enum) << QualSelect; T = T.getAtomicUnqualifiedType(); diff --git a/clang/test/C/C23/n3030.c b/clang/test/C/C23/n3030.c index 6ac7d64a9ca4d..94ea7037edd11 100644 --- a/clang/test/C/C23/n3030.c +++ b/clang/test/C/C23/n3030.c @@ -92,6 +92,18 @@ enum g : short { yyy } h = yyy; enum ee2 : typeof ((enum ee3 : short { A })0, (short)0); -enum not_actually_atomic : _Atomic(short) { // expected-warning {{'_Atomic' qualifier ignored; operations involving the enumeration type will be non-atomic}} +enum not_actually_atomic : _Atomic(short) { // expected-error {{'_Atomic' qualifier ignored; operations involving the enumeration type will be non-atomic}} Surprise }; + +enum not_actually_const : const int { // expected-warning {{'const' qualifier in enumeration underlying type ignored}} + SurpriseAgain +}; + +enum not_actually_volatile : volatile int { // expected-warning {{'volatile' qualifier in enumeration underlying type ignored}} + SurpriseOnceMore +}; + +enum not_acually_const_or_volatile : const volatile int { // expected-warning {{'const' and 'volatile' qualifiers in enumeration underlying type ignored}} + WhyTheSurprise +}; diff --git a/clang/test/C/C23/n3030_1.c b/clang/test/C/C23/n3030_1.c index 4acfc007709ac..1afc9855767f0 100644 --- a/clang/test/C/C23/n3030_1.c +++ b/clang/test/C/C23/n3030_1.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c23 -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -std=c23 -Wno-underlying-atomic-qualifier-ignored -ast-dump %s | FileCheck %s // The underlying type is the unqualified, non-atomic version of the type // specified. diff --git a/clang/test/CodeGen/enum3.c b/clang/test/CodeGen/enum3.c index b06d0b7ca22ac..6878a0bbb94d0 100644 --- a/clang/test/CodeGen/enum3.c +++ b/clang/test/CodeGen/enum3.c @@ -1,5 +1,5 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c23 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-error=underlying-atomic-qualifier-ignored -std=c23 %s -emit-llvm -o - | FileCheck %s // Ensure that an "atomic" underlying type has no actual atomic semantics // because the qualifier is stripped. diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp index dbb4e6ae3948e..0ce47274979d9 100644 --- a/clang/test/SemaCXX/enum-scoped.cpp +++ b/clang/test/SemaCXX/enum-scoped.cpp @@ -353,7 +353,7 @@ B b{a}; // expected-error {{cannot initialize}} namespace GH147736 { template <typename Ty> struct S { - enum OhBoy : Ty { // expected-warning 2 {{'_Atomic' qualifier ignored; operations involving the enumeration type will be non-atomic}} + enum OhBoy : Ty { // expected-error 2 {{'_Atomic' qualifier ignored; operations involving the enumeration type will be non-atomic}} Unimportant } e; }; >From 1331d9bb3d4faa953f11c7fc319518850aae846a Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Thu, 10 Jul 2025 12:37:55 -0400 Subject: [PATCH 7/8] Fix failing test --- clang/test/CXX/dcl.dcl/dcl.enum/p2.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/test/CXX/dcl.dcl/dcl.enum/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.enum/p2.cpp index de826d0570422..7b69358687a2f 100644 --- a/clang/test/CXX/dcl.dcl/dcl.enum/p2.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.enum/p2.cpp @@ -1,6 +1,5 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -// expected-no-diagnostics -enum class E : int const volatile { }; +enum class E : int const volatile { }; // expected-warning {{'const' and 'volatile' qualifiers in enumeration underlying type ignored}} using T = __underlying_type(E); using T = int; >From 45b75ffb1b86d4e5fd84977c325dd121b1fce381 Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Thu, 10 Jul 2025 12:45:50 -0400 Subject: [PATCH 8/8] Use enum_select; NFC --- .../clang/Basic/DiagnosticSemaKinds.td | 6 ++++-- clang/lib/Sema/SemaDecl.cpp | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e0378f9a1d928..ef59cf25541b2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9365,8 +9365,10 @@ def warn_atomic_implicit_seq_cst : Warning< def err_atomic_unsupported : Error< "atomic types are not supported in '%0'">; def warn_cv_stripped_in_enum : Warning< - "%select{'const' and 'volatile' qualifiers|'const' qualifier|'volatile' " - "qualifier}0 in enumeration underlying type ignored">, + "%enum_select<CVQualList>{" + "%Both{'const' and 'volatile' qualifiers}|" + "%Const{'const' qualifier}|" + "%Volatile{'volatile' qualifier}}0 in enumeration underlying type ignored">, InGroup<DiagGroup<"underlying-cv-qualifier-ignored">>; def warn_atomic_stripped_in_enum : Warning< "'_Atomic' qualifier ignored; operations involving the enumeration type will " diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b153ddb97a68d..92f9bac723d18 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17164,17 +17164,18 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { // involving the enumeration type will be non-atomic. if (T->isAtomicType()) Diag(UnderlyingLoc, diag::warn_atomic_stripped_in_enum); + Qualifiers Q = T.getQualifiers(); - int QualSelect = -1; - if (Q.hasConst() && Q.hasVolatile()) { - QualSelect = 0; - } else if (Q.hasConst()) { - QualSelect = 1; - } else if (Q.hasVolatile()) { - QualSelect = 2; - } - if (QualSelect != -1) - Diag(UnderlyingLoc, diag::warn_cv_stripped_in_enum) << QualSelect; + std::optional<diag::CVQualList> QualSelect; + if (Q.hasConst() && Q.hasVolatile()) + QualSelect = diag::CVQualList::Both; + else if (Q.hasConst()) + QualSelect = diag::CVQualList::Const; + else if (Q.hasVolatile()) + QualSelect = diag::CVQualList::Volatile; + + if (QualSelect) + Diag(UnderlyingLoc, diag::warn_cv_stripped_in_enum) << *QualSelect; T = T.getAtomicUnqualifiedType(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits