leoetlino created this revision. leoetlino requested review of this revision. Herald added a project: clang.
C++17 changed the definition of literal types so that unions that have at least one non-static data member of non-volatile literal type are also considered literal types. This patch implements that new rule and also adds a test for closure types (10.5.2) and for unions (10.5.3) to the existing test file for literal types. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D113694 Files: clang/include/clang/AST/CXXRecordDeclDefinitionBits.def clang/include/clang/AST/DeclCXX.h clang/lib/AST/DeclCXX.cpp clang/test/CXX/basic/basic.types/p10.cpp
Index: clang/test/CXX/basic/basic.types/p10.cpp =================================================================== --- clang/test/CXX/basic/basic.types/p10.cpp +++ clang/test/CXX/basic/basic.types/p10.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y %s -DCXX1Y +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -DCXX11 -DCXX11_OR_LATER +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y %s -DCXX1Y -DCXX11_OR_LATER -DCXX1Y_OR_LATER +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s -DCXX17 -DCXX11_OR_LATER -DCXX1Y_OR_LATER -DCXX17_OR_LATER struct NonLiteral { NonLiteral(); }; @@ -7,7 +8,7 @@ // [C++1y] - void constexpr void f() {} -#ifndef CXX1Y +#ifdef CXX11 // expected-error@-2 {{'void' is not a literal type}} #endif @@ -20,7 +21,7 @@ struct BeingDefined; extern BeingDefined beingdefined; -struct BeingDefined { +struct BeingDefined { static constexpr BeingDefined& t = beingdefined; }; @@ -64,8 +65,14 @@ }; constexpr int f(TrivDefaultedDtor) { return 0; } -// - it is an aggregate type or has at least one constexpr constructor or +// - it is [a closure type [C++17]], an aggregate type or has at least one constexpr constructor or // constexpr constructor template that is not a copy or move constructor +#ifndef CXX17_OR_LATER +// expected-error@+4 {{not a literal type}} +// expected-note@+2 {{lambda closure types are non-literal types before C++17}} +#endif +auto closure = [] {}; +constexpr int f(decltype(closure)) { return 0; } struct Agg { int a; char *b; @@ -101,7 +108,8 @@ template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {} constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // expected-error {{constant expression}} expected-note {{cannot construct object of type 'DerivedFromVBase<HasVBase>' with virtual base class in a constant expression}} -// - it has all non-static data members and base classes of literal types +// - [C++17] if it is a union, at least one of its non-static data members is of non-volatile literal type, and +// - [if it is not a union [C++17]] it has all non-static data members and base classes of literal types struct NonLitMember { S s; // expected-note {{has data member 's' of non-literal type 'S'}} }; @@ -122,6 +130,19 @@ constexpr int f(MemberType<int>) { return 0; } constexpr int f(MemberType<NonLiteral>) { return 0; } // expected-error {{not a literal type}} +template<typename T> +union UnionType { + char c; + T t; + constexpr UnionType() : c{} {} +}; +constexpr int f(UnionType<int>) { return 0; } +#ifndef CXX17_OR_LATER +// expected-error@+3 {{not a literal type}} +// expected-note@-6 {{'UnionType<NonLiteral>' is not literal because it has data member 't' of non-literal type 'NonLiteral'}} +#endif +constexpr int f(UnionType<NonLiteral>) { return 0; } + // - an array of literal type [C++1y] other than an array of runtime bound struct ArrGood { Agg agg[24]; Index: clang/lib/AST/DeclCXX.cpp =================================================================== --- clang/lib/AST/DeclCXX.cpp +++ clang/lib/AST/DeclCXX.cpp @@ -102,7 +102,8 @@ DefaultedDefaultConstructorIsConstexpr(true), HasConstexprDefaultConstructor(false), DefaultedDestructorIsConstexpr(true), - HasNonLiteralTypeFieldsOrBases(false), StructuralIfLiteral(true), + HasNonLiteralTypeFieldsOrBases(false), + HasNonVolatileLiteralTypeFields(false), StructuralIfLiteral(true), UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0), ImplicitCopyConstructorCanHaveConstParamForVBase(true), ImplicitCopyConstructorCanHaveConstParamForNonVBase(true), @@ -1103,8 +1104,12 @@ } } + const bool IsNonVolatileLiteralTypeField = + T->isLiteralType(Context) && !T.isVolatileQualified(); // Record if this field is the first non-literal or volatile field or base. - if (!T->isLiteralType(Context) || T.isVolatileQualified()) + if (IsNonVolatileLiteralTypeField) + data().HasNonVolatileLiteralTypeFields = true; + else data().HasNonLiteralTypeFieldsOrBases = true; if (Field->hasInClassInitializer() || Index: clang/include/clang/AST/DeclCXX.h =================================================================== --- clang/include/clang/AST/DeclCXX.h +++ clang/include/clang/AST/DeclCXX.h @@ -1354,6 +1354,12 @@ return data().HasNonLiteralTypeFieldsOrBases; } + /// Determine whether this class has a non-volatile literal type + /// non-static data member. + bool hasNonVolatileLiteralTypeFields() const { + return data().HasNonVolatileLiteralTypeFields; + } + /// Determine whether this class has a using-declaration that names /// a user-declared base class constructor. bool hasInheritedConstructor() const { @@ -1396,12 +1402,20 @@ /// treating types with trivial default constructors as literal types. /// /// Only in C++17 and beyond, are lambdas literal types. + /// A union is a literal type if at least one of its non-static data members + /// is of non-volatile literal type. bool isLiteral() const { const LangOptions &LangOpts = getLangOpts(); + + bool FieldsOk = !hasNonLiteralTypeFieldsOrBases(); + if (LangOpts.CPlusPlus17 && isUnion()) { + FieldsOk = field_empty() || hasNonVolatileLiteralTypeFields(); + } + return (LangOpts.CPlusPlus20 ? hasConstexprDestructor() : hasTrivialDestructor()) && (!isLambda() || LangOpts.CPlusPlus17) && - !hasNonLiteralTypeFieldsOrBases() && + FieldsOk && (isAggregate() || isLambda() || hasConstexprNonCopyMoveConstructor() || hasTrivialDefaultConstructor()); Index: clang/include/clang/AST/CXXRecordDeclDefinitionBits.def =================================================================== --- clang/include/clang/AST/CXXRecordDeclDefinitionBits.def +++ clang/include/clang/AST/CXXRecordDeclDefinitionBits.def @@ -214,6 +214,10 @@ /// member or base class of non-literal or volatile type. FIELD(HasNonLiteralTypeFieldsOrBases, 1, NO_MERGE) +/// True when this class contains at least one non-static data +/// member of non-volatile literal type. +FIELD(HasNonVolatileLiteralTypeFields, 1, NO_MERGE) + /// True if this class is a structural type, assuming it is a literal type. FIELD(StructuralIfLiteral, 1, NO_MERGE)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits