mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 13:50:11 +00:00
[Clang] Implement CWG2598: Union of non-literal types (#78195)
A union is considered a literal type unless it has no non-literal member. This resolves CWG2096 (which makes unions with literal members literal) and CWG2598 (empty unions are literal types). Fixes #77924
This commit is contained in:
parent
933c25e558
commit
4e64159c86
@ -227,6 +227,11 @@ C++2c Feature Support
|
||||
Resolutions to C++ Defect Reports
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Implemented `CWG2598 <https://wg21.link/CWG2598>`_ and `CWG2096 <https://wg21.link/CWG2096>`_,
|
||||
making unions (that have either no members or at least one literal member) literal types.
|
||||
(`#77924: <https://github.com/llvm/llvm-project/issues/77924>`_).
|
||||
|
||||
|
||||
C Language Changes
|
||||
------------------
|
||||
- ``structs``, ``unions``, and ``arrays`` that are const may now be used as
|
||||
|
@ -1439,31 +1439,20 @@ public:
|
||||
|
||||
/// Determine whether this class is a literal type.
|
||||
///
|
||||
/// C++11 [basic.types]p10:
|
||||
/// C++20 [basic.types]p10:
|
||||
/// A class type that has all the following properties:
|
||||
/// - it has a trivial destructor
|
||||
/// - every constructor call and full-expression in the
|
||||
/// brace-or-equal-intializers for non-static data members (if any) is
|
||||
/// a constant expression.
|
||||
/// - it is an aggregate type or has at least one constexpr constructor
|
||||
/// or constructor template that is not a copy or move constructor, and
|
||||
/// - all of its non-static data members and base classes are of literal
|
||||
/// types
|
||||
///
|
||||
/// We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by
|
||||
/// treating types with trivial default constructors as literal types.
|
||||
///
|
||||
/// Only in C++17 and beyond, are lambdas literal types.
|
||||
bool isLiteral() const {
|
||||
const LangOptions &LangOpts = getLangOpts();
|
||||
return (LangOpts.CPlusPlus20 ? hasConstexprDestructor()
|
||||
: hasTrivialDestructor()) &&
|
||||
(!isLambda() || LangOpts.CPlusPlus17) &&
|
||||
!hasNonLiteralTypeFieldsOrBases() &&
|
||||
(isAggregate() || isLambda() ||
|
||||
hasConstexprNonCopyMoveConstructor() ||
|
||||
hasTrivialDefaultConstructor());
|
||||
}
|
||||
/// - it has a constexpr destructor
|
||||
/// - all of its non-static non-variant data members and base classes
|
||||
/// are of non-volatile literal types, and it:
|
||||
/// - is a closure type
|
||||
/// - is an aggregate union type that has either no variant members
|
||||
/// or at least one variant member of non-volatile literal type
|
||||
/// - is a non-union aggregate type for which each of its anonymous
|
||||
/// union members satisfies the above requirements for an aggregate
|
||||
/// union type, or
|
||||
/// - has at least one constexpr constructor or constructor template
|
||||
/// that is not a copy or move constructor.
|
||||
bool isLiteral() const;
|
||||
|
||||
/// Determine whether this is a structural type.
|
||||
bool isStructural() const {
|
||||
|
@ -1383,6 +1383,31 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||
}
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::isLiteral() const {
|
||||
const LangOptions &LangOpts = getLangOpts();
|
||||
if (!(LangOpts.CPlusPlus20 ? hasConstexprDestructor()
|
||||
: hasTrivialDestructor()))
|
||||
return false;
|
||||
|
||||
if (hasNonLiteralTypeFieldsOrBases()) {
|
||||
// CWG2598
|
||||
// is an aggregate union type that has either no variant
|
||||
// members or at least one variant member of non-volatile literal type,
|
||||
if (!isUnion())
|
||||
return false;
|
||||
bool HasAtLeastOneLiteralMember =
|
||||
fields().empty() || any_of(fields(), [this](const FieldDecl *D) {
|
||||
return !D->getType().isVolatileQualified() &&
|
||||
D->getType()->isLiteralType(getASTContext());
|
||||
});
|
||||
if (!HasAtLeastOneLiteralMember)
|
||||
return false;
|
||||
}
|
||||
|
||||
return isAggregate() || (isLambda() && LangOpts.CPlusPlus17) ||
|
||||
hasConstexprNonCopyMoveConstructor() || hasTrivialDefaultConstructor();
|
||||
}
|
||||
|
||||
void CXXRecordDecl::addedSelectedDestructor(CXXDestructorDecl *DD) {
|
||||
DD->setIneligibleOrNotSelected(false);
|
||||
addedEligibleSpecialMemberFunction(DD, SMF_Destructor);
|
||||
|
@ -418,3 +418,5 @@ namespace dr2094 { // dr2094: 5
|
||||
static_assert(__is_trivially_assignable(A, const A&), "");
|
||||
static_assert(__is_trivially_assignable(B, const B&), "");
|
||||
}
|
||||
|
||||
// dr2096: dup 2598
|
||||
|
@ -208,3 +208,67 @@ namespace dr2565 { // dr2565: 16 open
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
namespace dr2598 { // dr2598: 18
|
||||
#if __cplusplus >= 201103L
|
||||
struct NonLiteral {
|
||||
NonLiteral();
|
||||
};
|
||||
|
||||
struct anonymous1 {
|
||||
union {} a;
|
||||
};
|
||||
static_assert(__is_literal(anonymous1), "");
|
||||
|
||||
struct anonymous2 {
|
||||
union { char c; };
|
||||
};
|
||||
static_assert(__is_literal(anonymous2), "");
|
||||
|
||||
struct anonymous3 {
|
||||
union { char c; NonLiteral NL; };
|
||||
};
|
||||
static_assert(__is_literal(anonymous3), "");
|
||||
|
||||
struct anonymous4 {
|
||||
union { NonLiteral NL; };
|
||||
};
|
||||
static_assert(!__is_literal(anonymous4), "");
|
||||
|
||||
union empty {};
|
||||
static_assert(__is_literal(empty), "");
|
||||
|
||||
union union1 { char c; };
|
||||
static_assert(__is_literal(union1), "");
|
||||
|
||||
union union2 { char c; NonLiteral NL;};
|
||||
static_assert(__is_literal(union2), "");
|
||||
|
||||
union union3 { NonLiteral NL;};
|
||||
static_assert(!__is_literal(union3), "");
|
||||
|
||||
union union4 { union4(); };
|
||||
static_assert(!__is_literal(union4), "");
|
||||
|
||||
union union5 { static NonLiteral NL; };
|
||||
static_assert(__is_literal(union5), "");
|
||||
|
||||
struct Literal { constexpr Literal() {} };
|
||||
union union6 { NonLiteral NL; Literal L; };
|
||||
static_assert(__is_literal(union6), "");
|
||||
|
||||
#if __cplusplus >= 202003L
|
||||
struct A { A(); };
|
||||
union U {
|
||||
A a;
|
||||
constexpr U() {}
|
||||
constexpr ~U() {}
|
||||
};
|
||||
static_assert(!__is_literal(U), "");
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
|
||||
|
||||
|
||||
static_assert(__is_literal(int), "fail");
|
||||
static_assert(__is_literal_type(int), "fail"); // alternate spelling for GCC
|
||||
@ -75,3 +77,34 @@ template <typename T> class HasConstExprCtorT {
|
||||
static_assert(__is_literal(HasConstExprCtor), "fail");
|
||||
static_assert(__is_literal(HasConstExprCtorTemplate<int>), "fail");
|
||||
static_assert(__is_literal(HasConstExprCtorT<NonLiteral>), "fail");
|
||||
|
||||
|
||||
#if __cplusplus >= 202003L
|
||||
namespace GH77924 {
|
||||
|
||||
struct A { A(); };
|
||||
template <class T>
|
||||
struct opt {
|
||||
union Data {
|
||||
constexpr Data() : x{} {}
|
||||
constexpr ~Data() {}
|
||||
char x;
|
||||
T data;
|
||||
};
|
||||
|
||||
constexpr opt() : data{} {}
|
||||
constexpr ~opt() { if (engaged) data.data.~T(); }
|
||||
Data data;
|
||||
bool engaged = false;
|
||||
};
|
||||
|
||||
consteval void foo() {
|
||||
opt<A> a;
|
||||
}
|
||||
|
||||
void test() {
|
||||
foo();
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@ -12384,7 +12384,7 @@ and <I>POD class</I></td>
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2096.html">2096</a></td>
|
||||
<td>CD4</td>
|
||||
<td>Constraints on literal unions</td>
|
||||
<td class="unknown" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Duplicate of <a href="#2598">2598</a></td>
|
||||
</tr>
|
||||
<tr class="open" id="2097">
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2097.html">2097</a></td>
|
||||
@ -15396,7 +15396,7 @@ and <I>POD class</I></td>
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2598.html">2598</a></td>
|
||||
<td>C++23</td>
|
||||
<td>Unions should not require a non-static data member of literal type</td>
|
||||
<td class="unknown" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Clang 18</td>
|
||||
</tr>
|
||||
<tr id="2599">
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2599.html">2599</a></td>
|
||||
|
Loading…
Reference in New Issue
Block a user