Improve source location information for C++ member initializers in a

constructor, by keeping the DeclaratorInfo* rather than just the type
and a single location.

llvm-svn: 90355
This commit is contained in:
Douglas Gregor 2009-12-02 22:36:29 +00:00
parent a3b825edd1
commit c8c44b5d67
6 changed files with 189 additions and 112 deletions

View File

@ -888,11 +888,12 @@ 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<DeclaratorInfo *, FieldDecl *> BaseOrMember;
/// \brief The source location for the field name.
SourceLocation MemberLocation;
/// Args - The arguments used to initialize the base or member.
Stmt **Args;
@ -918,8 +919,8 @@ class CXXBaseOrMemberInitializer {
/// and AnonUnionMember holds field decl for au_i1.
llvm::PointerUnion<CXXConstructorDecl *, FieldDecl *> 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,38 +953,27 @@ 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<void*>(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<DeclaratorInfo*>(); }
/// isMemberInitializer - Returns true when this initializer is
/// initializing a non-static data member.
bool isMemberInitializer() const { return (BaseOrMember & 0x1) == 0; }
bool isMemberInitializer() const { return BaseOrMember.is<FieldDecl*>(); }
/// 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<Type*>(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;
/// 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<const Type*>(BaseOrMember & ~0x01);
else
return 0;
/// 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<DeclaratorInfo *>();
}
/// getMember - If this is a member initializer, returns the
@ -987,15 +981,26 @@ public:
/// initialized. Otherwise, returns NULL.
FieldDecl *getMember() {
if (isMemberInitializer())
return reinterpret_cast<FieldDecl *>(BaseOrMember);
return BaseOrMember.get<FieldDecl*>();
else
return 0;
}
void setMember(FieldDecl * anonUnionField) {
BaseOrMember = reinterpret_cast<uintptr_t>(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<FieldDecl *>();
}
@ -1007,7 +1012,7 @@ public:
return CtorOrAnonUnion.dyn_cast<CXXConstructorDecl *>();
}
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.

View File

@ -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<uintptr_t>(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<uintptr_t>(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<DeclaratorInfo*>()->getTypeLoc();
else
return TypeLoc();
}
Type *CXXBaseOrMemberInitializer::getBaseClass() {
if (isBaseInitializer())
return BaseOrMember.get<DeclaratorInfo*>()->getType().getTypePtr();
else
return 0;
}
const Type *CXXBaseOrMemberInitializer::getBaseClass() const {
if (isBaseInitializer())
return BaseOrMember.get<DeclaratorInfo*>()->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 *

View File

@ -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);

View File

@ -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<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->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<Expr>(),
CtorArgs.size(), Ctor,
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialDeclaratorInfo(VBase->getType(),
SourceLocation()),
Ctor,
SourceLocation(),
CtorArgs.takeAs<Expr>(),
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<Expr>(),
CtorArgs.size(), Ctor,
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialDeclaratorInfo(Base->getType(),
SourceLocation()),
Ctor,
SourceLocation(),
CtorArgs.takeAs<Expr>(),
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<Expr>(),
CtorArgs.size(), Ctor,
new (Context) CXXBaseOrMemberInitializer(Context,
*Field, SourceLocation(),
Ctor,
SourceLocation(),
CtorArgs.takeAs<Expr>(),
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;

View File

View File

@ -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());
DeclaratorInfo *BaseDInfo = SubstType(Init->getBaseClassInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!BaseDInfo) {
New->setInvalidDecl();
continue;
}
NewInit = BuildBaseInitializer(BaseType,
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());
}