diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.h | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 478 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 86 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.h | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 43 |
5 files changed, 385 insertions, 249 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 86dbff30378..6f1ab14778d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1911,7 +1911,8 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 130bf4dbdf9..f23f702d054 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1195,10 +1195,6 @@ 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. - 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 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, 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; + + // Initialize the member. + InitializedEntity MemberEntity = + InitializedEntity::InitializeMember(Member, 0); + InitializationKind Kind = + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc); + + InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - // FIXME: Perform direct initialization of the member. + 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 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, 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(); - - // 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(); - } - - 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(); - } + 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)); + + // 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, BaseTInfo, + LParenLoc, + BaseInit.takeAs<Expr>(), + RParenLoc); } + + if (!BaseType->isRecordType()) + return Diag(BaseLoc, diag::err_base_init_does_not_name_class) + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. - ExprTemporaries.clear(); + // 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; - return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C, - LParenLoc, (Expr **)Args, - NumArgs, RParenLoc); + // 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 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, 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 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, 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 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = 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 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, 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 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, /// 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 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SetBaseOrMemberInitializers(Constructor, reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits), - NumMemInits, false); + NumMemInits, false, AnyErrors); if (Constructor->isDependentContext()) return; @@ -1860,7 +1880,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { 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 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, = 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 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, "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 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, << CXXDestructor << Context.getTagDeclType(ClassDecl); Destructor->setInvalidDecl(); + CurContext = PreviousContext; + return; } + CurContext = PreviousContext; Destructor->setUsed(); } @@ -3750,6 +3780,9 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, 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 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, } if (!err) MethodDecl->setUsed(); + + CurContext = PreviousContext; } CXXMethodDecl * @@ -3835,6 +3870,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, 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 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } } 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 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, } 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::OwningExprResult 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/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index b0dee9c6917..5269167df2c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2562,7 +2562,18 @@ static void TryConstructorInitialization(Sema &S, 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 @@ static void TryDefaultInitialization(Sema &S, // 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 @@ InitializationSequence::Perform(Sema &S, 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 @@ bool InitializationSequence::Diagnose(Sema &S, 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 @@ bool InitializationSequence::Diagnose(Sema &S, 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 @@ bool InitializationSequence::Diagnose(Sema &S, } 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/clang/lib/Sema/SemaInit.h b/clang/lib/Sema/SemaInit.h index 0b72fd4532d..001ba91d546 100644 --- a/clang/lib/Sema/SemaInit.h +++ b/clang/lib/Sema/SemaInit.h @@ -66,7 +66,6 @@ public: /// \brief The entity being initialized is an element of a vector. /// or vector. EK_VectorElement - }; private: @@ -95,8 +94,8 @@ private: /// 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 @@ public: /// 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/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a2f1f63ed8a..d526962323d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1830,7 +1830,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, 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 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, 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 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, 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 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, 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 |