Author: cor3ntin Date: 2024-01-17T06:16:12+01:00 New Revision: 4e64159c866446ed7f5783649f8f5699f84bb1a6
URL: https://github.com/llvm/llvm-project/commit/4e64159c866446ed7f5783649f8f5699f84bb1a6 DIFF: https://github.com/llvm/llvm-project/commit/4e64159c866446ed7f5783649f8f5699f84bb1a6.diff LOG: [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 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/AST/DeclCXX.h clang/lib/AST/DeclCXX.cpp clang/test/CXX/drs/dr20xx.cpp clang/test/CXX/drs/dr25xx.cpp clang/test/SemaCXX/literal-type.cpp clang/www/cxx_dr_status.html Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1eba8ab5590c52..e45e016b3d66bd 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 648f5f94640870..75b73700c44d67 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1439,31 +1439,20 @@ class CXXRecordDecl : public RecordDecl { /// 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 { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 98b0a6dc28ea2f..c11f6458c07dde 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -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); diff --git a/clang/test/CXX/drs/dr20xx.cpp b/clang/test/CXX/drs/dr20xx.cpp index 60ee7684440f54..f7f37379e61ad1 100644 --- a/clang/test/CXX/drs/dr20xx.cpp +++ b/clang/test/CXX/drs/dr20xx.cpp @@ -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 diff --git a/clang/test/CXX/drs/dr25xx.cpp b/clang/test/CXX/drs/dr25xx.cpp index 32bbfc63d0df4f..502f03271d9afe 100644 --- a/clang/test/CXX/drs/dr25xx.cpp +++ b/clang/test/CXX/drs/dr25xx.cpp @@ -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 +} diff --git a/clang/test/SemaCXX/literal-type.cpp b/clang/test/SemaCXX/literal-type.cpp index 14a4094c45a1b8..88535c169fe01c 100644 --- a/clang/test/SemaCXX/literal-type.cpp +++ b/clang/test/SemaCXX/literal-type.cpp @@ -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 diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 397bf1357d3cb3..5e7c1a0fa2f246 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -12384,7 +12384,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <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 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits