From: Richard Smith Date: Sat, 25 Feb 2012 07:33:38 +0000 (+0000) Subject: Teach CXXRecordDecl::hasIrrelevantDestructor to check the base classes and X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dfefb840e36f069286ef6cf178ef339c90f4603d;p=clang Teach CXXRecordDecl::hasIrrelevantDestructor to check the base classes and data members for deleted or user-provided destructors. Now it's computed in advance, serialize it, and in passing fix all the other record DefinitionData flags whose serialization was missing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151441 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index afb5375745..b2773027e0 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -469,6 +469,10 @@ class CXXRecordDecl : public RecordDecl { /// type (or array thereof), each such class has a trivial destructor. bool HasTrivialDestructor : 1; + /// HasIrrelevantDestructor - True when this class has a destructor with no + /// semantic effect. + bool HasIrrelevantDestructor : 1; + /// HasNonLiteralTypeFieldsOrBases - True when this class contains at least /// one non-static data member or base class of non-literal or volatile /// type. @@ -1145,9 +1149,9 @@ public: // hasIrrelevantDestructor - Whether this class has a destructor which has no // semantic effect. Any such destructor will be trivial, public, defaulted - // and not deleted. + // and not deleted, and will call only irrelevant destructors. bool hasIrrelevantDestructor() const { - return hasTrivialDestructor() && !hasUserDeclaredDestructor(); + return data().HasIrrelevantDestructor; } // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index d7e979526d..a7766255d0 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1849,16 +1849,29 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.HasProtectedFields = FromData.HasProtectedFields; ToData.HasPublicFields = FromData.HasPublicFields; ToData.HasMutableFields = FromData.HasMutableFields; + ToData.HasOnlyCMembers = FromData.HasOnlyCMembers; ToData.HasTrivialDefaultConstructor = FromData.HasTrivialDefaultConstructor; ToData.HasConstexprNonCopyMoveConstructor = FromData.HasConstexprNonCopyMoveConstructor; + ToData.DefaultedDefaultConstructorIsConstexpr + = FromData.DefaultedDefaultConstructorIsConstexpr; + ToData.DefaultedCopyConstructorIsConstexpr + = FromData.DefaultedCopyConstructorIsConstexpr; + ToData.DefaultedMoveConstructorIsConstexpr + = FromData.DefaultedMoveConstructorIsConstexpr; + ToData.HasConstexprDefaultConstructor + = FromData.HasConstexprDefaultConstructor; + ToData.HasConstexprCopyConstructor = FromData.HasConstexprCopyConstructor; + ToData.HasConstexprMoveConstructor = FromData.HasConstexprMoveConstructor; ToData.HasTrivialCopyConstructor = FromData.HasTrivialCopyConstructor; ToData.HasTrivialMoveConstructor = FromData.HasTrivialMoveConstructor; ToData.HasTrivialCopyAssignment = FromData.HasTrivialCopyAssignment; ToData.HasTrivialMoveAssignment = FromData.HasTrivialMoveAssignment; ToData.HasTrivialDestructor = FromData.HasTrivialDestructor; + ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor; ToData.HasNonLiteralTypeFieldsOrBases = FromData.HasNonLiteralTypeFieldsOrBases; + // ComputedVisibleConversions not imported. ToData.UserProvidedDefaultConstructor = FromData.UserProvidedDefaultConstructor; ToData.DeclaredDefaultConstructor = FromData.DeclaredDefaultConstructor; @@ -1870,7 +1883,8 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.FailedImplicitMoveConstructor = FromData.FailedImplicitMoveConstructor; ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment; - + ToData.IsLambda = FromData.IsLambda; + SmallVector Bases; for (CXXRecordDecl::base_class_iterator Base1 = FromCXX->bases_begin(), diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 4dd44cbf17..89a6661cbf 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -52,6 +52,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasConstexprMoveConstructor(false), HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true), HasTrivialDestructor(true), + HasIrrelevantDestructor(true), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), DeclaredMoveConstructor(false), @@ -284,7 +285,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // have trivial destructors. if (!BaseClassDecl->hasTrivialDestructor()) data().HasTrivialDestructor = false; - + + if (!BaseClassDecl->hasIrrelevantDestructor()) + data().HasIrrelevantDestructor = false; + // A class has an Objective-C object member if... or any of its bases // has an Objective-C object member. if (BaseClassDecl->hasObjectMember()) @@ -648,7 +652,8 @@ NotASpecialMember:; if (CXXDestructorDecl *DD = dyn_cast(D)) { data().DeclaredDestructor = true; data().UserDeclaredDestructor = true; - + data().HasIrrelevantDestructor = false; + // C++ [class]p4: // A POD-struct is an aggregate class that has [...] no user-defined // destructor. @@ -865,6 +870,8 @@ NotASpecialMember:; if (!FieldRec->hasTrivialDestructor()) data().HasTrivialDestructor = false; + if (!FieldRec->hasIrrelevantDestructor()) + data().HasIrrelevantDestructor = false; if (FieldRec->hasObjectMember()) setHasObjectMember(true); @@ -1248,6 +1255,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { Data.HasTrivialCopyConstructor = false; Data.HasTrivialCopyAssignment = false; Data.HasTrivialDestructor = false; + Data.HasIrrelevantDestructor = false; } // If the class may be abstract (but hasn't been marked as such), check for diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index ce92e9cab4..f79c2f51b7 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1072,13 +1072,21 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasProtectedFields = Record[Idx++]; Data.HasPublicFields = Record[Idx++]; Data.HasMutableFields = Record[Idx++]; + Data.HasOnlyCMembers = Record[Idx++]; Data.HasTrivialDefaultConstructor = Record[Idx++]; Data.HasConstexprNonCopyMoveConstructor = Record[Idx++]; + Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++]; + Data.DefaultedCopyConstructorIsConstexpr = Record[Idx++]; + Data.DefaultedMoveConstructorIsConstexpr = Record[Idx++]; + Data.HasConstexprDefaultConstructor = Record[Idx++]; + Data.HasConstexprCopyConstructor = Record[Idx++]; + Data.HasConstexprMoveConstructor = Record[Idx++]; Data.HasTrivialCopyConstructor = Record[Idx++]; Data.HasTrivialMoveConstructor = Record[Idx++]; Data.HasTrivialCopyAssignment = Record[Idx++]; Data.HasTrivialMoveAssignment = Record[Idx++]; Data.HasTrivialDestructor = Record[Idx++]; + Data.HasIrrelevantDestructor = Record[Idx++]; Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++]; Data.ComputedVisibleConversions = Record[Idx++]; Data.UserProvidedDefaultConstructor = Record[Idx++]; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index f626f0b7e0..f497a038b3 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4296,13 +4296,21 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasProtectedFields); Record.push_back(Data.HasPublicFields); Record.push_back(Data.HasMutableFields); + Record.push_back(Data.HasOnlyCMembers); Record.push_back(Data.HasTrivialDefaultConstructor); Record.push_back(Data.HasConstexprNonCopyMoveConstructor); + Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr); + Record.push_back(Data.DefaultedCopyConstructorIsConstexpr); + Record.push_back(Data.DefaultedMoveConstructorIsConstexpr); + Record.push_back(Data.HasConstexprDefaultConstructor); + Record.push_back(Data.HasConstexprCopyConstructor); + Record.push_back(Data.HasConstexprMoveConstructor); Record.push_back(Data.HasTrivialCopyConstructor); Record.push_back(Data.HasTrivialMoveConstructor); Record.push_back(Data.HasTrivialCopyAssignment); Record.push_back(Data.HasTrivialMoveAssignment); Record.push_back(Data.HasTrivialDestructor); + Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasNonLiteralTypeFieldsOrBases); Record.push_back(Data.ComputedVisibleConversions); Record.push_back(Data.UserProvidedDefaultConstructor); @@ -4314,6 +4322,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.DeclaredDestructor); Record.push_back(Data.FailedImplicitMoveConstructor); Record.push_back(Data.FailedImplicitMoveAssignment); + // IsLambda bit is already saved. Record.push_back(Data.NumBases); if (Data.NumBases > 0) diff --git a/test/PCH/cxx0x-default-delete.cpp b/test/PCH/cxx0x-default-delete.cpp index 3ecb19c295..6eb65d61df 100644 --- a/test/PCH/cxx0x-default-delete.cpp +++ b/test/PCH/cxx0x-default-delete.cpp @@ -12,6 +12,14 @@ struct foo { void bar() = delete; // expected-note{{deleted here}} }; +struct baz { + ~baz() = delete; // expected-note{{deleted here}} +}; + +class quux { + ~quux() = default; // expected-note{{private here}} +}; + #else foo::foo() { } // expected-error{{definition of explicitly defaulted default constructor}} @@ -20,4 +28,7 @@ void fn() { f.bar(); // expected-error{{deleted function}} } +baz bz; // expected-error{{deleted function}} +quux qx; // expected-error{{private destructor}} + #endif diff --git a/test/PCH/cxx11-constexpr.cpp b/test/PCH/cxx11-constexpr.cpp new file mode 100644 index 0000000000..338543ecf9 --- /dev/null +++ b/test/PCH/cxx11-constexpr.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t +// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s + +#ifndef HEADER_INCLUDED + +#define HEADER_INCLUDED + +struct B { + B(); // expected-note {{here}} + constexpr B(char) {} +}; + +struct C { // expected-note {{not an aggregate and has no constexpr constructors}} + B b; + double d = 0.0; +}; + +struct D : B { + constexpr D(int n) : B('x'), k(2*n+1) {} + int k; +}; + +#else + +static_assert(D(4).k == 9, ""); +constexpr int f(C c) { return 0; } // expected-error {{not a literal type}} +constexpr B b; // expected-error {{constant expression}} expected-note {{non-constexpr}} + +#endif diff --git a/test/SemaCXX/defaulted-private-dtor.cpp b/test/SemaCXX/defaulted-private-dtor.cpp index a15bdde60c..a4b868c0ad 100644 --- a/test/SemaCXX/defaulted-private-dtor.cpp +++ b/test/SemaCXX/defaulted-private-dtor.cpp @@ -2,7 +2,7 @@ class BadDtor { // A private, but nonetheless trivial, destructor. - ~BadDtor() = default; // expected-note 9{{here}} + ~BadDtor() = default; // expected-note 11{{here}} friend class K; }; void f() { @@ -12,6 +12,15 @@ void f() { BadDtor dd; // expected-error {{private destructor}} throw dd; // expected-error {{private destructor}} } +struct V { // expected-note {{here}} + V(); + BadDtor bd; // expected-error {{private destructor}} +}; +V v; // expected-error {{deleted function}} expected-note {{required here}} +struct W : BadDtor { // expected-note {{here}} expected-error {{private destructor}} + W(); +}; +W w; // expected-error {{deleted function}} expected-note {{required here}} struct X : BadDtor { // expected-error {{private destructor}} ~X() {} };