Skip to content

Commit

Permalink
Rework the AST for the initializer of a delegating constructor, so
Browse files Browse the repository at this point in the history
that it retains source location information for the type. Aside from
general goodness (being able to walk the types described in that
information), we now have a proper representation for dependent
delegating constructors. Fixes PR10457 (for real).


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143410 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
DougGregor committed Nov 1, 2011
1 parent d8c4551 commit 76852c2
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 70 deletions.
43 changes: 19 additions & 24 deletions include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1445,11 +1445,10 @@ class CXXMethodDecl : public FunctionDecl {
/// };
/// @endcode
class CXXCtorInitializer {
/// \brief Either the base class name (stored as a TypeSourceInfo*), an normal
/// field (FieldDecl), anonymous field (IndirectFieldDecl*), or target
/// constructor (CXXConstructorDecl*) being initialized.
llvm::PointerUnion4<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *,
CXXConstructorDecl *>
/// \brief Either the base class name/delegating constructor type (stored as
/// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field
/// (IndirectFieldDecl*) being initialized.
llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *>
Initializee;

/// \brief The source location for the field name or, for a base initializer
Expand All @@ -1470,6 +1469,10 @@ class CXXCtorInitializer {
/// RParenLoc - Location of the right paren of the ctor-initializer.
SourceLocation RParenLoc;

/// \brief If the initializee is a type, whether that type makes this
/// a delegating initialization.
bool IsDelegating : 1;

/// IsVirtual - If the initializer is a base initializer, this keeps track
/// of whether the base is virtual or not.
bool IsVirtual : 1;
Expand All @@ -1483,7 +1486,7 @@ class CXXCtorInitializer {
/// original sources, counting from 0; otherwise, if IsWritten is false,
/// it stores the number of array index variables stored after this
/// object in memory.
unsigned SourceOrderOrNumArrayIndices : 14;
unsigned SourceOrderOrNumArrayIndices : 13;

CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
Expand All @@ -1510,8 +1513,8 @@ class CXXCtorInitializer {

/// CXXCtorInitializer - Creates a new delegating Initializer.
explicit
CXXCtorInitializer(ASTContext &Context, SourceLocation D, SourceLocation L,
CXXConstructorDecl *Target, Expr *Init, SourceLocation R);
CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo,
SourceLocation L, Expr *Init, SourceLocation R);

/// \brief Creates a new member initializer that optionally contains
/// array indices used to describe an elementwise initialization.
Expand All @@ -1522,7 +1525,9 @@ class CXXCtorInitializer {

/// isBaseInitializer - Returns true when this initializer is
/// initializing a base class.
bool isBaseInitializer() const { return Initializee.is<TypeSourceInfo*>(); }
bool isBaseInitializer() const {
return Initializee.is<TypeSourceInfo*>() && !IsDelegating;
}

/// isMemberInitializer - Returns true when this initializer is
/// initializing a non-static data member.
Expand All @@ -1546,7 +1551,7 @@ class CXXCtorInitializer {
/// isDelegatingInitializer - Returns true when this initializer is creating
/// a delegating constructor.
bool isDelegatingInitializer() const {
return Initializee.is<CXXConstructorDecl *>();
return Initializee.is<TypeSourceInfo*>() && IsDelegating;
}

/// \brief Determine whether this initializer is a pack expansion.
Expand Down Expand Up @@ -1576,8 +1581,9 @@ class CXXCtorInitializer {
return IsVirtual;
}

/// \brief Returns the declarator information for a base class initializer.
TypeSourceInfo *getBaseClassInfo() const {
/// \brief Returns the declarator information for a base class or delegating
/// initializer.
TypeSourceInfo *getTypeSourceInfo() const {
return Initializee.dyn_cast<TypeSourceInfo *>();
}

Expand Down Expand Up @@ -1606,13 +1612,6 @@ class CXXCtorInitializer {
return 0;
}

CXXConstructorDecl *getTargetConstructor() const {
if (isDelegatingInitializer())
return Initializee.get<CXXConstructorDecl*>();
else
return 0;
}

SourceLocation getMemberLocation() const {
return MemberOrEllipsisLocation;
}
Expand Down Expand Up @@ -1821,11 +1820,7 @@ class CXXConstructorDecl : public CXXMethodDecl {

/// getTargetConstructor - When this constructor delegates to
/// another, retrieve the target
CXXConstructorDecl *getTargetConstructor() const {
assert(isDelegatingConstructor() &&
"A non-delegating constructor has no target");
return CtorInitializers[0]->getTargetConstructor();
}
CXXConstructorDecl *getTargetConstructor() const;

/// isDefaultConstructor - Whether this constructor is a default
/// constructor (C++ [class.ctor]p5), which can be used to
Expand Down
4 changes: 3 additions & 1 deletion include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,9 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments(
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
CXXCtorInitializer *Init) {
// FIXME: recurse on TypeLoc of the base initializer if isBaseInitializer()?
if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));

if (Init->isWritten())
TRY_TO(TraverseStmt(Init->getInit()));
return true;
Expand Down
1 change: 0 additions & 1 deletion include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3518,7 +3518,6 @@ class Sema {

MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo,
const MultiInitializer &Args,
SourceLocation BaseLoc,
CXXRecordDecl *ClassDecl);

bool SetDelegatingInitializer(CXXConstructorDecl *Constructor,
Expand Down
33 changes: 23 additions & 10 deletions lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
Expand Down Expand Up @@ -1299,8 +1300,8 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
SourceLocation R,
SourceLocation EllipsisLoc)
: Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init),
LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false),
SourceOrderOrNumArrayIndices(0)
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}

Expand All @@ -1310,7 +1311,7 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
SourceLocation L, Expr *Init,
SourceLocation R)
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
LParenLoc(L), RParenLoc(R), IsVirtual(false),
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}
Expand All @@ -1321,17 +1322,17 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
SourceLocation L, Expr *Init,
SourceLocation R)
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
LParenLoc(L), RParenLoc(R), IsVirtual(false),
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}

CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
SourceLocation D, SourceLocation L,
CXXConstructorDecl *Target, Expr *Init,
TypeSourceInfo *TInfo,
SourceLocation L, Expr *Init,
SourceLocation R)
: Initializee(Target), MemberOrEllipsisLocation(D), Init(Init),
LParenLoc(L), RParenLoc(R), IsVirtual(false),
: Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init),
LParenLoc(L), RParenLoc(R), IsDelegating(true), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}
Expand Down Expand Up @@ -1380,13 +1381,16 @@ const Type *CXXCtorInitializer::getBaseClass() const {
}

SourceLocation CXXCtorInitializer::getSourceLocation() const {
if (isAnyMemberInitializer() || isDelegatingInitializer())
if (isAnyMemberInitializer())
return getMemberLocation();

if (isInClassMemberInitializer())
return getAnyMember()->getLocation();

return getBaseClassLoc().getLocalSourceRange().getBegin();
if (TypeSourceInfo *TSInfo = Initializee.get<TypeSourceInfo*>())
return TSInfo->getTypeLoc().getLocalSourceRange().getBegin();

return SourceLocation();
}

SourceRange CXXCtorInitializer::getSourceRange() const {
Expand Down Expand Up @@ -1421,6 +1425,15 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
isConstexpr);
}

CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
assert(isDelegatingConstructor() && "Not a delegating constructor!");
Expr *E = (*init_begin())->getInit()->IgnoreImplicit();
if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(E))
return Construct->getConstructor();

return 0;
}

bool CXXConstructorDecl::isDefaultConstructor() const {
// C++ [class.ctor]p5:
// A default constructor for a class X is a constructor of class
Expand Down
17 changes: 7 additions & 10 deletions lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2125,13 +2125,12 @@ Sema::BuildMemberInitializer(ValueDecl *Member,
MemInitResult
Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
const MultiInitializer &Args,
SourceLocation NameLoc,
CXXRecordDecl *ClassDecl) {
SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!LangOpts.CPlusPlus0x)
return Diag(Loc, diag::err_delegating_ctor)
return Diag(NameLoc, diag::err_delegating_ctor)
<< TInfo->getTypeLoc().getLocalSourceRange();
Diag(Loc, diag::warn_cxx98_compat_delegating_ctor);
Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor);

// Initialize the object.
InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation(
Expand All @@ -2158,9 +2157,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
if (DelegationInit.isInvalid())
return true;

assert(!CurContext->isDependentContext());
return new (Context) CXXCtorInitializer(Context, Loc, Args.getStartLoc(),
Constructor,
return new (Context) CXXCtorInitializer(Context, TInfo, Args.getStartLoc(),
DelegationInit.takeAs<Expr>(),
Args.getEndLoc());
}
Expand Down Expand Up @@ -2210,7 +2207,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (!Dependent) {
if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
BaseType))
return BuildDelegatingInitializer(BaseTInfo, Args, BaseLoc, ClassDecl);
return BuildDelegatingInitializer(BaseTInfo, Args, ClassDecl);

FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
VirtualBaseSpec);
Expand Down Expand Up @@ -3000,12 +2997,12 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
if (PrevInit->isAnyMemberInitializer())
D << 0 << PrevInit->getAnyMember()->getDeclName();
else
D << 1 << PrevInit->getBaseClassInfo()->getType();
D << 1 << PrevInit->getTypeSourceInfo()->getType();

if (Init->isAnyMemberInitializer())
D << 0 << Init->getAnyMember()->getDeclName();
else
D << 1 << Init->getBaseClassInfo()->getType();
D << 1 << Init->getTypeSourceInfo()->getType();

// Move back to the initializer's location in the ideal list.
for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex)
Expand Down
25 changes: 15 additions & 10 deletions lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2744,7 +2744,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,

if (Init->isPackExpansion()) {
// This is a pack expansion. We should expand it now.
TypeLoc BaseTL = Init->getBaseClassInfo()->getTypeLoc();
TypeLoc BaseTL = Init->getTypeSourceInfo()->getTypeLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
bool ShouldExpand = false;
Expand Down Expand Up @@ -2774,7 +2774,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
}

// Instantiate the base type.
TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
TypeSourceInfo *BaseTInfo = SubstType(Init->getTypeSourceInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
Expand Down Expand Up @@ -2809,20 +2809,25 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
}

MemInitResult NewInit;
if (Init->isBaseInitializer()) {
TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!BaseTInfo) {
if (Init->isDelegatingInitializer() || Init->isBaseInitializer()) {
TypeSourceInfo *TInfo = SubstType(Init->getTypeSourceInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!TInfo) {
AnyErrors = true;
New->setInvalidDecl();
continue;
}

MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, MultiInit,
New->getParent(), EllipsisLoc);

if (Init->isBaseInitializer())
NewInit = BuildBaseInitializer(TInfo->getType(), TInfo, MultiInit,
New->getParent(), EllipsisLoc);
else
NewInit = BuildDelegatingInitializer(TInfo, MultiInit,
cast<CXXRecordDecl>(CurContext->getParent()));
} else if (Init->isMemberInitializer()) {
FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
Expand Down
19 changes: 9 additions & 10 deletions lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5152,21 +5152,20 @@ ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record,
CtorInitializers
= new (Context) CXXCtorInitializer*[NumInitializers];
for (unsigned i=0; i != NumInitializers; ++i) {
TypeSourceInfo *BaseClassInfo = 0;
TypeSourceInfo *TInfo = 0;
bool IsBaseVirtual = false;
FieldDecl *Member = 0;
IndirectFieldDecl *IndirectMember = 0;
CXXConstructorDecl *Target = 0;

CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
switch (Type) {
case CTOR_INITIALIZER_BASE:
BaseClassInfo = GetTypeSourceInfo(F, Record, Idx);
case CTOR_INITIALIZER_BASE:
TInfo = GetTypeSourceInfo(F, Record, Idx);
IsBaseVirtual = Record[Idx++];
break;

case CTOR_INITIALIZER_DELEGATING:
Target = ReadDeclAs<CXXConstructorDecl>(F, Record, Idx);
case CTOR_INITIALIZER_DELEGATING:
TInfo = GetTypeSourceInfo(F, Record, Idx);
break;

case CTOR_INITIALIZER_MEMBER:
Expand Down Expand Up @@ -5196,12 +5195,12 @@ ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record,

CXXCtorInitializer *BOMInit;
if (Type == CTOR_INITIALIZER_BASE) {
BOMInit = new (Context) CXXCtorInitializer(Context, BaseClassInfo, IsBaseVirtual,
BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual,
LParenLoc, Init, RParenLoc,
MemberOrEllipsisLoc);
} else if (Type == CTOR_INITIALIZER_DELEGATING) {
BOMInit = new (Context) CXXCtorInitializer(Context, MemberOrEllipsisLoc, LParenLoc,
Target, Init, RParenLoc);
BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc,
Init, RParenLoc);
} else if (IsWritten) {
if (Member)
BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
Expand Down
4 changes: 2 additions & 2 deletions lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3881,11 +3881,11 @@ void ASTWriter::AddCXXCtorInitializers(

if (Init->isBaseInitializer()) {
Record.push_back(CTOR_INITIALIZER_BASE);
AddTypeSourceInfo(Init->getBaseClassInfo(), Record);
AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
Record.push_back(Init->isBaseVirtual());
} else if (Init->isDelegatingInitializer()) {
Record.push_back(CTOR_INITIALIZER_DELEGATING);
AddDeclRef(Init->getTargetConstructor(), Record);
AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
} else if (Init->isMemberInitializer()){
Record.push_back(CTOR_INITIALIZER_MEMBER);
AddDeclRef(Init->getMember(), Record);
Expand Down
13 changes: 13 additions & 0 deletions test/SemaTemplate/delegating-constructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,17 @@ namespace PR10457 {
void f() {
string s("hello");
}

struct Foo {
Foo(int) { }


template <typename T>
Foo(T, int i) : Foo(i) { }
};

void test_Foo()
{
Foo f(1, 1);
}
}
Loading

0 comments on commit 76852c2

Please sign in to comment.