From: John McCall Date: Thu, 4 Feb 2010 22:26:26 +0000 (+0000) Subject: Extract a common structure for holding information about the definition X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=86ff308724171494395a840fd2efbe25e62f352e;p=clang Extract a common structure for holding information about the definition of a C++ record. Exposed a lot of problems where various routines were silently doing The Wrong Thing (or The Acceptable Thing in The Wrong Order) when presented with a non-definition. Also cuts down on memory usage. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95330 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 0fbdfe97cb..705aff25be 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -174,115 +174,137 @@ public: /// FIXME: This class will disappear once we've properly taught RecordDecl /// to deal with C++-specific things. class CXXRecordDecl : public RecordDecl { - /// UserDeclaredConstructor - True when this class has a - /// user-declared constructor. - bool UserDeclaredConstructor : 1; - /// UserDeclaredCopyConstructor - True when this class has a - /// user-declared copy constructor. - bool UserDeclaredCopyConstructor : 1; + friend void TagDecl::startDefinition(); + + struct DefinitionData { + DefinitionData(CXXRecordDecl *D); + + /// UserDeclaredConstructor - True when this class has a + /// user-declared constructor. + bool UserDeclaredConstructor : 1; + + /// UserDeclaredCopyConstructor - True when this class has a + /// user-declared copy constructor. + bool UserDeclaredCopyConstructor : 1; + + /// UserDeclaredCopyAssignment - True when this class has a + /// user-declared copy assignment operator. + bool UserDeclaredCopyAssignment : 1; + + /// UserDeclaredDestructor - True when this class has a + /// user-declared destructor. + bool UserDeclaredDestructor : 1; + + /// Aggregate - True when this class is an aggregate. + bool Aggregate : 1; + + /// PlainOldData - True when this class is a POD-type. + bool PlainOldData : 1; + + /// Empty - true when this class is empty for traits purposes, + /// i.e. has no data members other than 0-width bit-fields, has no + /// virtual function/base, and doesn't inherit from a non-empty + /// class. Doesn't take union-ness into account. + bool Empty : 1; + + /// Polymorphic - True when this class is polymorphic, i.e. has at + /// least one virtual member or derives from a polymorphic class. + bool Polymorphic : 1; + + /// Abstract - True when this class is abstract, i.e. has at least + /// one pure virtual function, (that can come from a base class). + bool Abstract : 1; + + /// HasTrivialConstructor - True when this class has a trivial constructor. + /// + /// C++ [class.ctor]p5. A constructor is trivial if it is an + /// implicitly-declared default constructor and if: + /// * its class has no virtual functions and no virtual base classes, and + /// * all the direct base classes of its class have trivial constructors, and + /// * for all the nonstatic data members of its class that are of class type + /// (or array thereof), each such class has a trivial constructor. + bool HasTrivialConstructor : 1; + + /// HasTrivialCopyConstructor - True when this class has a trivial copy + /// constructor. + /// + /// C++ [class.copy]p6. A copy constructor for class X is trivial + /// if it is implicitly declared and if + /// * class X has no virtual functions and no virtual base classes, and + /// * each direct base class of X has a trivial copy constructor, and + /// * for all the nonstatic data members of X that are of class type (or + /// array thereof), each such class type has a trivial copy constructor; + /// otherwise the copy constructor is non-trivial. + bool HasTrivialCopyConstructor : 1; + + /// HasTrivialCopyAssignment - True when this class has a trivial copy + /// assignment operator. + /// + /// C++ [class.copy]p11. A copy assignment operator for class X is + /// trivial if it is implicitly declared and if + /// * class X has no virtual functions and no virtual base classes, and + /// * each direct base class of X has a trivial copy assignment operator, and + /// * for all the nonstatic data members of X that are of class type (or + /// array thereof), each such class type has a trivial copy assignment + /// operator; + /// otherwise the copy assignment operator is non-trivial. + bool HasTrivialCopyAssignment : 1; + + /// HasTrivialDestructor - True when this class has a trivial destructor. + /// + /// C++ [class.dtor]p3. A destructor is trivial if it is an + /// implicitly-declared destructor and if: + /// * all of the direct base classes of its class have trivial destructors + /// and + /// * for all of the non-static data members of its class that are of class + /// type (or array thereof), each such class has a trivial destructor. + bool HasTrivialDestructor : 1; + + /// ComputedVisibleConversions - True when visible conversion functions are + /// already computed and are available. + bool ComputedVisibleConversions : 1; + + /// Bases - Base classes of this class. + /// FIXME: This is wasted space for a union. + CXXBaseSpecifier *Bases; - /// UserDeclaredCopyAssignment - True when this class has a - /// user-declared copy assignment operator. - bool UserDeclaredCopyAssignment : 1; + /// NumBases - The number of base class specifiers in Bases. + unsigned NumBases; - /// UserDeclaredDestructor - True when this class has a - /// user-declared destructor. - bool UserDeclaredDestructor : 1; + /// VBases - direct and indirect virtual base classes of this class. + CXXBaseSpecifier *VBases; - /// Aggregate - True when this class is an aggregate. - bool Aggregate : 1; + /// NumVBases - The number of virtual base class specifiers in VBases. + unsigned NumVBases; - /// PlainOldData - True when this class is a POD-type. - bool PlainOldData : 1; + /// Conversions - Overload set containing the conversion functions + /// of this C++ class (but not its inherited conversion + /// functions). Each of the entries in this overload set is a + /// CXXConversionDecl. + UnresolvedSet<4> Conversions; - /// Empty - true when this class is empty for traits purposes, i.e. has no - /// data members other than 0-width bit-fields, has no virtual function/base, - /// and doesn't inherit from a non-empty class. Doesn't take union-ness into - /// account. - bool Empty : 1; + /// VisibleConversions - Overload set containing the conversion + /// functions of this C++ class and all those inherited conversion + /// functions that are visible in this class. Each of the entries + /// in this overload set is a CXXConversionDecl or a + /// FunctionTemplateDecl. + UnresolvedSet<4> VisibleConversions; - /// Polymorphic - True when this class is polymorphic, i.e. has at least one - /// virtual member or derives from a polymorphic class. - bool Polymorphic : 1; + /// Definition - The declaration which defines this record. + CXXRecordDecl *Definition; - /// Abstract - True when this class is abstract, i.e. has at least one - /// pure virtual function, (that can come from a base class). - bool Abstract : 1; + } *DefinitionData; - /// HasTrivialConstructor - True when this class has a trivial constructor. - /// - /// C++ [class.ctor]p5. A constructor is trivial if it is an - /// implicitly-declared default constructor and if: - /// * its class has no virtual functions and no virtual base classes, and - /// * all the direct base classes of its class have trivial constructors, and - /// * for all the nonstatic data members of its class that are of class type - /// (or array thereof), each such class has a trivial constructor. - bool HasTrivialConstructor : 1; - - /// HasTrivialCopyConstructor - True when this class has a trivial copy - /// constructor. - /// - /// C++ [class.copy]p6. A copy constructor for class X is trivial - /// if it is implicitly declared and if - /// * class X has no virtual functions and no virtual base classes, and - /// * each direct base class of X has a trivial copy constructor, and - /// * for all the nonstatic data members of X that are of class type (or - /// array thereof), each such class type has a trivial copy constructor; - /// otherwise the copy constructor is non-trivial. - bool HasTrivialCopyConstructor : 1; - - /// HasTrivialCopyAssignment - True when this class has a trivial copy - /// assignment operator. - /// - /// C++ [class.copy]p11. A copy assignment operator for class X is - /// trivial if it is implicitly declared and if - /// * class X has no virtual functions and no virtual base classes, and - /// * each direct base class of X has a trivial copy assignment operator, and - /// * for all the nonstatic data members of X that are of class type (or - /// array thereof), each such class type has a trivial copy assignment - /// operator; - /// otherwise the copy assignment operator is non-trivial. - bool HasTrivialCopyAssignment : 1; - - /// HasTrivialDestructor - True when this class has a trivial destructor. - /// - /// C++ [class.dtor]p3. A destructor is trivial if it is an - /// implicitly-declared destructor and if: - /// * all of the direct base classes of its class have trivial destructors - /// and - /// * for all of the non-static data members of its class that are of class - /// type (or array thereof), each such class has a trivial destructor. - bool HasTrivialDestructor : 1; - - /// ComputedVisibleConversions - True when visible conversion functions are - /// already computed and are available. - bool ComputedVisibleConversions : 1; - - /// Bases - Base classes of this class. - /// FIXME: This is wasted space for a union. - CXXBaseSpecifier *Bases; - - /// NumBases - The number of base class specifiers in Bases. - unsigned NumBases; - - /// VBases - direct and indirect virtual base classes of this class. - CXXBaseSpecifier *VBases; - - /// NumVBases - The number of virtual base class specifiers in VBases. - unsigned NumVBases; - - /// Conversions - Overload set containing the conversion functions - /// of this C++ class (but not its inherited conversion - /// functions). Each of the entries in this overload set is a - /// CXXConversionDecl. - UnresolvedSet<4> Conversions; - - /// VisibleConversions - Overload set containing the conversion functions - /// of this C++ class and all those inherited conversion functions that - /// are visible in this class. Each of the entries in this overload set is - /// a CXXConversionDecl or a FunctionTemplateDecl. - UnresolvedSet<4> VisibleConversions; + struct DefinitionData &data() { + assert(DefinitionData && "queried property of class with no definition"); + return *DefinitionData; + } + + const struct DefinitionData &data() const { + assert(DefinitionData && "queried property of class with no definition"); + return *DefinitionData; + } /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. @@ -336,6 +358,13 @@ public: return cast(RecordDecl::getCanonicalDecl()); } + CXXRecordDecl *getDefinition(ASTContext& C) const { + if (!DefinitionData) return 0; + return data().Definition; + } + + bool hasDefinition() const { return DefinitionData != 0; } + static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation TKL = SourceLocation(), @@ -345,7 +374,7 @@ public: virtual void Destroy(ASTContext& C); bool isDynamicClass() const { - return Polymorphic || NumVBases != 0; + return data().Polymorphic || data().NumVBases != 0; } /// setBases - Sets the base classes of this struct or class. @@ -354,12 +383,14 @@ public: /// getNumBases - Retrieves the number of base classes of this /// class. - unsigned getNumBases() const { return NumBases; } + unsigned getNumBases() const { return data().NumBases; } - base_class_iterator bases_begin() { return Bases; } - base_class_const_iterator bases_begin() const { return Bases; } - base_class_iterator bases_end() { return Bases + NumBases; } - base_class_const_iterator bases_end() const { return Bases + NumBases; } + base_class_iterator bases_begin() { return data().Bases; } + base_class_const_iterator bases_begin() const { return data().Bases; } + base_class_iterator bases_end() { return bases_begin() + data().NumBases; } + base_class_const_iterator bases_end() const { + return bases_begin() + data().NumBases; + } reverse_base_class_iterator bases_rbegin() { return reverse_base_class_iterator(bases_end()); } @@ -375,12 +406,14 @@ public: /// getNumVBases - Retrieves the number of virtual base classes of this /// class. - unsigned getNumVBases() const { return NumVBases; } + unsigned getNumVBases() const { return data().NumVBases; } - base_class_iterator vbases_begin() { return VBases; } - base_class_const_iterator vbases_begin() const { return VBases; } - base_class_iterator vbases_end() { return VBases + NumVBases; } - base_class_const_iterator vbases_end() const { return VBases + NumVBases; } + base_class_iterator vbases_begin() { return data().VBases; } + base_class_const_iterator vbases_begin() const { return data().VBases; } + base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; } + base_class_const_iterator vbases_end() const { + return vbases_begin() + data().NumVBases; + } reverse_base_class_iterator vbases_rbegin() { return reverse_base_class_iterator(vbases_end()); } @@ -445,17 +478,14 @@ public: /// user-declared constructors. When true, a default constructor /// will not be implicitly declared. bool hasUserDeclaredConstructor() const { - assert((isDefinition() || - cast(getTypeForDecl())->isBeingDefined()) && - "Incomplete record decl!"); - return UserDeclaredConstructor; + return data().UserDeclaredConstructor; } /// hasUserDeclaredCopyConstructor - Whether this class has a /// user-declared copy constructor. When false, a copy constructor /// will be implicitly declared. bool hasUserDeclaredCopyConstructor() const { - return UserDeclaredCopyConstructor; + return data().UserDeclaredCopyConstructor; } /// addedAssignmentOperator - Notify the class that another assignment @@ -467,45 +497,45 @@ public: /// user-declared copy assignment operator. When false, a copy /// assigment operator will be implicitly declared. bool hasUserDeclaredCopyAssignment() const { - return UserDeclaredCopyAssignment; + return data().UserDeclaredCopyAssignment; } /// hasUserDeclaredDestructor - Whether this class has a /// user-declared destructor. When false, a destructor will be /// implicitly declared. - bool hasUserDeclaredDestructor() const { return UserDeclaredDestructor; } + bool hasUserDeclaredDestructor() const { + return data().UserDeclaredDestructor; + } /// setUserDeclaredDestructor - Set whether this class has a /// user-declared destructor. If not set by the time the class is /// fully defined, a destructor will be implicitly declared. void setUserDeclaredDestructor(bool UCD) { - UserDeclaredDestructor = UCD; + data().UserDeclaredDestructor = UCD; } /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. UnresolvedSetImpl *getConversionFunctions() { - assert((this->isDefinition() || - cast(getTypeForDecl())->isBeingDefined()) && - "getConversionFunctions() called on incomplete type"); - return &Conversions; + return &data().Conversions; } const UnresolvedSetImpl *getConversionFunctions() const { - assert((this->isDefinition() || - cast(getTypeForDecl())->isBeingDefined()) && - "getConversionFunctions() called on incomplete type"); - return &Conversions; + return &data().Conversions; } typedef UnresolvedSetImpl::iterator conversion_iterator; - conversion_iterator conversion_begin() const { return Conversions.begin(); } - conversion_iterator conversion_end() const { return Conversions.end(); } + conversion_iterator conversion_begin() const { + return getConversionFunctions()->begin(); + } + conversion_iterator conversion_end() const { + return getConversionFunctions()->end(); + } /// Replaces a conversion function with a new declaration. /// /// Returns true if the old conversion was found. bool replaceConversion(const NamedDecl* Old, NamedDecl *New) { - return Conversions.replace(Old, New); + return getConversionFunctions()->replace(Old, New); } /// getVisibleConversionFunctions - get all conversion functions visible @@ -532,11 +562,11 @@ public: /// [dcl.init.aggr]), which is a class with no user-declared /// constructors, no private or protected non-static data members, /// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1). - bool isAggregate() const { return Aggregate; } + bool isAggregate() const { return data().Aggregate; } /// setAggregate - Set whether this class is an aggregate (C++ /// [dcl.init.aggr]). - void setAggregate(bool Agg) { Aggregate = Agg; } + void setAggregate(bool Agg) { data().Aggregate = Agg; } /// setMethodAsVirtual - Make input method virtual and set the necesssary /// special function bits and other bits accordingly. @@ -546,66 +576,74 @@ public: /// that is an aggregate that has no non-static non-POD data members, no /// reference data members, no user-defined copy assignment operator and no /// user-defined destructor. - bool isPOD() const { return PlainOldData; } + bool isPOD() const { return data().PlainOldData; } /// setPOD - Set whether this class is a POD-type (C++ [class]p4). - void setPOD(bool POD) { PlainOldData = POD; } + void setPOD(bool POD) { data().PlainOldData = POD; } /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which /// means it has a virtual function, virtual base, data member (other than /// 0-width bit-field) or inherits from a non-empty class. Does NOT include /// a check for union-ness. - bool isEmpty() const { return Empty; } + bool isEmpty() const { return data().Empty; } /// Set whether this class is empty (C++0x [meta.unary.prop]) - void setEmpty(bool Emp) { Empty = Emp; } + void setEmpty(bool Emp) { data().Empty = Emp; } /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]), /// which means that the class contains or inherits a virtual function. - bool isPolymorphic() const { return Polymorphic; } + bool isPolymorphic() const { return data().Polymorphic; } /// setPolymorphic - Set whether this class is polymorphic (C++ /// [class.virtual]). - void setPolymorphic(bool Poly) { Polymorphic = Poly; } + void setPolymorphic(bool Poly) { data().Polymorphic = Poly; } /// isAbstract - Whether this class is abstract (C++ [class.abstract]), /// which means that the class contains or inherits a pure virtual function. - bool isAbstract() const { return Abstract; } + bool isAbstract() const { return data().Abstract; } /// setAbstract - Set whether this class is abstract (C++ [class.abstract]) - void setAbstract(bool Abs) { Abstract = Abs; } + void setAbstract(bool Abs) { data().Abstract = Abs; } // hasTrivialConstructor - Whether this class has a trivial constructor // (C++ [class.ctor]p5) - bool hasTrivialConstructor() const { return HasTrivialConstructor; } + bool hasTrivialConstructor() const { return data().HasTrivialConstructor; } // setHasTrivialConstructor - Set whether this class has a trivial constructor // (C++ [class.ctor]p5) - void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; } + void setHasTrivialConstructor(bool TC) { data().HasTrivialConstructor = TC; } // hasTrivialCopyConstructor - Whether this class has a trivial copy // constructor (C++ [class.copy]p6) - bool hasTrivialCopyConstructor() const { return HasTrivialCopyConstructor; } + bool hasTrivialCopyConstructor() const { + return data().HasTrivialCopyConstructor; + } // setHasTrivialCopyConstructor - Set whether this class has a trivial // copy constructor (C++ [class.copy]p6) - void setHasTrivialCopyConstructor(bool TC) { HasTrivialCopyConstructor = TC; } + void setHasTrivialCopyConstructor(bool TC) { + data().HasTrivialCopyConstructor = TC; + } // hasTrivialCopyAssignment - Whether this class has a trivial copy // assignment operator (C++ [class.copy]p11) - bool hasTrivialCopyAssignment() const { return HasTrivialCopyAssignment; } + bool hasTrivialCopyAssignment() const { + return data().HasTrivialCopyAssignment; + } // setHasTrivialCopyAssignment - Set whether this class has a // trivial copy assignment operator (C++ [class.copy]p11) - void setHasTrivialCopyAssignment(bool TC) { HasTrivialCopyAssignment = TC; } + void setHasTrivialCopyAssignment(bool TC) { + data().HasTrivialCopyAssignment = TC; + } // hasTrivialDestructor - Whether this class has a trivial destructor // (C++ [class.dtor]p3) - bool hasTrivialDestructor() const { return HasTrivialDestructor; } + bool hasTrivialDestructor() const { return data().HasTrivialDestructor; } // setHasTrivialDestructor - Set whether this class has a trivial destructor // (C++ [class.dtor]p3) - void setHasTrivialDestructor(bool TC) { HasTrivialDestructor = TC; } + void setHasTrivialDestructor(bool TC) { data().HasTrivialDestructor = TC; } /// \brief If this record is an instantiation of a member class, /// retrieves the member class from which it was instantiated. diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b5d378d0e3..4d8114d617 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1706,6 +1706,8 @@ def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_no_member : Error<"no member named %0 in %1">; def err_member_redeclared : Error<"class member cannot be redeclared">; +def err_member_def_undefined_record : Error< + "out-of-line definition of %0 from class %1 without definition">; def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; def err_nonstatic_member_out_of_line : Error< diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index c3e976a080..ba1def643e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1373,6 +1373,16 @@ void TagDecl::startDefinition() { TagT->decl.setPointer(this); TagT->decl.setInt(1); } + + if (isa(this)) { + CXXRecordDecl *D = cast(this); + struct CXXRecordDecl::DefinitionData *Data = + new (getASTContext()) struct CXXRecordDecl::DefinitionData(D); + do { + D->DefinitionData = Data; + D = cast_or_null(D->getPreviousDeclaration()); + } while (D); + } } void TagDecl::completeDefinition() { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 3d690d15f2..02ad36d479 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -25,18 +25,23 @@ using namespace clang; // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// -CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl, - SourceLocation TKL) - : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), - UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), +CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) + : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), HasTrivialConstructor(true), HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), ComputedVisibleConversions(false), Bases(0), NumBases(0), VBases(0), NumVBases(0), + Definition(D) { +} + +CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl *PrevDecl, + SourceLocation TKL) + : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), + DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, @@ -57,8 +62,11 @@ CXXRecordDecl::~CXXRecordDecl() { } void CXXRecordDecl::Destroy(ASTContext &C) { - C.Deallocate(Bases); - C.Deallocate(VBases); + if (data().Definition == this) { + C.Deallocate(data().Bases); + C.Deallocate(data().VBases); + C.Deallocate(&data()); + } this->RecordDecl::Destroy(C); } @@ -69,19 +77,19 @@ CXXRecordDecl::setBases(ASTContext &C, // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. - Aggregate = false; + data().Aggregate = false; - if (this->Bases) - C.Deallocate(this->Bases); + if (data().Bases) + C.Deallocate(data().Bases); int vbaseCount = 0; llvm::SmallVector UniqueVbases; bool hasDirectVirtualBase = false; - this->Bases = new(C) CXXBaseSpecifier [NumBases]; - this->NumBases = NumBases; + data().Bases = new(C) CXXBaseSpecifier [NumBases]; + data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { - this->Bases[i] = *Bases[i]; + data().Bases[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); @@ -130,13 +138,13 @@ CXXRecordDecl::setBases(ASTContext &C, } if (vbaseCount > 0) { // build AST for inhireted, direct or indirect, virtual bases. - this->VBases = new (C) CXXBaseSpecifier [vbaseCount]; - this->NumVBases = vbaseCount; + data().VBases = new (C) CXXBaseSpecifier [vbaseCount]; + data().NumVBases = vbaseCount; for (int i = 0; i < vbaseCount; i++) { QualType QT = UniqueVbases[i]->getType(); CXXRecordDecl *VBaseClassDecl = cast(QT->getAs()->getDecl()); - this->VBases[i] = + data().VBases[i] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == RecordDecl::TK_class, UniqueVbases[i]->getAccessSpecifier(), QT); @@ -239,32 +247,32 @@ CXXRecordDecl::addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl) { assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl"); // Note that we have a user-declared constructor. - UserDeclaredConstructor = true; + data().UserDeclaredConstructor = true; // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with no // user-declared constructors (12.1) [...]. - Aggregate = false; + data().Aggregate = false; // C++ [class]p4: // A POD-struct is an aggregate class [...] - PlainOldData = false; + data().PlainOldData = false; // C++ [class.ctor]p5: // A constructor is trivial if it is an implicitly-declared default // constructor. // FIXME: C++0x: don't do this for "= default" default constructors. - HasTrivialConstructor = false; + data().HasTrivialConstructor = false; // Note when we have a user-declared copy constructor, which will // suppress the implicit declaration of a copy constructor. if (ConDecl->isCopyConstructor()) { - UserDeclaredCopyConstructor = true; + data().UserDeclaredCopyConstructor = true; // C++ [class.copy]p6: // A copy constructor is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy constructors. - HasTrivialCopyConstructor = false; + data().HasTrivialCopyConstructor = false; } } @@ -295,17 +303,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, OpDecl->setCopyAssignment(true); // Suppress the implicit declaration of a copy constructor. - UserDeclaredCopyAssignment = true; + data().UserDeclaredCopyAssignment = true; // C++ [class.copy]p11: // A copy assignment operator is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy operators. - HasTrivialCopyAssignment = false; + data().HasTrivialCopyAssignment = false; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. - PlainOldData = false; + data().PlainOldData = false; } void @@ -415,42 +423,42 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) - return &Conversions; + return &data().Conversions; // If visible conversion list is already evaluated, return it. - if (ComputedVisibleConversions) - return &VisibleConversions; + if (data().ComputedVisibleConversions) + return &data().VisibleConversions; llvm::SmallPtrSet TopConversionsTypeSet; collectConversionFunctions(TopConversionsTypeSet); getNestedVisibleConversionFunctions(this, TopConversionsTypeSet, TopConversionsTypeSet); - ComputedVisibleConversions = true; - return &VisibleConversions; + data().ComputedVisibleConversions = true; + return &data().VisibleConversions; } void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - VisibleConversions.addDecl(ConvDecl); + data().VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addVisibleConversionFunction( FunctionTemplateDecl *ConvDecl) { assert(isa(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - VisibleConversions.addDecl(ConvDecl); + data().VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - Conversions.addDecl(ConvDecl); + data().Conversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { assert(isa(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - Conversions.addDecl(ConvDecl); + data().Conversions.addDecl(ConvDecl); } diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 29552ce444..5236d20634 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -256,6 +256,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) { if (const RecordType *RecordTy = dyn_cast(Ty)) { const CXXRecordDecl *RD = cast(RecordTy->getDecl()); + if (!RD->hasDefinition()) + return false; + if (!RD->isDynamicClass()) return false; @@ -469,7 +472,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { const CXXRecordDecl *RD = cast(cast(Ty)->getDecl()); - if (!RD->getNumBases()) { + if (!RD->hasDefinition() || !RD->getNumBases()) { // abi::__class_type_info. VtableName = "_ZTVN10__cxxabiv117__class_type_infoE"; } else if (CanUseSingleInheritance(RD)) { @@ -566,7 +569,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) { case Type::Record: { const CXXRecordDecl *RD = cast(cast(Ty)->getDecl()); - if (!RD->getNumBases()) { + if (!RD->hasDefinition() || !RD->getNumBases()) { // We don't need to emit any fields. break; } diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 838f62a5cb..e2f45fe076 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -399,18 +399,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { /// enum. const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { - // FIXME. This may have to move to a better place. - if (const CXXRecordDecl *RD = dyn_cast(TD)) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - if (!i->isVirtual()) { - const CXXRecordDecl *Base = - cast(i->getType()->getAs()->getDecl()); - ConvertTagDeclType(Base); - } - } - } - // TagDecl's are not necessarily unique, instead use the (clang) // type connected to the decl. const Type *Key = @@ -446,6 +434,18 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { const RecordDecl *RD = cast(TD); + // Force conversion of non-virtual base classes recursively. + if (const CXXRecordDecl *RD = dyn_cast(TD)) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + ConvertTagDeclType(Base); + } + } + } + // Layout fields. CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2e3a4352f2..bef53df4f0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -510,9 +510,18 @@ static void RemoveUsingDecls(LookupResult &R) { } static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { + if (D->isInvalidDecl()) + return false; + if (D->isUsed() || D->hasAttr()) return false; - + + // White-list anything that isn't a local variable. + if (!isa(D) || isa(D) || isa(D) || + !D->getDeclContext()->isFunctionOrMethod()) + return false; + + // Types of valid local variables should be complete, so this should succeed. if (const ValueDecl *VD = dyn_cast(D)) { if (const RecordType *RT = VD->getType()->getAs()) { if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { @@ -524,9 +533,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { } } - return (isa(D) && !isa(D) && - !isa(D) && - D->getDeclContext()->isFunctionOrMethod()); + return true; } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { @@ -1903,6 +1910,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (!DC->isDependentContext() && RequireCompleteDeclContext(D.getCXXScopeSpec())) return DeclPtrTy(); + + if (isa(DC) && !cast(DC)->hasDefinition()) { + Diag(D.getIdentifierLoc(), + diag::err_member_def_undefined_record) + << Name << DC << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + } LookupQualifiedName(Previous, DC); @@ -3020,7 +3034,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // Fake up an access specifier if it's supposed to be a class member. - if (isa(NewFD->getDeclContext())) + if (!Redeclaration && isa(NewFD->getDeclContext())) NewFD->setAccess(AS_public); // An out-of-line member function declaration must also be a @@ -5212,7 +5226,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, NewFD->setInvalidDecl(); } - if (getLangOptions().CPlusPlus) { + if (!InvalidDecl && getLangOptions().CPlusPlus) { CXXRecordDecl* CXXRecord = cast(Record); if (!T->isPODType()) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 4552d544b9..e746a8e98c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -680,7 +680,8 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base) { CXXRecordDecl *DerivedRD = cast(DerivedRT->getDecl()); CXXRecordDecl *BaseRD = cast(BaseRT->getDecl()); - return DerivedRD->isDerivedFrom(BaseRD); + // FIXME: instantiate DerivedRD if necessary. We need a PoI for this. + return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD); } /// \brief Determine whether the type \p Derived is a C++ class that is @@ -1998,13 +1999,15 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, if (!RT) return false; - const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); - if (!RD) - return false; + const CXXRecordDecl *RD = cast(RT->getDecl()); if (CurrentRD && CurrentRD != RD) return false; + // FIXME: is this reasonable? It matches current behavior, but.... + if (!RD->getDefinition(Context)) + return false; + if (!RD->isAbstract()) return false; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 850308e147..9033137898 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -71,19 +71,18 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, QualType T = E->getType(); if (const RecordType *RecordT = T->getAs()) { CXXRecordDecl *RecordD = cast(RecordT->getDecl()); + // C++ [expr.typeid]p3: + // [...] If the type of the expression is a class type, the class + // shall be completely-defined. + if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid)) + return ExprError(); + // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an lvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) isUnevaluatedOperand = false; - else { - // C++ [expr.typeid]p3: - // [...] If the type of the expression is a class type, the class - // shall be completely-defined. - if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid)) - return ExprError(); - } } // C++ [expr.typeid]p4: @@ -1985,10 +1984,8 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!RT) return Owned(E); - CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->hasTrivialDestructor()) - return Owned(E); - + // If this is the result of a call expression, our source might + // actually be a reference, in which case we shouldn't bind. if (CallExpr *CE = dyn_cast(E)) { QualType Ty = CE->getCallee()->getType(); if (const PointerType *PT = Ty->getAs()) @@ -1998,6 +1995,13 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { if (FTy->getResultType()->isReferenceType()) return Owned(E); } + + // That should be enough to guarantee that this type is complete. + // If it has a trivial destructor, we can avoid the extra copy. + CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return Owned(E); + CXXTemporary *Temp = CXXTemporary::Create(Context, RD->getDestructor(Context)); ExprTemporaries.push_back(Temp); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index d1a379435e..c4b261fad4 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1406,6 +1406,12 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, AssociatedClasses); } + // Only recurse into base classes for complete types. + if (!Class->hasDefinition()) { + // FIXME: we might need to instantiate templates here + return; + } + // Add direct and indirect base classes along with their associated // namespaces. llvm::SmallVector Bases; @@ -2058,6 +2064,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Traverse the contexts of inherited C++ classes. if (CXXRecordDecl *Record = dyn_cast(Ctx)) { + if (!Record->hasDefinition()) + return; + for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), BEnd = Record->bases_end(); B != BEnd; ++B) { diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 1319f337a6..c76cbca160 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3408,6 +3408,9 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); + if (!ClassDecl->hasDefinition()) + return VRQuals; + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions();