[clang] [C23] Accept an _Atomic underlying type (PR #147802)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 10 09:59:19 PDT 2025
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 <aaron at aaronballman.com>
Date: Wed, 9 Jul 2025 14:40:00 -0400
Subject: [PATCH 1/9] [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 <aaron at aaronballman.com>
Date: Wed, 9 Jul 2025 15:02:46 -0400
Subject: [PATCH 2/9] 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 <aaron at aaronballman.com>
Date: Wed, 9 Jul 2025 15:15:55 -0400
Subject: [PATCH 3/9] 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 <aaron at aaronballman.com>
Date: Thu, 10 Jul 2025 08:09:12 -0400
Subject: [PATCH 4/9] 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 at -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 at -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 <aaron at aaronballman.com>
Date: Thu, 10 Jul 2025 09:45:06 -0400
Subject: [PATCH 5/9] 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 <aaron at aaronballman.com>
Date: Thu, 10 Jul 2025 12:00:06 -0400
Subject: [PATCH 6/9] 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 <aaron at aaronballman.com>
Date: Thu, 10 Jul 2025 12:37:55 -0400
Subject: [PATCH 7/9] 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 <aaron at aaronballman.com>
Date: Thu, 10 Jul 2025 12:45:50 -0400
Subject: [PATCH 8/9] 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();
>From 168d8284fe6e0ae5fba8ed1bd0b841763bcbe02e Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Thu, 10 Jul 2025 12:58:38 -0400
Subject: [PATCH 9/9] Fix build
That'll teach me to commit before the build completes!
---
clang/lib/Sema/SemaDecl.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 92f9bac723d18..d7234e269f645 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -17166,7 +17166,7 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
Diag(UnderlyingLoc, diag::warn_atomic_stripped_in_enum);
Qualifiers Q = T.getQualifiers();
- std::optional<diag::CVQualList> QualSelect;
+ std::optional<unsigned> QualSelect;
if (Q.hasConst() && Q.hasVolatile())
QualSelect = diag::CVQualList::Both;
else if (Q.hasConst())
More information about the cfe-commits
mailing list