Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94952 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 86dbff3..6f1ab14 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1911,7 +1911,8 @@
QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg Exprs,
- bool RequiresZeroInit = false);
+ bool RequiresZeroInit = false,
+ bool BaseInitialization = false);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
@@ -1920,7 +1921,8 @@
CXXConstructorDecl *Constructor,
bool Elidable,
MultiExprArg Exprs,
- bool RequiresZeroInit = false);
+ bool RequiresZeroInit = false,
+ bool BaseInitialization = false);
OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
QualType writtenTy,
@@ -2282,9 +2284,10 @@
CXXRecordDecl *ClassDecl);
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor);
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ bool IsImplicitConstructor,
+ bool AnyErrors);
/// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl,
/// mark all its non-trivial member and base destructor declarations
@@ -2316,7 +2319,8 @@
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits);
+ MemInitTy **MemInits, unsigned NumMemInits,
+ bool AnyErrors);
void CheckCompletedCXXClass(CXXRecordDecl *Record);
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 130bf4d..f23f702 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1195,10 +1195,6 @@
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.
- ExprTemporaries.clear();
-
// Diagnose value-uses of fields to initialize themselves, e.g.
// foo(foo)
// where foo is not also a parameter to the constructor.
@@ -1220,65 +1216,80 @@
for (unsigned i = 0; i < NumArgs; i++)
HasDependentArg |= Args[i]->isTypeDependent();
- CXXConstructorDecl *C = 0;
QualType FieldType = Member->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- if (FieldType->isDependentType()) {
- // Can't check init for dependent type.
- } else if (FieldType->isRecordType()) {
- // Member is a record (struct/union/class), so pass the initializer
- // arguments down to the record's constructor.
- if (!HasDependentArg) {
- C = PerformInitializationByConstructor(FieldType,
- MultiExprArg(*this,
- (void**)Args,
- NumArgs),
- IdLoc,
- SourceRange(IdLoc, RParenLoc),
- Member->getDeclName(),
- InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc),
- ConstructorArgs);
-
- if (C) {
- // Take over the constructor arguments as our own.
- NumArgs = ConstructorArgs.size();
- Args = (Expr **)ConstructorArgs.take();
- }
- }
- } else if (NumArgs != 1 && NumArgs != 0) {
- // The member type is not a record type (or an array of record
- // types), so it can be only be default- or copy-initialized.
- return Diag(IdLoc, diag::err_mem_initializer_mismatch)
- << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
- } else if (!HasDependentArg) {
- Expr *NewExp;
- if (NumArgs == 0) {
- if (FieldType->isReferenceType()) {
- Diag(IdLoc, diag::err_null_intialized_reference_member)
- << Member->getDeclName();
- return Diag(Member->getLocation(), diag::note_declared_at);
- }
- NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc);
- NumArgs = 1;
- }
- else
- NewExp = (Expr*)Args[0];
- if (!Member->isInvalidDecl() &&
- PerformCopyInitialization(NewExp, FieldType, AA_Passing))
- return true;
- Args[0] = NewExp;
+ if (FieldType->isDependentType() || HasDependentArg) {
+ // Can't check initialization for a member of dependent type or when
+ // any of the arguments are type-dependent expressions.
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+
+ // Erase any temporaries within this evaluation context; we're not
+ // going to track them in the AST, since we'll be rebuilding the
+ // ASTs during template instantiation.
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+
}
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
+ if (Member->isInvalidDecl())
+ return true;
- // FIXME: Perform direct initialization of the member.
+ // Initialize the member.
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(Member, 0);
+ InitializationKind Kind =
+ InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc);
+
+ InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs);
+
+ OwningExprResult MemberInit =
+ InitSeq.Perform(*this, MemberEntity, Kind,
+ MultiExprArg(*this, (void**)Args, NumArgs), 0);
+ if (MemberInit.isInvalid())
+ return true;
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid())
+ return true;
+
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the member
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext()) {
+ // Bump the reference count of all of the arguments.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Retain();
+
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+ }
+
return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
- C, LParenLoc, (Expr **)Args,
- NumArgs, RParenLoc);
+ LParenLoc,
+ MemberInit.takeAs<Expr>(),
+ RParenLoc);
}
Sema::MemInitResult
@@ -1291,76 +1302,118 @@
HasDependentArg |= Args[i]->isTypeDependent();
SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin();
- if (!BaseType->isDependentType()) {
- if (!BaseType->isRecordType())
- return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+ if (BaseType->isDependentType() || HasDependentArg) {
+ // Can't check initialization for a base of dependent type or when
+ // any of the arguments are type-dependent expressions.
+ OwningExprResult BaseInit
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
- // C++ [class.base.init]p2:
- // [...] Unless the mem-initializer-id names a nonstatic data
- // member of the constructor’s class or a direct or virtual base
- // of that class, the mem-initializer is ill-formed. A
- // mem-initializer-list can initialize a base class using any
- // name that denotes that base class type.
+ // Erase any temporaries within this evaluation context; we're not
+ // going to track them in the AST, since we'll be rebuilding the
+ // ASTs during template instantiation.
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
- // Check for direct and virtual base classes.
- const CXXBaseSpecifier *DirectBaseSpec = 0;
- const CXXBaseSpecifier *VirtualBaseSpec = 0;
- FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
- VirtualBaseSpec);
-
- // C++ [base.class.init]p2:
- // If a mem-initializer-id is ambiguous because it designates both
- // a direct non-virtual base class and an inherited virtual base
- // class, the mem-initializer is ill-formed.
- if (DirectBaseSpec && VirtualBaseSpec)
- return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
- << BaseType << BaseTInfo->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(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
- << BaseTInfo->getTypeLoc().getSourceRange();
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ BaseInit.takeAs<Expr>(),
+ RParenLoc);
}
-
- CXXConstructorDecl *C = 0;
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- if (!BaseType->isDependentType() && !HasDependentArg) {
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(BaseType).getUnqualifiedType());
-
- C = PerformInitializationByConstructor(BaseType,
- MultiExprArg(*this,
- (void**)Args, NumArgs),
- BaseLoc,
- SourceRange(BaseLoc, RParenLoc),
- Name,
- InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc),
- ConstructorArgs);
- if (C) {
- // Take over the constructor arguments as our own.
- NumArgs = ConstructorArgs.size();
- Args = (Expr **)ConstructorArgs.take();
- }
- }
-
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
- return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C,
- LParenLoc, (Expr **)Args,
- NumArgs, RParenLoc);
+ if (!BaseType->isRecordType())
+ return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+
+ // C++ [class.base.init]p2:
+ // [...] Unless the mem-initializer-id names a nonstatic data
+ // member of the constructor’s class or a direct or virtual base
+ // of that class, the mem-initializer is ill-formed. A
+ // mem-initializer-list can initialize a base class using any
+ // name that denotes that base class type.
+
+ // Check for direct and virtual base classes.
+ const CXXBaseSpecifier *DirectBaseSpec = 0;
+ const CXXBaseSpecifier *VirtualBaseSpec = 0;
+ FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+ VirtualBaseSpec);
+
+ // C++ [base.class.init]p2:
+ // If a mem-initializer-id is ambiguous because it designates both
+ // a direct non-virtual base class and an inherited virtual base
+ // class, the mem-initializer is ill-formed.
+ if (DirectBaseSpec && VirtualBaseSpec)
+ return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
+ << BaseType << BaseTInfo->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(BaseLoc, diag::err_not_direct_base_or_virtual)
+ << BaseType << ClassDecl->getNameAsCString()
+ << BaseTInfo->getTypeLoc().getSourceRange();
+
+ CXXBaseSpecifier *BaseSpec
+ = const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
+ if (!BaseSpec)
+ BaseSpec = const_cast<CXXBaseSpecifier *>(VirtualBaseSpec);
+
+ // Initialize the base.
+ InitializedEntity BaseEntity =
+ InitializedEntity::InitializeBase(Context, BaseSpec);
+ InitializationKind Kind =
+ InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc);
+
+ InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs);
+
+ OwningExprResult BaseInit =
+ InitSeq.Perform(*this, BaseEntity, Kind,
+ MultiExprArg(*this, (void**)Args, NumArgs), 0);
+ if (BaseInit.isInvalid())
+ return true;
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid())
+ return true;
+
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the base
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext()) {
+ // Bump the reference count of all of the arguments.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Retain();
+
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+ }
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ BaseInit.takeAs<Expr>(),
+ RParenLoc);
}
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor) {
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ bool IsImplicitConstructor,
+ bool AnyErrors) {
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
@@ -1403,6 +1456,8 @@
AllToInit.push_back(Member);
}
} else {
+ llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
+
// Push virtual bases before others.
for (CXXRecordDecl::base_class_iterator VBase =
ClassDecl->vbases_begin(),
@@ -1412,44 +1467,34 @@
if (CXXBaseOrMemberInitializer *Value
= AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
- }
- else {
- CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
- assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null");
- CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 0 << VBase->getType();
- Diag(VBaseDecl->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(VBaseDecl);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, VBase);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
HadError = true;
continue;
}
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+ // Don't attach synthesized base initializers in a dependent
+ // context; they'll be checked again at template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
-
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // 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 =
+ CXXBaseOrMemberInitializer *CXXBaseInit =
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialTypeSourceInfo(VBase->getType(),
SourceLocation()),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ BaseInit.takeAs<Expr>(),
SourceLocation());
- AllToInit.push_back(Member);
+ AllToInit.push_back(CXXBaseInit);
}
}
@@ -1466,43 +1511,34 @@
= AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
}
- else {
- CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null");
- CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 0 << Base->getType();
- Diag(BaseDecl->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(BaseDecl);
+ else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, Base);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
HadError = true;
continue;
}
-
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+
+ // Don't attach synthesized base initializers in a dependent
+ // context; they'll be regenerated at template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
-
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // 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 =
+ CXXBaseOrMemberInitializer *CXXBaseInit =
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialTypeSourceInfo(Base->getType(),
SourceLocation()),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ BaseInit.takeAs<Expr>(),
SourceLocation());
- AllToInit.push_back(Member);
+ AllToInit.push_back(CXXBaseInit);
}
}
}
@@ -1535,66 +1571,49 @@
continue;
}
- if ((*Field)->getType()->isDependentType())
+ if ((*Field)->getType()->isDependentType() || AnyErrors)
continue;
QualType FT = Context.getBaseElementType((*Field)->getType());
- if (const RecordType* RT = FT->getAs<RecordType>()) {
- CXXConstructorDecl *Ctor =
- cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 1 << (*Field)->getDeclName();
- Diag(Field->getLocation(), diag::note_field_decl);
- Diag(RT->getDecl()->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(RT->getDecl());
+ if (FT->getAs<RecordType>()) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeMember(*Field);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid()) {
HadError = true;
continue;
}
-
- if (FT.isConstQualified() && Ctor->isTrivial()) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 1 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- HadError = true;
- }
-
- // Don't create initializers for trivial constructors, since they don't
- // actually need to be run.
- if (Ctor->isTrivial())
- continue;
-
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+
+ // Don't attach synthesized member initializers in a dependent
+ // context; they'll be regenerated a template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
new (Context) CXXBaseOrMemberInitializer(Context,
*Field, SourceLocation(),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ MemberInit.takeAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
}
else if (FT->isReferenceType()) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 0 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
}
else if (FT.isConstQualified()) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
@@ -1659,7 +1678,8 @@
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits) {
+ MemInitTy **MemInits, unsigned NumMemInits,
+ bool AnyErrors) {
if (!ConstructorDecl)
return;
@@ -1709,7 +1729,7 @@
SetBaseOrMemberInitializers(Constructor,
reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits, false);
+ NumMemInits, false, AnyErrors);
if (Constructor->isDependentContext())
return;
@@ -1860,7 +1880,7 @@
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
- SetBaseOrMemberInitializers(Constructor, 0, 0, false);
+ SetBaseOrMemberInitializers(Constructor, 0, 0, false, false);
}
namespace {
@@ -3673,13 +3693,16 @@
= cast<CXXRecordDecl>(Constructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) {
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Constructor;
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
}
+ CurContext = PreviousContext;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3688,6 +3711,10 @@
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
+
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Destructor;
+
// C++ [class.dtor] p5
// Before the implicitly-declared default destructor for a class is
// implicitly defined, all the implicitly-declared default destructors
@@ -3734,8 +3761,11 @@
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
Destructor->setInvalidDecl();
+ CurContext = PreviousContext;
+
return;
}
+ CurContext = PreviousContext;
Destructor->setUsed();
}
@@ -3750,6 +3780,9 @@
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+ DeclContext *PreviousContext = CurContext;
+ CurContext = MethodDecl;
+
// C++[class.copy] p12
// Before the implicitly-declared copy assignment operator for a class is
// implicitly defined, all implicitly-declared copy assignment operators
@@ -3793,6 +3826,8 @@
}
if (!err)
MethodDecl->setUsed();
+
+ CurContext = PreviousContext;
}
CXXMethodDecl *
@@ -3835,6 +3870,10 @@
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
+
+ DeclContext *PreviousContext = CurContext;
+ CurContext = CopyConstructor;
+
// C++ [class.copy] p209
// Before the implicitly-declared copy constructor for a class is
// implicitly defined, all the implicitly-declared copy constructors
@@ -3863,13 +3902,16 @@
}
}
CopyConstructor->setUsed();
+
+ CurContext = PreviousContext;
}
Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
- bool RequiresZeroInit) {
+ bool RequiresZeroInit,
+ bool BaseInitialization) {
bool Elidable = false;
// C++ [class.copy]p15:
@@ -3902,7 +3944,8 @@
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs), RequiresZeroInit);
+ Elidable, move(ExprArgs), RequiresZeroInit,
+ BaseInitialization);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3911,14 +3954,15 @@
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
- bool RequiresZeroInit) {
+ bool RequiresZeroInit,
+ bool BaseInitialization) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
- RequiresZeroInit));
+ RequiresZeroInit, BaseInitialization));
}
Sema::OwningExprResult
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index b0dee9c..5269167 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2562,7 +2562,18 @@
Result);
return;
}
-
+
+ // C++0x [dcl.init]p6:
+ // If a program calls for the default initialization of an object
+ // of a const-qualified type T, T shall be a class type with a
+ // user-provided default constructor.
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ Entity.getType().isConstQualified() &&
+ cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
+
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
if (Kind.getKind() == InitializationKind::IK_Copy) {
@@ -2635,9 +2646,6 @@
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
if (DestType->isRecordType()) {
- // FIXME: If a program calls for the default initialization of an object of
- // a const-qualified type T, T shall be a class type with a user-provided
- // default constructor.
return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType,
Sequence);
}
@@ -3408,7 +3416,8 @@
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
move_arg(ConstructorArgs),
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ Entity.getKind() == InitializedEntity::EK_Base);
if (CurInit.isInvalid())
return S.ExprError();
@@ -3488,8 +3497,13 @@
QualType DestType = Entity.getType();
switch (Failure) {
case FK_TooManyInitsForReference:
- S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
- << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
+ // FIXME: Customize for the initialized entity?
+ if (NumArgs == 0)
+ S.Diag(Kind.getLocation(), diag::err_reference_without_init)
+ << DestType.getNonReferenceType();
+ else // FIXME: diagnostic below could be better!
+ S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
+ << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
break;
case FK_ArrayNeedsInitList:
@@ -3634,6 +3648,45 @@
break;
case OR_No_Viable_Function:
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ (Entity.getKind() == InitializedEntity::EK_Base ||
+ Entity.getKind() == InitializedEntity::EK_Member) &&
+ isa<CXXConstructorDecl>(S.CurContext)) {
+ // This is implicit default initialization of a member or
+ // base within a constructor. If no viable function was
+ // found, notify the user that she needs to explicitly
+ // initialize this base/member.
+ CXXConstructorDecl *Constructor
+ = cast<CXXConstructorDecl>(S.CurContext);
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*base=*/0
+ << Entity.getType();
+
+ RecordDecl *BaseDecl
+ = Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
+ ->getDecl();
+ S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
+ << S.Context.getTagDeclType(BaseDecl);
+ } else {
+ S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*member=*/1
+ << Entity.getName();
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_field_decl);
+
+ if (const RecordType *Record
+ = Entity.getType()->getAs<RecordType>())
+ S.Diag(Record->getDecl()->getLocation(),
+ diag::note_previous_decl)
+ << S.Context.getTagDeclType(Record->getDecl());
+ }
+ break;
+ }
+
S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange;
S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates,
@@ -3664,8 +3717,23 @@
}
case FK_DefaultInitOfConst:
- S.Diag(Kind.getLocation(), diag::err_default_init_const)
- << DestType;
+ if (Entity.getKind() == InitializedEntity::EK_Member &&
+ isa<CXXConstructorDecl>(S.CurContext)) {
+ // This is implicit default-initialization of a const member in
+ // a constructor. Complain that it needs to be explicitly
+ // initialized.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
+ S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*const=*/1
+ << Entity.getName();
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl)
+ << Entity.getName();
+ } else {
+ S.Diag(Kind.getLocation(), diag::err_default_init_const)
+ << DestType << (bool)DestType->getAs<RecordType>();
+ }
break;
}
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 0b72fd4..001ba91 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -66,7 +66,6 @@
/// \brief The entity being initialized is an element of a vector.
/// or vector.
EK_VectorElement
-
};
private:
@@ -95,8 +94,8 @@
/// base class.
CXXBaseSpecifier *Base;
- /// \brief When Kind = EK_ArrayOrVectorElement, the index of the
- /// array or vector element being initialized.
+ /// \brief When Kind = EK_ArrayElement or EK_VectorElement, the
+ /// index of the array or vector element being initialized.
unsigned Index;
};
@@ -201,6 +200,12 @@
/// initialized.
DeclaratorDecl *getDecl() const;
+ /// \brief Retrieve the base specifier.
+ CXXBaseSpecifier *getBaseSpecifier() const {
+ assert(getKind() == EK_Base && "Not a base specifier");
+ return Base;
+ }
+
/// \brief Determine the location of the 'return' keyword when initializing
/// the result of a function call.
SourceLocation getReturnLoc() const {
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a2f1f63..d526962 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1830,7 +1830,8 @@
const MultiLevelTemplateArgumentList &TemplateArgs) {
llvm::SmallVector<MemInitTy*, 4> NewInits;
-
+ bool AnyErrors = false;
+
// Instantiate all the initializers.
for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
InitsEnd = Tmpl->init_end();
@@ -1838,26 +1839,38 @@
CXXBaseOrMemberInitializer *Init = *Inits;
ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this);
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
// Instantiate all the arguments.
- for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end();
- Args != ArgsEnd; ++Args) {
- OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs);
-
- if (NewArg.isInvalid())
- New->setInvalidDecl();
- else
- NewArgs.push_back(NewArg.takeAs<Expr>());
+ Expr *InitE = Init->getInit();
+ if (!InitE) {
+ // Nothing to instantiate;
+ } else if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(InitE)) {
+ if (InstantiateInitializationArguments(*this, ParenList->getExprs(),
+ ParenList->getNumExprs(),
+ TemplateArgs, CommaLocs,
+ NewArgs)) {
+ AnyErrors = true;
+ continue;
+ }
+ } else {
+ OwningExprResult InitArg = SubstExpr(InitE, TemplateArgs);
+ if (InitArg.isInvalid()) {
+ AnyErrors = true;
+ continue;
+ }
+
+ NewArgs.push_back(InitArg.release());
}
-
+
MemInitResult NewInit;
-
if (Init->isBaseInitializer()) {
TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!BaseTInfo) {
+ AnyErrors = true;
New->setInvalidDecl();
continue;
}
@@ -1885,9 +1898,10 @@
Init->getRParenLoc());
}
- if (NewInit.isInvalid())
+ if (NewInit.isInvalid()) {
+ AnyErrors = true;
New->setInvalidDecl();
- else {
+ } else {
// FIXME: It would be nice if ASTOwningVector had a release function.
NewArgs.take();
@@ -1899,7 +1913,8 @@
ActOnMemInitializers(DeclPtrTy::make(New),
/*FIXME: ColonLoc */
SourceLocation(),
- NewInits.data(), NewInits.size());
+ NewInits.data(), NewInits.size(),
+ AnyErrors);
}
// TODO: this could be templated if the various decl types used the