Skip to content

[C23] Accept an _Atomic underlying type #147802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're now stripping qualifications, we should probably make sure that all of the callers of this 'treat' that like underlying.


if (T->isDependentType())
return false;

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions clang/test/C/C23/n3030_1.c
Original file line number Diff line number Diff line change
@@ -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'
13 changes: 13 additions & 0 deletions clang/test/SemaCXX/enum-scoped.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
}
Loading