diff options
| author | Diana Picus <diana.picus@linaro.org> | 2017-08-09 12:22:25 +0000 |
|---|---|---|
| committer | Diana Picus <diana.picus@linaro.org> | 2017-08-09 12:22:25 +0000 |
| commit | 0c9f193acc8b9a45888f08ba44f04f918cabc75f (patch) | |
| tree | 78416e96155db3a077ca178980fe59500cf442b2 /clang/lib | |
| parent | 6228aeda651dc1b8afe61254b3f966ea25d78559 (diff) | |
| download | bcm5719-llvm-0c9f193acc8b9a45888f08ba44f04f918cabc75f.tar.gz bcm5719-llvm-0c9f193acc8b9a45888f08ba44f04f918cabc75f.zip | |
Revert "PR19668, PR23034: Fix handling of move constructors and deleted copy constructors when deciding whether classes should be passed indirectly."
This reverts commit r310401 because it seems to have broken some ARM
bot(s).
llvm-svn: 310464
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 34 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGCXXABI.cpp | 31 | ||||
| -rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 52 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 56 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 3 |
8 files changed, 73 insertions, 127 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 2c0bb11cc4b..6e33b98d2f1 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -956,16 +956,12 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.HasUninitializedFields = FromData.HasUninitializedFields; ToData.HasInheritedConstructor = FromData.HasInheritedConstructor; ToData.HasInheritedAssignment = FromData.HasInheritedAssignment; - ToData.NeedOverloadResolutionForCopyConstructor - = FromData.NeedOverloadResolutionForCopyConstructor; ToData.NeedOverloadResolutionForMoveConstructor = FromData.NeedOverloadResolutionForMoveConstructor; ToData.NeedOverloadResolutionForMoveAssignment = FromData.NeedOverloadResolutionForMoveAssignment; ToData.NeedOverloadResolutionForDestructor = FromData.NeedOverloadResolutionForDestructor; - ToData.DefaultedCopyConstructorIsDeleted - = FromData.DefaultedCopyConstructorIsDeleted; ToData.DefaultedMoveConstructorIsDeleted = FromData.DefaultedMoveConstructorIsDeleted; ToData.DefaultedMoveAssignmentIsDeleted @@ -977,7 +973,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, = FromData.HasConstexprNonCopyMoveConstructor; ToData.HasDefaultedDefaultConstructor = FromData.HasDefaultedDefaultConstructor; - ToData.CanPassInRegisters = FromData.CanPassInRegisters; ToData.DefaultedDefaultConstructorIsConstexpr = FromData.DefaultedDefaultConstructorIsConstexpr; ToData.HasConstexprDefaultConstructor diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index fe10d1cdd94..5cab4888225 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -55,18 +55,15 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasOnlyCMembers(true), HasInClassInitializer(false), HasUninitializedReferenceMember(false), HasUninitializedFields(false), HasInheritedConstructor(false), HasInheritedAssignment(false), - NeedOverloadResolutionForCopyConstructor(false), NeedOverloadResolutionForMoveConstructor(false), NeedOverloadResolutionForMoveAssignment(false), NeedOverloadResolutionForDestructor(false), - DefaultedCopyConstructorIsDeleted(false), DefaultedMoveConstructorIsDeleted(false), DefaultedMoveAssignmentIsDeleted(false), DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All), DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true), HasConstexprNonCopyMoveConstructor(false), HasDefaultedDefaultConstructor(false), - CanPassInRegisters(false), DefaultedDefaultConstructorIsConstexpr(true), HasConstexprDefaultConstructor(false), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), @@ -355,10 +352,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, setHasVolatileMember(true); // Keep track of the presence of mutable fields. - if (BaseClassDecl->hasMutableFields()) { + if (BaseClassDecl->hasMutableFields()) data().HasMutableFields = true; - data().NeedOverloadResolutionForCopyConstructor = true; - } if (BaseClassDecl->hasUninitializedReferenceMember()) data().HasUninitializedReferenceMember = true; @@ -411,8 +406,6 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { // -- a direct or virtual base class B that cannot be copied/moved [...] // -- a non-static data member of class type M (or array thereof) // that cannot be copied or moved [...] - if (!Subobj->hasSimpleCopyConstructor()) - data().NeedOverloadResolutionForCopyConstructor = true; if (!Subobj->hasSimpleMoveConstructor()) data().NeedOverloadResolutionForMoveConstructor = true; @@ -433,7 +426,6 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { // -- any non-static data member has a type with a destructor // that is deleted or inaccessible from the defaulted [ctor or dtor]. if (!Subobj->hasSimpleDestructor()) { - data().NeedOverloadResolutionForCopyConstructor = true; data().NeedOverloadResolutionForMoveConstructor = true; data().NeedOverloadResolutionForDestructor = true; } @@ -719,10 +711,8 @@ void CXXRecordDecl::addedMember(Decl *D) { data().IsStandardLayout = false; // Keep track of the presence of mutable fields. - if (Field->isMutable()) { + if (Field->isMutable()) data().HasMutableFields = true; - data().NeedOverloadResolutionForCopyConstructor = true; - } // C++11 [class.union]p8, DR1460: // If X is a union, a non-static data member of X that is not an anonymous @@ -766,12 +756,6 @@ void CXXRecordDecl::addedMember(Decl *D) { // A standard-layout class is a class that: // -- has no non-static data members of type [...] reference, data().IsStandardLayout = false; - - // C++1z [class.copy.ctor]p10: - // A defaulted copy constructor for a class X is defined as deleted if X has: - // -- a non-static data member of rvalue reference type - if (T->isRValueReferenceType()) - data().DefaultedCopyConstructorIsDeleted = true; } if (!Field->hasInClassInitializer() && !Field->isMutable()) { @@ -825,10 +809,6 @@ void CXXRecordDecl::addedMember(Decl *D) { // We may need to perform overload resolution to determine whether a // field can be moved if it's const or volatile qualified. if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) { - // We need to care about 'const' for the copy constructor because an - // implicit copy constructor might be declared with a non-const - // parameter. - data().NeedOverloadResolutionForCopyConstructor = true; data().NeedOverloadResolutionForMoveConstructor = true; data().NeedOverloadResolutionForMoveAssignment = true; } @@ -839,8 +819,6 @@ void CXXRecordDecl::addedMember(Decl *D) { // -- X is a union-like class that has a variant member with a // non-trivial [corresponding special member] if (isUnion()) { - if (FieldRec->hasNonTrivialCopyConstructor()) - data().DefaultedCopyConstructorIsDeleted = true; if (FieldRec->hasNonTrivialMoveConstructor()) data().DefaultedMoveConstructorIsDeleted = true; if (FieldRec->hasNonTrivialMoveAssignment()) @@ -852,8 +830,6 @@ void CXXRecordDecl::addedMember(Decl *D) { // For an anonymous union member, our overload resolution will perform // overload resolution for its members. if (Field->isAnonymousStructOrUnion()) { - data().NeedOverloadResolutionForCopyConstructor |= - FieldRec->data().NeedOverloadResolutionForCopyConstructor; data().NeedOverloadResolutionForMoveConstructor |= FieldRec->data().NeedOverloadResolutionForMoveConstructor; data().NeedOverloadResolutionForMoveAssignment |= @@ -939,10 +915,8 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Keep track of the presence of mutable fields. - if (FieldRec->hasMutableFields()) { + if (FieldRec->hasMutableFields()) data().HasMutableFields = true; - data().NeedOverloadResolutionForCopyConstructor = true; - } // C++11 [class.copy]p13: // If the implicitly-defined constructor would satisfy the @@ -1476,7 +1450,7 @@ void CXXRecordDecl::completeDefinition() { void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { RecordDecl::completeDefinition(); - + // If the class may be abstract (but hasn't been marked as such), check for // any pure final overriders. if (mayBeAbstract()) { diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index 033258643dd..e29e525edd2 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -30,9 +30,38 @@ void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) { } bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const { + // If RD has a non-trivial move or copy constructor, we cannot copy the + // argument. + if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor()) + return false; + + // If RD has a non-trivial destructor, we cannot copy the argument. + if (RD->hasNonTrivialDestructor()) + return false; + // We can only copy the argument if there exists at least one trivial, // non-deleted copy or move constructor. - return RD->canPassInRegisters(); + // FIXME: This assumes that all lazily declared copy and move constructors are + // not deleted. This assumption might not be true in some corner cases. + bool CopyDeleted = false; + bool MoveDeleted = false; + for (const CXXConstructorDecl *CD : RD->ctors()) { + if (CD->isCopyConstructor() || CD->isMoveConstructor()) { + assert(CD->isTrivial()); + // We had at least one undeleted trivial copy or move ctor. Return + // directly. + if (!CD->isDeleted()) + return true; + if (CD->isCopyConstructor()) + CopyDeleted = true; + else + MoveDeleted = true; + } + } + + // If all trivial copy and move constructors are deleted, we cannot copy the + // argument. + return !(CopyDeleted && MoveDeleted); } llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) { diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 5c33f8c1afa..c1f892a3173 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -63,8 +63,11 @@ public: bool classifyReturnType(CGFunctionInfo &FI) const override; RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override { - // If C++ prohibits us from making a copy, pass by address. - if (!canCopyArgument(RD)) + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always indirect. + // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared + // special members. + if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) return RAA_Indirect; return RAA_Default; } @@ -1011,8 +1014,10 @@ bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const { if (!RD) return false; - // If C++ prohibits us from making a copy, return by address. - if (!canCopyArgument(RD)) { + // Return indirectly if we have a non-trivial copy ctor or non-trivial dtor. + // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared + // special members. + if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) { auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType()); FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false); return true; diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 0a3cc306657..409bad72ee5 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -819,44 +819,46 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const { return RAA_Default; case llvm::Triple::x86_64: - // If a class has a destructor, we'd really like to pass it indirectly + // Win64 passes objects with non-trivial copy ctors indirectly. + if (RD->hasNonTrivialCopyConstructor()) + return RAA_Indirect; + + // If an object has a destructor, we'd really like to pass it indirectly // because it allows us to elide copies. Unfortunately, MSVC makes that // impossible for small types, which it will pass in a single register or // stack slot. Most objects with dtors are large-ish, so handle that early. // We can't call out all large objects as being indirect because there are // multiple x64 calling conventions and the C++ ABI code shouldn't dictate // how we pass large POD types. - // - // Note: This permits small classes with nontrivial destructors to be - // passed in registers, which is non-conforming. if (RD->hasNonTrivialDestructor() && getContext().getTypeSize(RD->getTypeForDecl()) > 64) return RAA_Indirect; - // If a class has at least one non-deleted, trivial copy constructor, it - // is passed according to the C ABI. Otherwise, it is passed indirectly. - // - // Note: This permits classes with non-trivial copy or move ctors to be - // passed in registers, so long as they *also* have a trivial copy ctor, - // which is non-conforming. - if (RD->needsImplicitCopyConstructor()) { - // If the copy ctor has not yet been declared, we can read its triviality - // off the AST. - if (!RD->defaultedCopyConstructorIsDeleted() && - RD->hasTrivialCopyConstructor()) - return RAA_Default; - } else { - // Otherwise, we need to find the copy constructor(s) and ask. - for (const CXXConstructorDecl *CD : RD->ctors()) { - if (CD->isCopyConstructor()) { - // We had at least one nondeleted trivial copy ctor. Return directly. - if (!CD->isDeleted() && CD->isTrivial()) - return RAA_Default; - } + // If this is true, the implicit copy constructor that Sema would have + // created would not be deleted. FIXME: We should provide a more direct way + // for CodeGen to ask whether the constructor was deleted. + if (!RD->hasUserDeclaredCopyConstructor() && + !RD->hasUserDeclaredMoveConstructor() && + !RD->needsOverloadResolutionForMoveConstructor() && + !RD->hasUserDeclaredMoveAssignment() && + !RD->needsOverloadResolutionForMoveAssignment()) + return RAA_Default; + + // Otherwise, Sema should have created an implicit copy constructor if + // needed. + assert(!RD->needsImplicitCopyConstructor()); + + // We have to make sure the trivial copy constructor isn't deleted. + for (const CXXConstructorDecl *CD : RD->ctors()) { + if (CD->isCopyConstructor()) { + assert(CD->isTrivial()); + // We had at least one undeleted trivial copy ctor. Return directly. + if (!CD->isDeleted()) + return RAA_Default; } } - // We have no trivial, non-deleted copy constructor. + // The trivial copy constructor was deleted. Return indirectly. return RAA_Indirect; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c05e5f02070..e9070881afe 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5726,53 +5726,6 @@ static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD, } } -/// Determine whether a type is permitted to be passed or returned in -/// registers, per C++ [class.temporary]p3. -static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { - if (D->isDependentType() || D->isInvalidDecl()) - return false; - - // Per C++ [class.temporary]p3, the relevant condition is: - // each copy constructor, move constructor, and destructor of X is - // either trivial or deleted, and X has at least one non-deleted copy - // or move constructor - bool HasNonDeletedCopyOrMove = false; - - if (D->needsImplicitCopyConstructor() && - !D->defaultedCopyConstructorIsDeleted()) { - if (!D->hasTrivialCopyConstructor()) - return false; - HasNonDeletedCopyOrMove = true; - } - - if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() && - !D->defaultedMoveConstructorIsDeleted()) { - if (!D->hasTrivialMoveConstructor()) - return false; - HasNonDeletedCopyOrMove = true; - } - - if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() && - !D->hasTrivialDestructor()) - return false; - - for (const CXXMethodDecl *MD : D->methods()) { - if (MD->isDeleted()) - continue; - - auto *CD = dyn_cast<CXXConstructorDecl>(MD); - if (CD && CD->isCopyOrMoveConstructor()) - HasNonDeletedCopyOrMove = true; - else if (!isa<CXXDestructorDecl>(MD)) - continue; - - if (!MD->isTrivial()) - return false; - } - - return HasNonDeletedCopyOrMove; -} - /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -5917,8 +5870,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } checkClassLevelDLLAttribute(Record); - - Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record)); } /// Look up the special member function that would be called by a special @@ -7545,7 +7496,8 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, reinterpret_cast<Decl**>(FieldCollector->getCurFields()), FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); - CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl)); + CheckCompletedCXXClass( + dyn_cast_or_null<CXXRecordDecl>(TagDecl)); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared @@ -11977,10 +11929,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyConstructor); - if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) { - ClassDecl->setImplicitCopyConstructorIsDeleted(); + if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) SetDeclDeleted(CopyConstructor, ClassLoc); - } if (S) PushOnScopeChains(CopyConstructor, S, false); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 085341571ce..abed2586561 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1559,11 +1559,9 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasUninitializedFields = Record.readInt(); Data.HasInheritedConstructor = Record.readInt(); Data.HasInheritedAssignment = Record.readInt(); - Data.NeedOverloadResolutionForCopyConstructor = Record.readInt(); Data.NeedOverloadResolutionForMoveConstructor = Record.readInt(); Data.NeedOverloadResolutionForMoveAssignment = Record.readInt(); Data.NeedOverloadResolutionForDestructor = Record.readInt(); - Data.DefaultedCopyConstructorIsDeleted = Record.readInt(); Data.DefaultedMoveConstructorIsDeleted = Record.readInt(); Data.DefaultedMoveAssignmentIsDeleted = Record.readInt(); Data.DefaultedDestructorIsDeleted = Record.readInt(); @@ -1572,7 +1570,6 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasIrrelevantDestructor = Record.readInt(); Data.HasConstexprNonCopyMoveConstructor = Record.readInt(); Data.HasDefaultedDefaultConstructor = Record.readInt(); - Data.CanPassInRegisters = Record.readInt(); Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt(); Data.HasConstexprDefaultConstructor = Record.readInt(); Data.HasNonLiteralTypeFieldsOrBases = Record.readInt(); @@ -1700,11 +1697,9 @@ void ASTDeclReader::MergeDefinitionData( MATCH_FIELD(HasUninitializedFields) MATCH_FIELD(HasInheritedConstructor) MATCH_FIELD(HasInheritedAssignment) - MATCH_FIELD(NeedOverloadResolutionForCopyConstructor) MATCH_FIELD(NeedOverloadResolutionForMoveConstructor) MATCH_FIELD(NeedOverloadResolutionForMoveAssignment) MATCH_FIELD(NeedOverloadResolutionForDestructor) - MATCH_FIELD(DefaultedCopyConstructorIsDeleted) MATCH_FIELD(DefaultedMoveConstructorIsDeleted) MATCH_FIELD(DefaultedMoveAssignmentIsDeleted) MATCH_FIELD(DefaultedDestructorIsDeleted) @@ -1713,7 +1708,6 @@ void ASTDeclReader::MergeDefinitionData( MATCH_FIELD(HasIrrelevantDestructor) OR_FIELD(HasConstexprNonCopyMoveConstructor) OR_FIELD(HasDefaultedDefaultConstructor) - MATCH_FIELD(CanPassInRegisters) MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr) OR_FIELD(HasConstexprDefaultConstructor) MATCH_FIELD(HasNonLiteralTypeFieldsOrBases) diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 62c9fb46203..9a739579b31 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5875,11 +5875,9 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { Record->push_back(Data.HasUninitializedFields); Record->push_back(Data.HasInheritedConstructor); Record->push_back(Data.HasInheritedAssignment); - Record->push_back(Data.NeedOverloadResolutionForCopyConstructor); Record->push_back(Data.NeedOverloadResolutionForMoveConstructor); Record->push_back(Data.NeedOverloadResolutionForMoveAssignment); Record->push_back(Data.NeedOverloadResolutionForDestructor); - Record->push_back(Data.DefaultedCopyConstructorIsDeleted); Record->push_back(Data.DefaultedMoveConstructorIsDeleted); Record->push_back(Data.DefaultedMoveAssignmentIsDeleted); Record->push_back(Data.DefaultedDestructorIsDeleted); @@ -5888,7 +5886,6 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { Record->push_back(Data.HasIrrelevantDestructor); Record->push_back(Data.HasConstexprNonCopyMoveConstructor); Record->push_back(Data.HasDefaultedDefaultConstructor); - Record->push_back(Data.CanPassInRegisters); Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr); Record->push_back(Data.HasConstexprDefaultConstructor); Record->push_back(Data.HasNonLiteralTypeFieldsOrBases); |

