From: Fariborz Jahanian Date: Tue, 21 Jul 2009 22:36:06 +0000 (+0000) Subject: Patch to accomodate Doug's comment on default X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=393612e6c7727f1fee50039254d9f434364cc0b2;p=clang Patch to accomodate Doug's comment on default destruction of base/members for each destructor AST. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76663 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 8da44de121..14a3bd7121 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -901,10 +901,7 @@ class CXXDestructorDecl : public CXXMethodDecl { /// Support for base and member destruction. /// BaseOrMemberDestructions - The arguments used to destruct the base /// or member. - // FIXME. May want to use a new class as CXXBaseOrMemberInitializer has - // more info. than is needed. At the least, CXXBaseOrMemberInitializer need - // be renamed to something neutral. - CXXBaseOrMemberInitializer **BaseOrMemberDestructions; + uintptr_t *BaseOrMemberDestructions; unsigned NumBaseOrMemberDestructions; CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L, @@ -915,7 +912,8 @@ class CXXDestructorDecl : public CXXMethodDecl { BaseOrMemberDestructions(0), NumBaseOrMemberDestructions(0) { setImplicit(isImplicitlyDeclared); } - + virtual void Destroy(ASTContext& C); + public: static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, @@ -941,32 +939,88 @@ public: } /// destr_iterator - Iterates through the member/base destruction list. - typedef CXXBaseOrMemberInitializer **destr_iterator; - + /// destr_const_iterator - Iterates through the member/base destruction list. - typedef CXXBaseOrMemberInitializer * const * destr_const_iterator; + typedef uintptr_t const destr_const_iterator; /// destr_begin() - Retrieve an iterator to the first destructed member/base. - destr_iterator destr_begin() { return BaseOrMemberDestructions; } + uintptr_t* destr_begin() { + return BaseOrMemberDestructions; + } /// destr_begin() - Retrieve an iterator to the first destructed member/base. - destr_const_iterator destr_begin() const { return BaseOrMemberDestructions; } + uintptr_t* destr_begin() const { + return BaseOrMemberDestructions; + } /// destr_end() - Retrieve an iterator past the last destructed member/base. - destr_iterator destr_end() { + uintptr_t* destr_end() { return BaseOrMemberDestructions + NumBaseOrMemberDestructions; } /// destr_end() - Retrieve an iterator past the last destructed member/base. - destr_const_iterator destr_end() const { + uintptr_t* destr_end() const { return BaseOrMemberDestructions + NumBaseOrMemberDestructions; } - /// getNumArgs - Determine the number of arguments used to - /// destruct the member or base. + /// getNumBaseOrMemberDestructions - Number of base and non-static members + /// to destroy. unsigned getNumBaseOrMemberDestructions() const { return NumBaseOrMemberDestructions; } - void setBaseOrMemberDestructions(ASTContext &C); + /// getBaseOrMember - get the generic 'member' representing either the field + /// or a base class. + uintptr_t* getBaseOrMemberToDestroy() const { + return BaseOrMemberDestructions; + } + + /// isVbaseToDestroy - returns true, if object is virtual base. + bool isVbaseToDestroy(uintptr_t Vbase) const { + return (Vbase & 0x1) != 0; + } + /// isDirectNonVBaseToDestroy - returns true, if object is direct non-virtual + /// base. + bool isDirectNonVBaseToDestroy(uintptr_t DrctNonVbase) const { + return (DrctNonVbase & 0x2) != 0; + } + /// isAnyBaseToDestroy - returns true, if object is any base (virtual or + /// direct non-virtual) + bool isAnyBaseToDestroy(uintptr_t AnyBase) const { + return (AnyBase & 0x3) != 0; + } + /// isMemberToDestroy - returns true if object is a non-static data member. + bool isMemberToDestroy(uintptr_t Member) const { + return (Member & 0x3) == 0; + } + /// getAnyBaseClassToDestroy - Get the type for the given base class object. + Type *getAnyBaseClassToDestroy(uintptr_t Base) const { + if (isAnyBaseToDestroy(Base)) + return reinterpret_cast(Base & ~0x03); + return 0; + } + /// getMemberToDestroy - Get the member for the given object. + FieldDecl *getMemberToDestroy(uintptr_t Member) { + if (isMemberToDestroy(Member)) + return reinterpret_cast(Member); + return 0; + } + /// getVbaseClassToDestroy - Get the virtual base. + Type *getVbaseClassToDestroy(uintptr_t Vbase) const { + if (isVbaseToDestroy(Vbase)) + return reinterpret_cast(Vbase & ~0x01); + return 0; + } + /// getDirectNonVBaseClassToDestroy - Get the virtual base. + Type *getDirectNonVBaseClassToDestroy(uintptr_t Base) const { + if (isDirectNonVBaseToDestroy(Base)) + return reinterpret_cast(Base & ~0x02); + return 0; + } + + /// computeBaseOrMembersToDestroy - Compute information in current + /// destructor decl's AST of bases and non-static data members which will be + /// implicitly destroyed. We are storing the destruction in the order that + /// they should occur (which is the reverse of construction order). + void computeBaseOrMembersToDestroy(ASTContext &C); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 1f6780e1fe..23c5428ef6 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1233,7 +1233,7 @@ public: MemInitTy **MemInits, unsigned NumMemInits){ } - virtual void ActOnDefaultCDtorInitializers(DeclPtrTy CDtorDecl) {} + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {} /// ActOnFinishCXXMemberSpecification - Invoked after all member declarators /// are parsed but *before* parsing of inline method definitions. diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 78c351035a..2f8a1ebd7e 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -480,13 +480,25 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, } void -CXXDestructorDecl::setBaseOrMemberDestructions(ASTContext &C) { +CXXDestructorDecl::Destroy(ASTContext& C) { + C.Deallocate(BaseOrMemberDestructions); + CXXMethodDecl::Destroy(C); +} + +void +CXXDestructorDecl::computeBaseOrMembersToDestroy(ASTContext &C) { CXXRecordDecl *ClassDecl = cast(getDeclContext()); - llvm::SmallVector AllToDestruct; + llvm::SmallVector AllToDestruct; + for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - CXXBaseOrMemberInitializer *Member = - new CXXBaseOrMemberInitializer(VBase->getType(), 0, 0,SourceLocation()); + // Skip over virtual bases which have trivial destructors. + CXXRecordDecl *BaseClassDecl + = cast(VBase->getType()->getAsRecordType()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + uintptr_t Member = + reinterpret_cast(VBase->getType().getTypePtr()) | 0x1; AllToDestruct.push_back(Member); } for (CXXRecordDecl::base_class_iterator Base = @@ -494,10 +506,17 @@ CXXDestructorDecl::setBaseOrMemberDestructions(ASTContext &C) { E = ClassDecl->bases_end(); Base != E; ++Base) { if (Base->isVirtual()) continue; - CXXBaseOrMemberInitializer *Member = - new CXXBaseOrMemberInitializer(Base->getType(), 0, 0, SourceLocation()); + // Skip over virtual bases which have trivial destructors. + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAsRecordType()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + + uintptr_t Member = + reinterpret_cast(Base->getType().getTypePtr()) | 0x2; AllToDestruct.push_back(Member); } + // non-static data members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { @@ -506,8 +525,12 @@ CXXDestructorDecl::setBaseOrMemberDestructions(ASTContext &C) { FieldType = AT->getElementType(); if (FieldType->getAsRecordType()) { - CXXBaseOrMemberInitializer *Member = - new CXXBaseOrMemberInitializer((*Field), 0, 0, SourceLocation()); + // Skip over virtual bases which have trivial destructors. + CXXRecordDecl *BaseClassDecl + = cast(FieldType->getAsRecordType()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + uintptr_t Member = reinterpret_cast(*Field); AllToDestruct.push_back(Member); } } @@ -515,8 +538,7 @@ CXXDestructorDecl::setBaseOrMemberDestructions(ASTContext &C) { unsigned NumDestructions = AllToDestruct.size(); if (NumDestructions > 0) { NumBaseOrMemberDestructions = NumDestructions; - BaseOrMemberDestructions = - new (C) CXXBaseOrMemberInitializer*[NumDestructions]; + BaseOrMemberDestructions = new (C) uintptr_t [NumDestructions]; // Insert in reverse order. for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx) BaseOrMemberDestructions[i++] = AllToDestruct[Idx]; diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 84ae72977e..fcc623ec78 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -376,25 +376,25 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } else if (CXXDestructorDecl *DDecl = dyn_cast(D)) { if (DDecl->getNumBaseOrMemberDestructions() > 0) { - // FIXME. This is strictly for visualization of destructor's AST for - // how base/members are destructed. It has no other validity. + // List order of base/member destruction for visualization purposes. assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list"); - Proto += " : "; - for (CXXDestructorDecl::destr_const_iterator B = DDecl->destr_begin(), - E = DDecl->destr_end(); + Proto += "/* : "; + for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(), + *E = DDecl->destr_end(); B != E; ++B) { - CXXBaseOrMemberInitializer * BMInitializer = (*B); + uintptr_t BaseOrMember = (*B); if (B != DDecl->destr_begin()) Proto += ", "; - if (BMInitializer->isMemberInitializer()) { - FieldDecl *FD = BMInitializer->getMember(); + if (DDecl->isMemberToDestroy(BaseOrMember)) { + FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember); Proto += "~"; Proto += FD->getNameAsString(); } else // FIXME. skip dependent types for now. if (const RecordType *RT = - BMInitializer->getBaseClass()->getAsRecordType()) { + DDecl->getAnyBaseClassToDestroy(BaseOrMember) + ->getAsRecordType()) { const CXXRecordDecl *BaseDecl = cast(RT->getDecl()); Proto += "~"; @@ -402,6 +402,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } Proto += "()"; } + Proto += " */"; } } else diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 3bb9c3eb9c..613e0e33f7 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -172,7 +172,7 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { if (Tok.is(tok::colon)) ParseConstructorInitializer(LM.D); else - Actions.ActOnDefaultCDtorInitializers(LM.D); + Actions.ActOnDefaultCtorInitializers(LM.D); // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'?? ParseFunctionStatementBody(LM.D); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e7b0f33732..3260444240 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -666,7 +666,7 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, if (Tok.is(tok::colon)) ParseConstructorInitializer(Res); else - Actions.ActOnDefaultCDtorInitializers(Res); + Actions.ActOnDefaultCtorInitializers(Res); return ParseFunctionStatementBody(Res); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 47938dcd41..f13ebd3eb3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1463,7 +1463,7 @@ public: SourceLocation MemberLoc, IdentifierInfo &Member, DeclPtrTy ImplDecl); - virtual void ActOnDefaultCDtorInitializers(DeclPtrTy CDtorDecl); + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 989e08ee9d..4674327e6c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3282,12 +3282,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Verify that that gotos and switch cases don't jump into scopes illegally. if (CurFunctionNeedsScopeChecking) DiagnoseInvalidJumps(Body); - - // C++ constructors that have function-try-blocks can't have return statements - // in the handlers of that block. (C++ [except.handle]p14) Verify this. + + // C++ constructors that have function-try-blocks can't have return + // statements in the handlers of that block. (C++ [except.handle]p14) + // Verify this. if (isa(dcl) && isa(Body)) DiagnoseReturnInConstructorExceptionHandler(cast(Body)); - + + if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) + Destructor->computeBaseOrMembersToDestroy(Context); return D; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index cb62debfe9..1dcac3fc9e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -918,7 +918,7 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, } } -void Sema::ActOnDefaultCDtorInitializers(DeclPtrTy CDtorDecl) { +void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { if (!CDtorDecl) return; @@ -926,10 +926,6 @@ void Sema::ActOnDefaultCDtorInitializers(DeclPtrTy CDtorDecl) { = dyn_cast(CDtorDecl.getAs())) Constructor->setBaseOrMemberInitializers(Context, (CXXBaseOrMemberInitializer **)0, 0); - else - if (CXXDestructorDecl *Destructor - = dyn_cast(CDtorDecl.getAs())) - Destructor->setBaseOrMemberDestructions(Context); } namespace {