From: Douglas Gregor Date: Wed, 2 Dec 2009 22:36:29 +0000 (+0000) Subject: Improve source location information for C++ member initializers in a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=802ab45fea51beff12f386329d4928811a479c6e;p=clang Improve source location information for C++ member initializers in a constructor, by keeping the DeclaratorInfo* rather than just the type and a single location. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90355 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 87a47fec6b..81f85e81a0 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -888,12 +888,13 @@ public: /// }; /// @endcode class CXXBaseOrMemberInitializer { - /// BaseOrMember - This points to the entity being initialized, - /// which is either a base class (a Type) or a non-static data - /// member. When the low bit is 1, it's a base - /// class; when the low bit is 0, it's a member. - uintptr_t BaseOrMember; - + /// \brief Either the base class name (stored as a DeclaratorInfo*) or the + /// field being initialized. + llvm::PointerUnion BaseOrMember; + + /// \brief The source location for the field name. + SourceLocation MemberLocation; + /// Args - The arguments used to initialize the base or member. Stmt **Args; unsigned NumArgs; @@ -918,8 +919,8 @@ class CXXBaseOrMemberInitializer { /// and AnonUnionMember holds field decl for au_i1. llvm::PointerUnion CtorOrAnonUnion; - /// IdLoc - Location of the id in ctor-initializer list. - SourceLocation IdLoc; + /// LParenLoc - Location of the left paren of the ctor-initializer. + SourceLocation LParenLoc; /// RParenLoc - Location of the right paren of the ctor-initializer. SourceLocation RParenLoc; @@ -927,18 +928,22 @@ class CXXBaseOrMemberInitializer { public: /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. explicit - CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R); + CXXBaseOrMemberInitializer(ASTContext &Context, + DeclaratorInfo *DInfo, CXXConstructorDecl *C, + SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R); /// CXXBaseOrMemberInitializer - Creates a new member initializer. explicit - CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R); + CXXBaseOrMemberInitializer(ASTContext &Context, + FieldDecl *Member, SourceLocation MemberLoc, + CXXConstructorDecl *C, SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R); - /// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer. - ~CXXBaseOrMemberInitializer(); + /// \brief Destroy the base or member initializer. + void Destroy(ASTContext &Context); /// arg_iterator - Iterates through the member initialization /// arguments. @@ -948,54 +953,54 @@ public: /// arguments. typedef ConstExprIterator const_arg_iterator; - /// getBaseOrMember - get the generic 'member' representing either the field - /// or a base class. - void* getBaseOrMember() const { return reinterpret_cast(BaseOrMember); } - /// isBaseInitializer - Returns true when this initializer is /// initializing a base class. - bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; } + bool isBaseInitializer() const { return BaseOrMember.is(); } /// isMemberInitializer - Returns true when this initializer is /// initializing a non-static data member. - bool isMemberInitializer() const { return (BaseOrMember & 0x1) == 0; } - - /// getBaseClass - If this is a base class initializer, returns the - /// type used to specify the initializer. The resulting type will be - /// a class type or a typedef of a class type. If this is not a base - /// class initializer, returns NULL. - Type *getBaseClass() { - if (isBaseInitializer()) - return reinterpret_cast(BaseOrMember & ~0x01); - else - return 0; - } + bool isMemberInitializer() const { return BaseOrMember.is(); } - /// getBaseClass - If this is a base class initializer, returns the - /// type used to specify the initializer. The resulting type will be - /// a class type or a typedef of a class type. If this is not a base - /// class initializer, returns NULL. - const Type *getBaseClass() const { - if (isBaseInitializer()) - return reinterpret_cast(BaseOrMember & ~0x01); - else - return 0; - } + /// If this is a base class initializer, returns the type of the + /// base class with location information. Otherwise, returns an NULL + /// type location. + TypeLoc getBaseClassLoc() const; + /// If this is a base class initializer, returns the type of the base class. + /// Otherwise, returns NULL. + const Type *getBaseClass() const; + Type *getBaseClass(); + + /// \brief Returns the declarator information for a base class initializer. + DeclaratorInfo *getBaseClassInfo() const { + return BaseOrMember.dyn_cast(); + } + /// getMember - If this is a member initializer, returns the /// declaration of the non-static data member being /// initialized. Otherwise, returns NULL. FieldDecl *getMember() { if (isMemberInitializer()) - return reinterpret_cast(BaseOrMember); + return BaseOrMember.get(); else return 0; } - void setMember(FieldDecl * anonUnionField) { - BaseOrMember = reinterpret_cast(anonUnionField); + SourceLocation getMemberLocation() const { + return MemberLocation; } + void setMember(FieldDecl *Member) { + assert(isMemberInitializer()); + BaseOrMember = Member; + } + + /// \brief Determine the source location of the initializer. + SourceLocation getSourceLocation() const; + + /// \brief Determine the source range covering the entire initializer. + SourceRange getSourceRange() const; + FieldDecl *getAnonUnionMember() const { return CtorOrAnonUnion.dyn_cast(); } @@ -1007,7 +1012,7 @@ public: return CtorOrAnonUnion.dyn_cast(); } - SourceLocation getSourceLocation() const { return IdLoc; } + SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } /// arg_begin() - Retrieve an iterator to the first initializer argument. diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index c98b3f078b..89ea097a33 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -630,43 +631,76 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { } CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R) - : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { - BaseOrMember = reinterpret_cast(BaseType.getTypePtr()); - assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer"); - BaseOrMember |= 0x01; - +CXXBaseOrMemberInitializer(ASTContext &Context, + DeclaratorInfo *DInfo, CXXConstructorDecl *C, + SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R) + : BaseOrMember(DInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C), + LParenLoc(L), RParenLoc(R) +{ if (NumArgs > 0) { this->NumArgs = NumArgs; - // FIXME. Allocation via Context - this->Args = new Stmt*[NumArgs]; + this->Args = new (Context) Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } - CtorOrAnonUnion = C; } CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R) - : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { - BaseOrMember = reinterpret_cast(Member); - assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); - +CXXBaseOrMemberInitializer(ASTContext &Context, + FieldDecl *Member, SourceLocation MemberLoc, + CXXConstructorDecl *C, SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R) + : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0), + CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R) +{ if (NumArgs > 0) { this->NumArgs = NumArgs; - this->Args = new Stmt*[NumArgs]; + this->Args = new (Context) Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } - CtorOrAnonUnion = C; } -CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { - delete [] Args; +void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Destroy(Context); + Context.Deallocate(Args); + this->~CXXBaseOrMemberInitializer(); +} + +TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const { + if (isBaseInitializer()) + return BaseOrMember.get()->getTypeLoc(); + else + return TypeLoc(); +} + +Type *CXXBaseOrMemberInitializer::getBaseClass() { + if (isBaseInitializer()) + return BaseOrMember.get()->getType().getTypePtr(); + else + return 0; +} + +const Type *CXXBaseOrMemberInitializer::getBaseClass() const { + if (isBaseInitializer()) + return BaseOrMember.get()->getType().getTypePtr(); + else + return 0; +} + +SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const { + if (isMemberInitializer()) + return getMemberLocation(); + + return getBaseClassLoc().getSourceRange().getBegin(); +} + +SourceRange CXXBaseOrMemberInitializer::getSourceRange() const { + return SourceRange(getSourceLocation(), getRParenLoc()); } CXXConstructorDecl * diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 2b48efb495..bd41072d3a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2110,10 +2110,13 @@ public: MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, + SourceLocation LParenLoc, SourceLocation RParenLoc); - MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, + MemInitResult BuildBaseInitializer(QualType BaseType, + DeclaratorInfo *BaseDInfo, + Expr **Args, unsigned NumArgs, + SourceLocation LParenLoc, SourceLocation RParenLoc, CXXRecordDecl *ClassDecl); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 4db769bd91..37681719aa 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -18,6 +18,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" #include "clang/Parse/DeclSpec.h" @@ -977,19 +978,26 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (Member) return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, - RParenLoc); + LParenLoc, RParenLoc); } // It didn't name a member, so see if it names a class. - TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy - : getTypeName(*MemberOrBase, IdLoc, S, &SS); - if (!BaseTy) + QualType BaseType; + + DeclaratorInfo *DInfo = 0; + if (TemplateTypeTy) + BaseType = GetTypeFromParser(TemplateTypeTy, &DInfo); + else + BaseType = QualType::getFromOpaquePtr(getTypeName(*MemberOrBase, IdLoc, + S, &SS)); + if (BaseType.isNull()) return Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc, RParenLoc); - QualType BaseType = GetTypeFromParser(BaseTy); + if (!DInfo) + DInfo = Context.getTrivialDeclaratorInfo(BaseType, IdLoc); - return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc, - RParenLoc, ClassDecl); + return BuildBaseInitializer(BaseType, DInfo, (Expr **)Args, NumArgs, + LParenLoc, RParenLoc, ClassDecl); } /// Checks an initializer expression for use of uninitialized fields, such as @@ -1038,6 +1046,7 @@ static bool InitExprContainsUninitializedFields(const Stmt* S, Sema::MemInitResult Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, + SourceLocation LParenLoc, SourceLocation RParenLoc) { // FIXME: CXXBaseOrMemberInitializer should only contain a single // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. @@ -1119,22 +1128,25 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, ExprTemporaries.clear(); // FIXME: Perform direct initialization of the member. - return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, - NumArgs, C, IdLoc, RParenLoc); + return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, + C, LParenLoc, (Expr **)Args, + NumArgs, RParenLoc); } Sema::MemInitResult -Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, - SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) { +Sema::BuildBaseInitializer(QualType BaseType, DeclaratorInfo *BaseDInfo, + Expr **Args, unsigned NumArgs, + SourceLocation LParenLoc, SourceLocation RParenLoc, + CXXRecordDecl *ClassDecl) { bool HasDependentArg = false; for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); + SourceLocation BaseLoc = BaseDInfo->getTypeLoc().getSourceRange().getBegin(); if (!BaseType->isDependentType()) { if (!BaseType->isRecordType()) - return Diag(IdLoc, diag::err_base_init_does_not_name_class) - << BaseType << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_base_init_does_not_name_class) + << BaseType << BaseDInfo->getTypeLoc().getSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data @@ -1180,16 +1192,16 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, // a direct non-virtual base class and an inherited virtual base // class, the mem-initializer is ill-formed. if (DirectBaseSpec && VirtualBaseSpec) - return Diag(IdLoc, diag::err_base_init_direct_and_virtual) - << BaseType << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) + << BaseType << BaseDInfo->getTypeLoc().getSourceRange(); // C++ [base.class.init]p2: // Unless the mem-initializer-id names a nonstatic data membeer of the // constructor's class ot a direst or virtual base of that class, the // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) - return Diag(IdLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() - << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) + << BaseType << ClassDecl->getNameAsCString() + << BaseDInfo->getTypeLoc().getSourceRange(); } CXXConstructorDecl *C = 0; @@ -1201,7 +1213,8 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, C = PerformInitializationByConstructor(BaseType, MultiExprArg(*this, (void**)Args, NumArgs), - IdLoc, SourceRange(IdLoc, RParenLoc), + BaseLoc, + SourceRange(BaseLoc, RParenLoc), Name, IK_Direct, ConstructorArgs); if (C) { @@ -1215,8 +1228,9 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. ExprTemporaries.clear(); - return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, - NumArgs, C, IdLoc, RParenLoc); + return new (Context) CXXBaseOrMemberInitializer(Context, BaseDInfo, C, + LParenLoc, (Expr **)Args, + NumArgs, RParenLoc); } bool @@ -1278,7 +1292,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, } else { CXXRecordDecl *VBaseDecl = - cast(VBase->getType()->getAs()->getDecl()); + cast(VBase->getType()->getAs()->getDecl()); assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null"); CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); if (!Ctor) { @@ -1299,13 +1313,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, MarkDeclarationReferenced(Constructor->getLocation(), Ctor); // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + // subexpression so we can wrap it in a CXXExprWithTemporaries if + // necessary. + // FIXME: Is there any better source-location information we can give? ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(VBase->getType(), - CtorArgs.takeAs(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialDeclaratorInfo(VBase->getType(), + SourceLocation()), + Ctor, SourceLocation(), + CtorArgs.takeAs(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); } @@ -1347,13 +1366,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, MarkDeclarationReferenced(Constructor->getLocation(), Ctor); // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + // subexpression so we can wrap it in a CXXExprWithTemporaries if + // necessary. + // FIXME: Is there any better source-location information we can give? ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Base->getType(), - CtorArgs.takeAs(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialDeclaratorInfo(Base->getType(), + SourceLocation()), + Ctor, SourceLocation(), + CtorArgs.takeAs(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); } @@ -1428,9 +1452,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + *Field, SourceLocation(), + Ctor, SourceLocation(), + CtorArgs.takeAs(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); @@ -1538,13 +1565,15 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, if (FieldDecl *Field = Member->getMember()) Diag(Member->getSourceLocation(), diag::error_multiple_mem_initialization) - << Field->getNameAsString(); + << Field->getNameAsString() + << Member->getSourceRange(); else { Type *BaseClass = Member->getBaseClass(); assert(BaseClass && "ActOnMemInitializers - neither field or base"); Diag(Member->getSourceLocation(), diag::error_multiple_base_initialization) - << QualType(BaseClass, 0); + << QualType(BaseClass, 0) + << Member->getSourceRange(); } Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) << 0; diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8808bf72db..95725bf44f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1620,14 +1620,19 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, MemInitResult NewInit; if (Init->isBaseInitializer()) { - QualType BaseType(Init->getBaseClass(), 0); - BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(), - New->getDeclName()); - - NewInit = BuildBaseInitializer(BaseType, + DeclaratorInfo *BaseDInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), + New->getDeclName()); + if (!BaseDInfo) { + New->setInvalidDecl(); + continue; + } + + NewInit = BuildBaseInitializer(BaseDInfo->getType(), BaseDInfo, (Expr **)NewArgs.data(), NewArgs.size(), - Init->getSourceLocation(), + Init->getLParenLoc(), Init->getRParenLoc(), New->getParent()); } else if (Init->isMemberInitializer()) { @@ -1643,6 +1648,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), NewArgs.size(), Init->getSourceLocation(), + Init->getLParenLoc(), Init->getRParenLoc()); }