diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:12:48 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:12:48 +0000 |
commit | 8aaf5818a64e9f7687798852af5945b053c68a54 (patch) | |
tree | d6a70c3518b8dea8be7062438d7e8676820ed17f /lib/Sema/SemaDeclCXX.cpp | |
parent | 71438373cd57f0d5d8c93bb5cf690844a0fbc9d0 (diff) | |
download | FreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.zip FreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.tar.gz |
Update clang to r103004.
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 2088 |
1 files changed, 1111 insertions, 977 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 39e3739..6259b85a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -16,12 +16,13 @@ #include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" -#include "clang/AST/StmtVisitor.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Template.h" #include "clang/Basic/PartialDiagnostic.h" @@ -297,13 +298,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { << OldParam->getDefaultArgRange(); Invalid = true; } else if (OldParam->hasDefaultArg()) { - // Merge the old default argument into the new parameter + // Merge the old default argument into the new parameter. + // It's important to use getInit() here; getDefaultArg() + // strips off any top-level CXXExprWithTemporaries. NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( OldParam->getUninstantiatedDefaultArg()); else - NewParam->setDefaultArg(OldParam->getDefaultArg()); + NewParam->setDefaultArg(OldParam->getInit()); } else if (NewParam->hasDefaultArg()) { if (New->getDescribedFunctionTemplate()) { // Paragraph 4, quoted above, only applies to non-template functions. @@ -710,6 +713,29 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { return DerivedRD->isDerivedFrom(BaseRD, Paths); } +void Sema::BuildBasePathArray(const CXXBasePaths &Paths, + CXXBaseSpecifierArray &BasePathArray) { + assert(BasePathArray.empty() && "Base path array must be empty!"); + assert(Paths.isRecordingPaths() && "Must record paths!"); + + const CXXBasePath &Path = Paths.front(); + + // We first go backward and check if we have a virtual base. + // FIXME: It would be better if CXXBasePath had the base specifier for + // the nearest virtual base. + unsigned Start = 0; + for (unsigned I = Path.size(); I != 0; --I) { + if (Path[I - 1].Base->isVirtual()) { + Start = I - 1; + break; + } + } + + // Now add all bases. + for (unsigned I = Start, E = Path.size(); I != E; ++I) + BasePathArray.push_back(Path[I].Base); +} + /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and @@ -723,7 +749,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, - DeclarationName Name) { + DeclarationName Name, + CXXBaseSpecifierArray *BasePath) { // First, determine whether the path from Derived to Base is // ambiguous. This is slightly more expensive than checking whether // the Derived to Base conversion exists, because here we need to @@ -736,17 +763,23 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { - if (!InaccessibleBaseID) - return false; - - // Check that the base class can be accessed. - switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), - InaccessibleBaseID)) { - case AR_accessible: return false; - case AR_inaccessible: return true; - case AR_dependent: return false; - case AR_delayed: return false; + if (InaccessibleBaseID) { + // Check that the base class can be accessed. + switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), + InaccessibleBaseID)) { + case AR_inaccessible: + return true; + case AR_accessible: + case AR_dependent: + case AR_delayed: + break; + } } + + // Build a base path if necessary. + if (BasePath) + BuildBasePathArray(Paths, *BasePath); + return false; } // We know that the derived-to-base conversion is ambiguous, and @@ -775,12 +808,14 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, + CXXBaseSpecifierArray *BasePath, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, IgnoreAccess ? 0 : diag::err_upcast_to_inaccessible_base, diag::err_ambiguous_derived_to_base_conv, - Loc, Range, DeclarationName()); + Loc, Range, DeclarationName(), + BasePath); } @@ -1013,7 +1048,7 @@ static bool FindBaseInitializer(Sema &SemaRef, Sema::MemInitResult Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, TypeTy *TemplateTypeTy, SourceLocation IdLoc, @@ -1076,6 +1111,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!TyD) { if (R.isAmbiguous()) return true; + // We don't want access-control diagnostics here. + R.suppressDiagnostics(); + if (SS.isSet() && isDependentScopeSpecifier(SS)) { bool NotUnknownSpecialization = false; DeclContext *DC = computeDeclContext(SS, false); @@ -1085,7 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!NotUnknownSpecialization) { // When the scope specifier can refer to a member of an unknown // specialization, we take it as a type name. - BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(), + BaseType = CheckTypenameType(ETK_None, + (NestedNameSpecifier *)SS.getScopeRep(), *MemberOrBase, SS.getRange()); if (BaseType.isNull()) return true; @@ -1096,7 +1135,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // If no results were found, try to correct typos. if (R.empty() && BaseType.isNull() && - CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) { + CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) && + R.isSingleResult()) { if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { // We have found a non-static data member with a similar @@ -1236,7 +1276,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, QualType FieldType = Member->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); if (FieldType->isDependentType() || HasDependentArg) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. @@ -1334,6 +1373,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, ExprTemporaries.end()); return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + /*IsVirtual=*/false, LParenLoc, BaseInit.takeAs<Expr>(), RParenLoc); @@ -1369,7 +1409,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() + << BaseType << Context.getTypeDeclType(ClassDecl) << BaseTInfo->getTypeLoc().getSourceRange(); CXXBaseSpecifier *BaseSpec @@ -1379,7 +1419,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // Initialize the base. InitializedEntity BaseEntity = - InitializedEntity::InitializeBase(Context, BaseSpec); + InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc); @@ -1414,23 +1454,199 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, RParenLoc)); return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + BaseSpec->isVirtual(), LParenLoc, Init.takeAs<Expr>(), RParenLoc); } return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + BaseSpec->isVirtual(), LParenLoc, BaseInit.takeAs<Expr>(), RParenLoc); } +/// ImplicitInitializerKind - How an implicit base or member initializer should +/// initialize its base or member. +enum ImplicitInitializerKind { + IIK_Default, + IIK_Copy, + IIK_Move +}; + +static bool +BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, + ImplicitInitializerKind ImplicitInitKind, + CXXBaseSpecifier *BaseSpec, + bool IsInheritedVirtualBase, + CXXBaseOrMemberInitializer *&CXXBaseInit) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec, + IsInheritedVirtualBase); + + Sema::OwningExprResult BaseInit(SemaRef); + + switch (ImplicitInitKind) { + case IIK_Default: { + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, 0, 0)); + break; + } + + case IIK_Copy: { + ParmVarDecl *Param = Constructor->getParamDecl(0); + QualType ParamType = Param->getType().getNonReferenceType(); + + Expr *CopyCtorArg = + DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + Constructor->getLocation(), ParamType, 0); + + // Cast to the base class to avoid ambiguities. + QualType ArgTy = + SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), + ParamType.getQualifiers()); + SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, + CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/true, + CXXBaseSpecifierArray(BaseSpec)); + + InitializationKind InitKind + = InitializationKind::CreateDirect(Constructor->getLocation(), + SourceLocation(), SourceLocation()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, + &CopyCtorArg, 1); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, + (void**)&CopyCtorArg, 1)); + break; + } + + case IIK_Move: + assert(false && "Unhandled initializer kind!"); + } + + BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) + return true; + + CXXBaseInit = + new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(), + SourceLocation()), + BaseSpec->isVirtual(), + SourceLocation(), + BaseInit.takeAs<Expr>(), + SourceLocation()); + + return false; +} + +static bool +BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, + ImplicitInitializerKind ImplicitInitKind, + FieldDecl *Field, + CXXBaseOrMemberInitializer *&CXXMemberInit) { + if (ImplicitInitKind == IIK_Copy) { + // FIXME: We should not return early here, but will do so until + // we know how to handle copy initialization of arrays. + CXXMemberInit = 0; + return false; + + ParmVarDecl *Param = Constructor->getParamDecl(0); + QualType ParamType = Param->getType().getNonReferenceType(); + + Expr *MemberExprBase = + DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + SourceLocation(), ParamType, 0); + + + Expr *CopyCtorArg = + MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false, + 0, SourceRange(), Field, + DeclAccessPair::make(Field, Field->getAccess()), + SourceLocation(), 0, + Field->getType().getNonReferenceType()); + + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDirect(Constructor->getLocation(), + SourceLocation(), SourceLocation()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, + &CopyCtorArg, 1); + + Sema::OwningExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0); + if (MemberInit.isInvalid()) + return true; + + CXXMemberInit = 0; + return false; + } + + assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!"); + + QualType FieldBaseElementType = + SemaRef.Context.getBaseElementType(Field->getType()); + + if (FieldBaseElementType->isRecordType()) { + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDefault(Constructor->getLocation()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); + Sema::OwningExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, 0, 0)); + MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + if (MemberInit.isInvalid()) + return true; + + CXXMemberInit = + new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + Field, SourceLocation(), + SourceLocation(), + MemberInit.takeAs<Expr>(), + SourceLocation()); + return false; + } + + if (FieldBaseElementType->isReferenceType()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 0 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } + + if (FieldBaseElementType.isConstQualified()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 1 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } + + // Nothing to initialize. + CXXMemberInit = 0; + return false; +} + bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { - if (Constructor->isDependentContext()) { + if (Constructor->getDeclContext()->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. if (NumInitializers > 0) { @@ -1445,6 +1661,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, return false; } + ImplicitInitializerKind ImplicitInitKind = IIK_Default; + + // FIXME: Handle implicit move constructors. + if (Constructor->isImplicit() && Constructor->isCopyConstructor()) + ImplicitInitKind = IIK_Copy; + // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); @@ -1464,7 +1686,13 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllBaseFields[Member->getMember()] = Member; } - llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit; + // Keep track of the direct virtual bases. + llvm::SmallPtrSet<CXXBaseSpecifier *, 16> DirectVBases; + for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); I != E; ++I) { + if (I->isVirtual()) + DirectVBases.insert(I); + } // Push virtual bases before others. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), @@ -1474,26 +1702,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } 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()) { + bool IsInheritedVirtualBase = !DirectVBases.count(VBase); + CXXBaseOrMemberInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + VBase, IsInheritedVirtualBase, + CXXBaseInit)) { HadError = true; continue; } - - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(VBase->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); + AllToInit.push_back(CXXBaseInit); } } @@ -1508,26 +1725,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } 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()) { + CXXBaseOrMemberInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + Base, /*IsInheritedVirtualBase=*/false, + CXXBaseInit)) { HadError = true; continue; } - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(Base->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); AllToInit.push_back(CXXBaseInit); } } @@ -1560,54 +1765,19 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; } - if ((*Field)->getType()->isDependentType() || AnyErrors) + if (AnyErrors) continue; - QualType FT = Context.getBaseElementType((*Field)->getType()); - 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; - } - - // Don't attach synthesized member initializers in a dependent - // context; they'll be regenerated a template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - - CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Context, - *Field, SourceLocation(), - SourceLocation(), - MemberInit.takeAs<Expr>(), - SourceLocation()); - - AllToInit.push_back(Member); - } - else if (FT->isReferenceType()) { - Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) - << 0 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); - HadError = true; - } - else if (FT.isConstQualified()) { - Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) - << 1 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); + CXXBaseOrMemberInitializer *Member; + if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind, + *Field, Member)) { HadError = true; + continue; } + + // If the member doesn't need to be initialized, it will be null. + if (Member) + AllToInit.push_back(Member); } NumInitializers = AllToInit.size(); @@ -1657,11 +1827,20 @@ static void *GetKeyForMember(ASTContext &Context, if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) Field = Member->getAnonUnionMember(); - // If the field is a member of an anonymous union, we use record decl of the - // union as the key. + // If the field is a member of an anonymous struct or union, our key + // is the anonymous record decl that's a direct child of the class. RecordDecl *RD = Field->getParent(); - if (RD->isAnonymousStructOrUnion() && RD->isUnion()) + if (RD->isAnonymousStructOrUnion()) { + while (true) { + RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext()); + if (Parent->isAnonymousStructOrUnion()) + RD = Parent; + else + break; + } + return static_cast<void *>(RD); + } return static_cast<void *>(Field); } @@ -1669,89 +1848,153 @@ static void *GetKeyForMember(ASTContext &Context, static void DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, const CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **MemInits, - unsigned NumMemInits) { - if (Constructor->isDependentContext()) + CXXBaseOrMemberInitializer **Inits, + unsigned NumInits) { + if (Constructor->getDeclContext()->isDependentContext()) return; - if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) == - Diagnostic::Ignored && - SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) == - Diagnostic::Ignored) + if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order) + == Diagnostic::Ignored) return; - // Also issue warning if order of ctor-initializer list does not match order - // of 1) base class declarations and 2) order of non-static data members. - llvm::SmallVector<const void*, 32> AllBaseOrMembers; + // Build the list of bases and members in the order that they'll + // actually be initialized. The explicit initializers should be in + // this same order but may be missing things. + llvm::SmallVector<const void*, 32> IdealInitKeys; const CXXRecordDecl *ClassDecl = Constructor->getParent(); - // Push virtual bases before others. + // 1. Virtual bases. for (CXXRecordDecl::base_class_const_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) - AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, - VBase->getType())); + IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType())); + // 2. Non-virtual bases. for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - // Virtuals are alread in the virtual base list and are constructed - // first. if (Base->isVirtual()) continue; - AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, - Base->getType())); + IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType())); } + // 3. Direct fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) - AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field)); + IdealInitKeys.push_back(GetKeyForTopLevelField(*Field)); - int Last = AllBaseOrMembers.size(); - int curIndex = 0; - CXXBaseOrMemberInitializer *PrevMember = 0; - for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = MemInits[i]; - void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true); + unsigned NumIdealInits = IdealInitKeys.size(); + unsigned IdealIndex = 0; + + CXXBaseOrMemberInitializer *PrevInit = 0; + for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) { + CXXBaseOrMemberInitializer *Init = Inits[InitIndex]; + void *InitKey = GetKeyForMember(SemaRef.Context, Init, true); - for (; curIndex < Last; curIndex++) - if (MemberInCtorList == AllBaseOrMembers[curIndex]) + // Scan forward to try to find this initializer in the idealized + // initializers list. + for (; IdealIndex != NumIdealInits; ++IdealIndex) + if (InitKey == IdealInitKeys[IdealIndex]) break; - if (curIndex == Last) { - assert(PrevMember && "Member not in member list?!"); - // Initializer as specified in ctor-initializer list is out of order. - // Issue a warning diagnostic. - if (PrevMember->isBaseInitializer()) { - // Diagnostics is for an initialized base class. - Type *BaseClass = PrevMember->getBaseClass(); - SemaRef.Diag(PrevMember->getSourceLocation(), - diag::warn_base_initialized) - << QualType(BaseClass, 0); - } else { - FieldDecl *Field = PrevMember->getMember(); - SemaRef.Diag(PrevMember->getSourceLocation(), - diag::warn_field_initialized) - << Field->getNameAsString(); - } - // Also the note! - if (FieldDecl *Field = Member->getMember()) - SemaRef.Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 0 - << Field->getNameAsString(); - else { - Type *BaseClass = Member->getBaseClass(); - SemaRef.Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 1 - << QualType(BaseClass, 0); - } - for (curIndex = 0; curIndex < Last; curIndex++) - if (MemberInCtorList == AllBaseOrMembers[curIndex]) + + // If we didn't find this initializer, it must be because we + // scanned past it on a previous iteration. That can only + // happen if we're out of order; emit a warning. + if (IdealIndex == NumIdealInits) { + assert(PrevInit && "initializer not found in initializer list"); + + Sema::SemaDiagnosticBuilder D = + SemaRef.Diag(PrevInit->getSourceLocation(), + diag::warn_initializer_out_of_order); + + if (PrevInit->isMemberInitializer()) + D << 0 << PrevInit->getMember()->getDeclName(); + else + D << 1 << PrevInit->getBaseClassInfo()->getType(); + + if (Init->isMemberInitializer()) + D << 0 << Init->getMember()->getDeclName(); + else + D << 1 << Init->getBaseClassInfo()->getType(); + + // Move back to the initializer's location in the ideal list. + for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex) + if (InitKey == IdealInitKeys[IdealIndex]) break; + + assert(IdealIndex != NumIdealInits && + "initializer not found in initializer list"); } - PrevMember = Member; + + PrevInit = Init; } } +namespace { +bool CheckRedundantInit(Sema &S, + CXXBaseOrMemberInitializer *Init, + CXXBaseOrMemberInitializer *&PrevInit) { + if (!PrevInit) { + PrevInit = Init; + return false; + } + + if (FieldDecl *Field = Init->getMember()) + S.Diag(Init->getSourceLocation(), + diag::err_multiple_mem_initialization) + << Field->getDeclName() + << Init->getSourceRange(); + else { + Type *BaseClass = Init->getBaseClass(); + assert(BaseClass && "neither field nor base"); + S.Diag(Init->getSourceLocation(), + diag::err_multiple_base_initialization) + << QualType(BaseClass, 0) + << Init->getSourceRange(); + } + S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer) + << 0 << PrevInit->getSourceRange(); + + return true; +} + +typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry; +typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap; + +bool CheckRedundantUnionInit(Sema &S, + CXXBaseOrMemberInitializer *Init, + RedundantUnionMap &Unions) { + FieldDecl *Field = Init->getMember(); + RecordDecl *Parent = Field->getParent(); + if (!Parent->isAnonymousStructOrUnion()) + return false; + + NamedDecl *Child = Field; + do { + if (Parent->isUnion()) { + UnionEntry &En = Unions[Parent]; + if (En.first && En.first != Child) { + S.Diag(Init->getSourceLocation(), + diag::err_multiple_mem_union_initialization) + << Field->getDeclName() + << Init->getSourceRange(); + S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer) + << 0 << En.second->getSourceRange(); + return true; + } else if (!En.first) { + En.first = Child; + En.second = Init; + } + } + + Child = Parent; + Parent = cast<RecordDecl>(Parent->getDeclContext()); + } while (Parent->isAnonymousStructOrUnion()); + + return false; +} +} + /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, @@ -1772,34 +2015,29 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, CXXBaseOrMemberInitializer **MemInits = reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits); - + + // Mapping for the duplicate initializers check. + // For member initializers, this is keyed with a FieldDecl*. + // For base initializers, this is keyed with a Type*. llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members; + + // Mapping for the inconsistent anonymous-union initializers check. + RedundantUnionMap MemberUnions; + bool HadError = false; for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = MemInits[i]; + CXXBaseOrMemberInitializer *Init = MemInits[i]; - void *KeyToMember = GetKeyForMember(Context, Member); - CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; - if (!PrevMember) { - PrevMember = Member; - continue; - } - if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::error_multiple_mem_initialization) - << 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) - << Member->getSourceRange(); + if (Init->isMemberInitializer()) { + FieldDecl *Field = Init->getMember(); + if (CheckRedundantInit(*this, Init, Members[Field]) || + CheckRedundantUnionInit(*this, Init, MemberUnions)) + HadError = true; + } else { + void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0)); + if (CheckRedundantInit(*this, Init, Members[Key])) + HadError = true; } - Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) - << 0; - HadError = true; } if (HadError) @@ -2060,12 +2298,12 @@ namespace { /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. -void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { +void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { if (!Record || Record->isInvalidDecl()) return; if (!Record->isDependentType()) - AddImplicitlyDeclaredMembersToClass(Record); + AddImplicitlyDeclaredMembersToClass(S, Record); if (Record->isInvalidDecl()) return; @@ -2141,6 +2379,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (Record->isAbstract() && !Record->isInvalidDecl()) (void)AbstractClassUsageDiagnoser(*this, Record); + + // If this is not an aggregate type and has no user-declared constructor, + // complain about any non-static data members of reference or const scalar + // type, since they will never get initializers. + if (!Record->isInvalidDecl() && !Record->isDependentType() && + !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) { + bool Complained = false; + for (RecordDecl::field_iterator F = Record->field_begin(), + FEnd = Record->field_end(); + F != FEnd; ++F) { + if (F->getType()->isReferenceType() || + (F->getType().isConstQualified() && F->getType()->isScalarType())) { + if (!Complained) { + Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst) + << Record->getTagKind() << Record; + Complained = true; + } + + Diag(F->getLocation(), diag::note_refconst_member_not_initialized) + << F->getType()->isReferenceType() + << F->getDeclName(); + } + } + } } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2157,7 +2419,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, (DeclPtrTy*)FieldCollector->getCurFields(), FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); - CheckCompletedCXXClass( + CheckCompletedCXXClass(S, dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>())); } @@ -2166,7 +2428,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, /// constructor, or destructor, to the given C++ class (C++ /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. -void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { +/// +/// The scope, if provided, is the class scope. +void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, + CXXRecordDecl *ClassDecl) { CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); @@ -2197,7 +2462,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { DefaultCon->setAccess(AS_public); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); - ClassDecl->addDecl(DefaultCon); + if (S) + PushOnScopeChains(DefaultCon, S, true); + else + ClassDecl->addDecl(DefaultCon); } if (!ClassDecl->hasUserDeclaredCopyConstructor()) { @@ -2278,9 +2546,13 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ClassDecl->getLocation(), /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); CopyConstructor->setParams(&FromParam, 1); - ClassDecl->addDecl(CopyConstructor); + if (S) + PushOnScopeChains(CopyConstructor, S, true); + else + ClassDecl->addDecl(CopyConstructor); } if (!ClassDecl->hasUserDeclaredCopyAssignment()) { @@ -2354,7 +2626,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { /*FIXME:*/false, false, 0, 0, FunctionType::ExtInfo()), - /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); + /*TInfo=*/0, /*isStatic=*/false, + /*StorageClassAsWritten=*/FunctionDecl::None, + /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); @@ -2363,14 +2637,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassDecl->getLocation(), - /*IdentifierInfo=*/0, + /*Id=*/0, ArgType, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); CopyAssignment->setParams(&FromParam, 1); // Don't call addedAssignmentOperator. There is no way to distinguish an // implicit from an explicit assignment operator. - ClassDecl->addDecl(CopyAssignment); + if (S) + PushOnScopeChains(CopyAssignment, S, true); + else + ClassDecl->addDecl(CopyAssignment); AddOverriddenMethods(ClassDecl, CopyAssignment); } @@ -2394,7 +2672,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Destructor->setAccess(AS_public); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); - ClassDecl->addDecl(Destructor); + if (S) + PushOnScopeChains(Destructor, S, true); + else + ClassDecl->addDecl(Destructor); // This could be uniqued if it ever proves significant. Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); @@ -2591,8 +2872,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { } } - // Notify the class that we've added a constructor. - ClassDecl->addedConstructor(Context, Constructor); + // Notify the class that we've added a constructor. In principle we + // don't need to do this for out-of-line declarations; in practice + // we only instantiate the most recent declaration of a method, so + // we have to call this for everything but friends. + if (!Constructor->getFriendObjectKind()) + ClassDecl->addedConstructor(Context, Constructor); } /// CheckDestructor - Checks a fully-formed destructor for well-formedness, @@ -2737,6 +3022,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, D.setInvalidType(); SC = FunctionDecl::None; } + + QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Conversion functions don't have return types, but the parser will // happily parse something like: @@ -2749,27 +3037,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); } + const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); + // Make sure we don't have any parameters. - if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) { + if (Proto->getNumArgs() > 0) { Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); // Delete the parameters. D.getTypeObject(0).Fun.freeArgs(); D.setInvalidType(); + } else if (Proto->isVariadic()) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); + D.setInvalidType(); } - // Make sure the conversion function isn't variadic. - if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) { - Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); + // Diagnose "&operator bool()" and other such nonsense. This + // is actually a gcc extension which we don't support. + if (Proto->getResultType() != ConvType) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl) + << Proto->getResultType(); D.setInvalidType(); + ConvType = Proto->getResultType(); } // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -2783,14 +3079,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // Rebuild the function type "R" without any parameters (in case any // of the errors above fired) and with the conversion type as the // return type. - const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); - R = Context.getFunctionType(ConvType, 0, 0, false, - Proto->getTypeQuals(), - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Proto->getNumExceptions(), - Proto->exception_begin(), - Proto->getExtInfo()); + if (D.isInvalidType()) { + R = Context.getFunctionType(ConvType, 0, 0, false, + Proto->getTypeQuals(), + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Proto->getNumExceptions(), + Proto->exception_begin(), + Proto->getExtInfo()); + } // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) @@ -2886,7 +3183,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // in that declarative region, it is treated as an original-namespace-name. NamedDecl *PrevDecl - = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, + = LookupSingleName(DeclRegionScope, II, IdentLoc, LookupOrdinaryName, ForRedeclaration); if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { @@ -3013,7 +3310,7 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) { Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList) { @@ -3082,7 +3379,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -3363,7 +3660,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { /// the lookup differently for these declarations. NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, @@ -3438,7 +3735,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (!LookupContext) return D; UsingDecl *UD = cast<UsingDecl>(D); - if (RequireCompleteDeclContext(SS)) { + if (RequireCompleteDeclContext(SS, LookupContext)) { UD->setInvalidDecl(); return UD; } @@ -3700,7 +3997,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { @@ -3709,8 +4006,13 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, LookupParsedName(R, S, &SS); // Check if we have a previous declaration with the same name. - if (NamedDecl *PrevDecl - = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) { + NamedDecl *PrevDecl + = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName, + ForRedeclaration); + if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S)) + PrevDecl = 0; + + if (PrevDecl) { if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { // We already have an alias with the same name that points to the same // namespace, so don't create a new one. @@ -3746,26 +4048,47 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, return DeclPtrTy::make(AliasDecl); } +namespace { + /// \brief Scoped object used to handle the state changes required in Sema + /// to implicitly define the body of a C++ member function; + class ImplicitlyDefinedFunctionScope { + Sema &S; + DeclContext *PreviousContext; + + public: + ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method) + : S(S), PreviousContext(S.CurContext) + { + S.CurContext = Method; + S.PushFunctionScope(); + S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + } + + ~ImplicitlyDefinedFunctionScope() { + S.PopExpressionEvaluationContext(); + S.PopFunctionOrBlockScope(); + S.CurContext = PreviousContext; + } + }; +} + void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor) { assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() && !Constructor->isUsed()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(Constructor->getDeclContext()); + CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); - DeclContext *PreviousContext = CurContext; - CurContext = Constructor; + ImplicitlyDefinedFunctionScope Scope(*this, Constructor); if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) { Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); + << CXXConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); } else { Constructor->setUsed(); } - CurContext = PreviousContext; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, @@ -3775,8 +4098,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); - DeclContext *PreviousContext = CurContext; - CurContext = Destructor; + ImplicitlyDefinedFunctionScope Scope(*this, Destructor); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); @@ -3788,114 +4110,429 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, << CXXDestructor << Context.getTagDeclType(ClassDecl); Destructor->setInvalidDecl(); - CurContext = PreviousContext; - return; } - CurContext = PreviousContext; Destructor->setUsed(); } -void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl) { - assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && - MethodDecl->getOverloadedOperator() == OO_Equal && - !MethodDecl->isUsed()) && - "DefineImplicitOverloadedAssign - call it for implicit assignment op"); +/// \brief Builds a statement that copies the given entity from \p From to +/// \c To. +/// +/// This routine is used to copy the members of a class with an +/// implicitly-declared copy assignment operator. When the entities being +/// copied are arrays, this routine builds for loops to copy them. +/// +/// \param S The Sema object used for type-checking. +/// +/// \param Loc The location where the implicit copy is being generated. +/// +/// \param T The type of the expressions being copied. Both expressions must +/// have this type. +/// +/// \param To The expression we are copying to. +/// +/// \param From The expression we are copying from. +/// +/// \param Depth Internal parameter recording the depth of the recursion. +/// +/// \returns A statement or a loop that copies the expressions. +static Sema::OwningStmtResult +BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, + Sema::OwningExprResult To, Sema::OwningExprResult From, + unsigned Depth = 0) { + typedef Sema::OwningStmtResult OwningStmtResult; + typedef Sema::OwningExprResult OwningExprResult; + + // C++0x [class.copy]p30: + // Each subobject is assigned in the manner appropriate to its type: + // + // - if the subobject is of class type, the copy assignment operator + // for the class is used (as if by explicit qualification; that is, + // ignoring any possible virtual overriding functions in more derived + // classes); + if (const RecordType *RecordTy = T->getAs<RecordType>()) { + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + + // Look for operator=. + DeclarationName Name + = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal); + LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName); + S.LookupQualifiedName(OpLookup, ClassDecl, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = OpLookup.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Create the nested-name-specifier that will be used to qualify the + // reference to operator=; this is required to suppress the virtual + // call mechanism. + CXXScopeSpec SS; + SS.setRange(Loc); + SS.setScopeRep(NestedNameSpecifier::Create(S.Context, 0, false, + T.getTypePtr())); + + // Create the reference to operator=. + OwningExprResult OpEqualRef + = S.BuildMemberReferenceExpr(move(To), T, Loc, /*isArrow=*/false, SS, + /*FirstQualifierInScope=*/0, OpLookup, + /*TemplateArgs=*/0, + /*SuppressQualifierCheck=*/true); + if (OpEqualRef.isInvalid()) + return S.StmtError(); + + // Build the call to the assignment operator. + Expr *FromE = From.takeAs<Expr>(); + OwningExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0, + OpEqualRef.takeAs<Expr>(), + Loc, &FromE, 1, 0, Loc); + if (Call.isInvalid()) + return S.StmtError(); + + return S.Owned(Call.takeAs<Stmt>()); + } + + // - if the subobject is of scalar type, the built-in assignment + // operator is used. + const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T); + if (!ArrayTy) { + OwningExprResult Assignment = S.CreateBuiltinBinOp(Loc, + BinaryOperator::Assign, + To.takeAs<Expr>(), + From.takeAs<Expr>()); + if (Assignment.isInvalid()) + return S.StmtError(); + + return S.Owned(Assignment.takeAs<Stmt>()); + } + + // - if the subobject is an array, each element is assigned, in the + // manner appropriate to the element type; + + // Construct a loop over the array bounds, e.g., + // + // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0) + // + // that will copy each of the array elements. + QualType SizeType = S.Context.getSizeType(); + + // Create the iteration variable. + IdentifierInfo *IterationVarName = 0; + { + llvm::SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "__i" << Depth; + IterationVarName = &S.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, + IterationVarName, SizeType, + S.Context.getTrivialTypeSourceInfo(SizeType, Loc), + VarDecl::None, VarDecl::None); + + // Initialize the iteration variable to zero. + llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0); + IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc)); + + // Create a reference to the iteration variable; we'll use this several + // times throughout. + Expr *IterationVarRef + = S.BuildDeclRefExpr(IterationVar, SizeType, Loc).takeAs<Expr>(); + assert(IterationVarRef && "Reference to invented variable cannot fail!"); + + // Create the DeclStmt that holds the iteration variable. + Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc); + + // Create the comparison against the array bound. + llvm::APInt Upper = ArrayTy->getSize(); + Upper.zextOrTrunc(S.Context.getTypeSize(SizeType)); + OwningExprResult Comparison + = S.Owned(new (S.Context) BinaryOperator(IterationVarRef->Retain(), + new (S.Context) IntegerLiteral(Upper, SizeType, Loc), + BinaryOperator::NE, S.Context.BoolTy, Loc)); + + // Create the pre-increment of the iteration variable. + OwningExprResult Increment + = S.Owned(new (S.Context) UnaryOperator(IterationVarRef->Retain(), + UnaryOperator::PreInc, + SizeType, Loc)); + + // Subscript the "from" and "to" expressions with the iteration variable. + From = S.CreateBuiltinArraySubscriptExpr(move(From), Loc, + S.Owned(IterationVarRef->Retain()), + Loc); + To = S.CreateBuiltinArraySubscriptExpr(move(To), Loc, + S.Owned(IterationVarRef->Retain()), + Loc); + assert(!From.isInvalid() && "Builtin subscripting can't fail!"); + assert(!To.isInvalid() && "Builtin subscripting can't fail!"); + + // Build the copy for an individual element of the array. + OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc, + ArrayTy->getElementType(), + move(To), move(From), Depth+1); + if (Copy.isInvalid()) { + InitStmt->Destroy(S.Context); + return S.StmtError(); + } + + // Construct the loop that copies all elements of this array. + return S.ActOnForStmt(Loc, Loc, S.Owned(InitStmt), + S.MakeFullExpr(Comparison), + Sema::DeclPtrTy(), + S.MakeFullExpr(Increment), + Loc, move(Copy)); +} - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(MethodDecl->getDeclContext()); +void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *CopyAssignOperator) { + assert((CopyAssignOperator->isImplicit() && + CopyAssignOperator->isOverloadedOperator() && + CopyAssignOperator->getOverloadedOperator() == OO_Equal && + !CopyAssignOperator->isUsed()) && + "DefineImplicitCopyAssignment called for wrong function"); + + CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); - DeclContext *PreviousContext = CurContext; - CurContext = MethodDecl; + if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) { + CopyAssignOperator->setInvalidDecl(); + return; + } + + CopyAssignOperator->setUsed(); - // C++[class.copy] p12 - // Before the implicitly-declared copy assignment operator for a class is - // implicitly defined, all implicitly-declared copy assignment operators - // for its direct base classes and its nonstatic data members shall have - // been implicitly defined. - bool err = false; + ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); + + // C++0x [class.copy]p30: + // The implicitly-defined or explicitly-defaulted copy assignment operator + // for a non-union class X performs memberwise copy assignment of its + // subobjects. The direct base classes of X are assigned first, in the + // order of their declaration in the base-specifier-list, and then the + // immediate non-static data members of X are assigned, in the order in + // which they were declared in the class definition. + + // The statements that form the synthesized function body. + ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this); + + // The parameter for the "other" object, which we are copying from. + ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0); + Qualifiers OtherQuals = Other->getType().getQualifiers(); + QualType OtherRefType = Other->getType(); + if (const LValueReferenceType *OtherRef + = OtherRefType->getAs<LValueReferenceType>()) { + OtherRefType = OtherRef->getPointeeType(); + OtherQuals = OtherRefType.getQualifiers(); + } + + // Our location for everything implicitly-generated. + SourceLocation Loc = CopyAssignOperator->getLocation(); + + // Construct a reference to the "other" object. We'll be using this + // throughout the generated ASTs. + Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, Loc).takeAs<Expr>(); + assert(OtherRef && "Reference to parameter cannot fail!"); + + // Construct the "this" pointer. We'll be using this throughout the generated + // ASTs. + Expr *This = ActOnCXXThis(Loc).takeAs<Expr>(); + assert(This && "Reference to this cannot fail!"); + + // Assign base classes. + bool Invalid = false; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (CXXMethodDecl *BaseAssignOpMethod = - getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - BaseClassDecl)) { - CheckDirectMemberAccess(Base->getSourceRange().getBegin(), - BaseAssignOpMethod, - PDiag(diag::err_access_assign_base) - << Base->getType()); - - MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); + // Form the assignment: + // static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other)); + QualType BaseType = Base->getType().getUnqualifiedType(); + CXXRecordDecl *BaseClassDecl = 0; + if (const RecordType *BaseRecordT = BaseType->getAs<RecordType>()) + BaseClassDecl = cast<CXXRecordDecl>(BaseRecordT->getDecl()); + else { + Invalid = true; + continue; + } + + // Construct the "from" expression, which is an implicit cast to the + // appropriately-qualified base type. + Expr *From = OtherRef->Retain(); + ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), + CastExpr::CK_UncheckedDerivedToBase, /*isLvalue=*/true, + CXXBaseSpecifierArray(Base)); + + // Dereference "this". + OwningExprResult To = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, + Owned(This->Retain())); + + // Implicitly cast "this" to the appropriately-qualified base type. + Expr *ToE = To.takeAs<Expr>(); + ImpCastExprToType(ToE, + Context.getCVRQualifiedType(BaseType, + CopyAssignOperator->getTypeQualifiers()), + CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/true, CXXBaseSpecifierArray(Base)); + To = Owned(ToE); + + // Build the copy. + OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, + move(To), Owned(From)); + if (Copy.isInvalid()) { + Invalid = true; + continue; } + + // Success! Record the copy. + Statements.push_back(Copy.takeAs<Expr>()); } + + // \brief Reference to the __builtin_memcpy function. + Expr *BuiltinMemCpyRef = 0; + + // Assign non-static members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (CXXMethodDecl *FieldAssignOpMethod = - getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - FieldClassDecl)) { - CheckDirectMemberAccess(Field->getLocation(), - FieldAssignOpMethod, - PDiag(diag::err_access_assign_field) - << Field->getDeclName() << Field->getType()); - - MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); - } - } else if (FieldType->isReferenceType()) { + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + // Check for members of reference type; we can't copy those. + if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); + << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_first_required_here); - err = true; - } else if (FieldType.isConstQualified()) { + Diag(Loc, diag::note_first_required_here); + Invalid = true; + continue; + } + + // Check for members of const-qualified, non-class type. + QualType BaseType = Context.getBaseElementType(Field->getType()); + if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); + << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_first_required_here); - err = true; + Diag(Loc, diag::note_first_required_here); + Invalid = true; + continue; } + + QualType FieldType = Field->getType().getNonReferenceType(); + + // Build references to the field in the object we're copying from and to. + CXXScopeSpec SS; // Intentionally empty + LookupResult MemberLookup(*this, Field->getDeclName(), Loc, + LookupMemberName); + MemberLookup.addDecl(*Field); + MemberLookup.resolveKind(); + OwningExprResult From = BuildMemberReferenceExpr(Owned(OtherRef->Retain()), + OtherRefType, + Loc, /*IsArrow=*/false, + SS, 0, MemberLookup, 0); + OwningExprResult To = BuildMemberReferenceExpr(Owned(This->Retain()), + This->getType(), + Loc, /*IsArrow=*/true, + SS, 0, MemberLookup, 0); + assert(!From.isInvalid() && "Implicit field reference cannot fail"); + assert(!To.isInvalid() && "Implicit field reference cannot fail"); + + // If the field should be copied with __builtin_memcpy rather than via + // explicit assignments, do so. This optimization only applies for arrays + // of scalars and arrays of class type with trivial copy-assignment + // operators. + if (FieldType->isArrayType() && + (!BaseType->isRecordType() || + cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()) + ->hasTrivialCopyAssignment())) { + // Compute the size of the memory buffer to be copied. + QualType SizeType = Context.getSizeType(); + llvm::APInt Size(Context.getTypeSize(SizeType), + Context.getTypeSizeInChars(BaseType).getQuantity()); + for (const ConstantArrayType *Array + = Context.getAsConstantArrayType(FieldType); + Array; + Array = Context.getAsConstantArrayType(Array->getElementType())) { + llvm::APInt ArraySize = Array->getSize(); + ArraySize.zextOrTrunc(Size.getBitWidth()); + Size *= ArraySize; + } + + // Take the address of the field references for "from" and "to". + From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From)); + To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To)); + + // Create a reference to the __builtin_memcpy builtin function. + if (!BuiltinMemCpyRef) { + LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, + LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>(); + if (!BuiltinMemCpy) { + // Something went horribly wrong earlier, and we will have complained + // about it. + Invalid = true; + continue; + } + + BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, + BuiltinMemCpy->getType(), + Loc, 0).takeAs<Expr>(); + assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); + } + + ASTOwningVector<&ActionBase::DeleteExpr> CallArgs(*this); + CallArgs.push_back(To.takeAs<Expr>()); + CallArgs.push_back(From.takeAs<Expr>()); + CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc)); + llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly + Commas.push_back(Loc); + Commas.push_back(Loc); + OwningExprResult Call = ActOnCallExpr(/*Scope=*/0, + Owned(BuiltinMemCpyRef->Retain()), + Loc, move_arg(CallArgs), + Commas.data(), Loc); + assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); + Statements.push_back(Call.takeAs<Expr>()); + continue; + } + + // Build the copy of this field. + OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, + move(To), move(From)); + if (Copy.isInvalid()) { + Invalid = true; + continue; + } + + // Success! Record the copy. + Statements.push_back(Copy.takeAs<Stmt>()); } - if (!err) - MethodDecl->setUsed(); - CurContext = PreviousContext; -} + if (!Invalid) { + // Add a "return *this;" + OwningExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, + Owned(This->Retain())); + + OwningStmtResult Return = ActOnReturnStmt(Loc, move(ThisObj)); + if (Return.isInvalid()) + Invalid = true; + else { + Statements.push_back(Return.takeAs<Stmt>()); + } + } -CXXMethodDecl * -Sema::getAssignOperatorMethod(SourceLocation CurrentLocation, - ParmVarDecl *ParmDecl, - CXXRecordDecl *ClassDecl) { - QualType LHSType = Context.getTypeDeclType(ClassDecl); - QualType RHSType(LHSType); - // If class's assignment operator argument is const/volatile qualified, - // look for operator = (const/volatile B&). Otherwise, look for - // operator = (B&). - RHSType = Context.getCVRQualifiedType(RHSType, - ParmDecl->getType().getCVRQualifiers()); - ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl, - LHSType, - SourceLocation())); - ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl, - RHSType, - CurrentLocation)); - Expr *Args[2] = { &*LHS, &*RHS }; - OverloadCandidateSet CandidateSet(CurrentLocation); - AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, - CandidateSet); - OverloadCandidateSet::iterator Best; - if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success) - return cast<CXXMethodDecl>(Best->Function); - assert(false && - "getAssignOperatorMethod - copy assignment operator method not found"); - return 0; + if (Invalid) { + CopyAssignOperator->setInvalidDecl(); + return; + } + + OwningStmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + /*isStmtExpr=*/false); + assert(!Body.isInvalid() && "Compound statement creation cannot fail"); + CopyAssignOperator->setBody(Body.takeAs<Stmt>()); } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, @@ -3906,32 +4543,21 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, !CopyConstructor->isUsed()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(CopyConstructor->getDeclContext()); + CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); - DeclContext *PreviousContext = CurContext; - CurContext = CopyConstructor; + ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); - // C++ [class.copy] p209 - // Before the implicitly-declared copy constructor for a class is - // implicitly defined, all the implicitly-declared copy constructors - // for its base class and its non-static data members shall have been - // implicitly defined. - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(Context, TypeQuals)) { - CheckDirectMemberAccess(Base->getSourceRange().getBegin(), - BaseCopyCtor, - PDiag(diag::err_access_copy_base) - << Base->getType()); - - MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); - } + if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + CopyConstructor->setInvalidDecl(); + } else { + CopyConstructor->setUsed(); } + + // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of + // fields, this code below should be removed. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { @@ -3952,9 +4578,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } } } - CopyConstructor->setUsed(); - - CurContext = PreviousContext; } Sema::OwningExprResult @@ -3962,7 +4585,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, bool RequiresZeroInit, - bool BaseInitialization) { + CXXConstructExpr::ConstructionKind ConstructKind) { bool Elidable = false; // C++0x [class.copy]p34: @@ -3984,7 +4607,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, Elidable, move(ExprArgs), RequiresZeroInit, - BaseInitialization); + ConstructKind); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -3994,14 +4617,14 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, bool RequiresZeroInit, - bool BaseInitialization) { + CXXConstructExpr::ConstructionKind ConstructKind) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, - RequiresZeroInit, BaseInitialization)); + RequiresZeroInit, ConstructKind)); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, @@ -4138,113 +4761,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, FinalizeVarWithDestructor(VDecl, Record); } -/// \brief Add the applicable constructor candidates for an initialization -/// by constructor. -static void AddConstructorInitializationCandidates(Sema &SemaRef, - QualType ClassType, - Expr **Args, - unsigned NumArgs, - InitializationKind Kind, - OverloadCandidateSet &CandidateSet) { - // C++ [dcl.init]p14: - // If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the - // class of the destination, constructors are considered. The - // applicable constructors are enumerated (13.3.1.3), and the - // best one is chosen through overload resolution (13.3). The - // constructor so selected is called to initialize the object, - // with the initializer expression(s) as its argument(s). If no - // constructor applies, or the overload resolution is ambiguous, - // the initialization is ill-formed. - const RecordType *ClassRec = ClassType->getAs<RecordType>(); - assert(ClassRec && "Can only initialize a class type here"); - - // FIXME: When we decide not to synthesize the implicitly-declared - // constructors, we'll need to make them appear here. - - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl()); - DeclarationName ConstructorName - = SemaRef.Context.DeclarationNames.getCXXConstructorName( - SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType()); - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); - Con != ConEnd; ++Con) { - DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con); - if (ConstructorTmpl) - Constructor - = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(*Con); - - if ((Kind.getKind() == InitializationKind::IK_Direct) || - (Kind.getKind() == InitializationKind::IK_Value) || - (Kind.getKind() == InitializationKind::IK_Copy && - Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - ((Kind.getKind() == InitializationKind::IK_Default) && - Constructor->isDefaultConstructor())) { - if (ConstructorTmpl) - SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - Args, NumArgs, CandidateSet); - else - SemaRef.AddOverloadCandidate(Constructor, FoundDecl, - Args, NumArgs, CandidateSet); - } - } -} - -/// \brief Attempt to perform initialization by constructor -/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or -/// copy-initialization. -/// -/// This routine determines whether initialization by constructor is possible, -/// but it does not emit any diagnostics in the case where the initialization -/// is ill-formed. -/// -/// \param ClassType the type of the object being initialized, which must have -/// class type. -/// -/// \param Args the arguments provided to initialize the object -/// -/// \param NumArgs the number of arguments provided to initialize the object -/// -/// \param Kind the type of initialization being performed -/// -/// \returns the constructor used to initialize the object, if successful. -/// Otherwise, emits a diagnostic and returns NULL. -CXXConstructorDecl * -Sema::TryInitializationByConstructor(QualType ClassType, - Expr **Args, unsigned NumArgs, - SourceLocation Loc, - InitializationKind Kind) { - // Build the overload candidate set - OverloadCandidateSet CandidateSet(Loc); - AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind, - CandidateSet); - - // Determine whether we found a constructor we can use. - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Loc, Best)) { - case OR_Success: - case OR_Deleted: - // We found a constructor. Return it. - return cast<CXXConstructorDecl>(Best->Function); - - case OR_No_Viable_Function: - case OR_Ambiguous: - // Overload resolution failed. Return nothing. - return 0; - } - - // Silence GCC warning - return 0; -} - /// \brief Given a constructor and the set of arguments provided for the /// constructor, convert the arguments and add any required default arguments /// to form a proper call to this constructor. @@ -4281,472 +4797,6 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, return Invalid; } -/// CompareReferenceRelationship - Compare the two types T1 and T2 to -/// determine whether they are reference-related, -/// reference-compatible, reference-compatible with added -/// qualification, or incompatible, for use in C++ initialization by -/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference -/// type, and the first type (T1) is the pointee type of the reference -/// type being initialized. -Sema::ReferenceCompareResult -Sema::CompareReferenceRelationship(SourceLocation Loc, - QualType OrigT1, QualType OrigT2, - bool& DerivedToBase) { - assert(!OrigT1->isReferenceType() && - "T1 must be the pointee type of the reference type"); - assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); - - QualType T1 = Context.getCanonicalType(OrigT1); - QualType T2 = Context.getCanonicalType(OrigT2); - Qualifiers T1Quals, T2Quals; - QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); - QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); - - // C++ [dcl.init.ref]p4: - // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is - // reference-related to "cv2 T2" if T1 is the same type as T2, or - // T1 is a base class of T2. - if (UnqualT1 == UnqualT2) - DerivedToBase = false; - else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && - !RequireCompleteType(Loc, OrigT2, PDiag()) && - IsDerivedFrom(UnqualT2, UnqualT1)) - DerivedToBase = true; - else - return Ref_Incompatible; - - // At this point, we know that T1 and T2 are reference-related (at - // least). - - // If the type is an array type, promote the element qualifiers to the type - // for comparison. - if (isa<ArrayType>(T1) && T1Quals) - T1 = Context.getQualifiedType(UnqualT1, T1Quals); - if (isa<ArrayType>(T2) && T2Quals) - T2 = Context.getQualifiedType(UnqualT2, T2Quals); - - // C++ [dcl.init.ref]p4: - // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is - // reference-related to T2 and cv1 is the same cv-qualification - // as, or greater cv-qualification than, cv2. For purposes of - // overload resolution, cases for which cv1 is greater - // cv-qualification than cv2 are identified as - // reference-compatible with added qualification (see 13.3.3.2). - if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers()) - return Ref_Compatible; - else if (T1.isMoreQualifiedThan(T2)) - return Ref_Compatible_With_Added_Qualification; - else - return Ref_Related; -} - -/// CheckReferenceInit - Check the initialization of a reference -/// variable with the given initializer (C++ [dcl.init.ref]). Init is -/// the initializer (either a simple initializer or an initializer -/// list), and DeclType is the type of the declaration. When ICS is -/// non-null, this routine will compute the implicit conversion -/// sequence according to C++ [over.ics.ref] and will not produce any -/// diagnostics; when ICS is null, it will emit diagnostics when any -/// errors are found. Either way, a return value of true indicates -/// that there was a failure, a return value of false indicates that -/// the reference initialization succeeded. -/// -/// When @p SuppressUserConversions, user-defined conversions are -/// suppressed. -/// When @p AllowExplicit, we also permit explicit user-defined -/// conversion functions. -/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue. -/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion. -/// This is used when this is called from a C-style cast. -bool -Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, - SourceLocation DeclLoc, - bool SuppressUserConversions, - bool AllowExplicit, bool ForceRValue, - ImplicitConversionSequence *ICS, - bool IgnoreBaseAccess) { - assert(DeclType->isReferenceType() && "Reference init needs a reference"); - - QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); - QualType T2 = Init->getType(); - - // If the initializer is the address of an overloaded function, try - // to resolve the overloaded function. If all goes well, T2 is the - // type of the resulting function. - if (Context.getCanonicalType(T2) == Context.OverloadTy) { - DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, - ICS != 0, Found); - if (Fn) { - // Since we're performing this reference-initialization for - // real, update the initializer with the resulting function. - if (!ICS) { - if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; - - CheckAddressOfMemberAccess(Init, Found); - Init = FixOverloadedFunctionReference(Init, Found, Fn); - } - - T2 = Fn->getType(); - } - } - - // Compute some basic properties of the types and the initializer. - bool isRValRef = DeclType->isRValueReferenceType(); - bool DerivedToBase = false; - Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : - Init->isLvalue(Context); - ReferenceCompareResult RefRelationship - = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); - - // Most paths end in a failed conversion. - if (ICS) { - ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType); - } - - // C++ [dcl.init.ref]p5: - // A reference to type "cv1 T1" is initialized by an expression - // of type "cv2 T2" as follows: - - // -- If the initializer expression - - // Rvalue references cannot bind to lvalues (N2812). - // There is absolutely no situation where they can. In particular, note that - // this is ill-formed, even if B has a user-defined conversion to A&&: - // B b; - // A&& r = b; - if (isRValRef && InitLvalue == Expr::LV_Valid) { - if (!ICS) - Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) - << Init->getSourceRange(); - return true; - } - - bool BindsDirectly = false; - // -- is an lvalue (but is not a bit-field), and "cv1 T1" is - // reference-compatible with "cv2 T2," or - // - // Note that the bit-field check is skipped if we are just computing - // the implicit conversion sequence (C++ [over.best.ics]p2). - if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) && - RefRelationship >= Ref_Compatible_With_Added_Qualification) { - BindsDirectly = true; - - if (ICS) { - // C++ [over.ics.ref]p1: - // When a parameter of reference type binds directly (8.5.3) - // to an argument expression, the implicit conversion sequence - // is the identity conversion, unless the argument expression - // has a type that is a derived class of the parameter type, - // in which case the implicit conversion sequence is a - // derived-to-base Conversion (13.3.3.1). - ICS->setStandard(); - ICS->Standard.First = ICK_Identity; - ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS->Standard.Third = ICK_Identity; - ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.setToType(0, T2); - ICS->Standard.setToType(1, T1); - ICS->Standard.setToType(2, T1); - ICS->Standard.ReferenceBinding = true; - ICS->Standard.DirectBinding = true; - ICS->Standard.RRefBinding = false; - ICS->Standard.CopyConstructor = 0; - - // Nothing more to do: the inaccessibility/ambiguity check for - // derived-to-base conversions is suppressed when we're - // computing the implicit conversion sequence (C++ - // [over.best.ics]p2). - return false; - } else { - // Perform the conversion. - CastExpr::CastKind CK = CastExpr::CK_NoOp; - if (DerivedToBase) - CK = CastExpr::CK_DerivedToBase; - else if(CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true); - } - } - - // -- has a class type (i.e., T2 is a class type) and can be - // implicitly converted to an lvalue of type "cv3 T3," - // where "cv1 T1" is reference-compatible with "cv3 T3" - // 92) (this conversion is selected by enumerating the - // applicable conversion functions (13.3.1.6) and choosing - // the best one through overload resolution (13.3)), - if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && - !RequireCompleteType(DeclLoc, T2, 0)) { - CXXRecordDecl *T2RecordDecl - = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); - - OverloadCandidateSet CandidateSet(DeclLoc); - const UnresolvedSetImpl *Conversions - = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); I != E; ++I) { - NamedDecl *D = *I; - CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - FunctionTemplateDecl *ConvTemplate - = dyn_cast<FunctionTemplateDecl>(D); - CXXConversionDecl *Conv; - if (ConvTemplate) - Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); - else - Conv = cast<CXXConversionDecl>(D); - - // If the conversion function doesn't return a reference type, - // it can't be considered for this conversion. - if (Conv->getConversionType()->isLValueReferenceType() && - (AllowExplicit || !Conv->isExplicit())) { - if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, DeclType, CandidateSet); - else - AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - DeclType, CandidateSet); - } - } - - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, DeclLoc, Best)) { - case OR_Success: - // C++ [over.ics.ref]p1: - // - // [...] If the parameter binds directly to the result of - // applying a conversion function to the argument - // expression, the implicit conversion sequence is a - // user-defined conversion sequence (13.3.3.1.2), with the - // second standard conversion sequence either an identity - // conversion or, if the conversion function returns an - // entity of a type that is a derived class of the parameter - // type, a derived-to-base Conversion. - if (!Best->FinalConversion.DirectBinding) - break; - - // This is a direct binding. - BindsDirectly = true; - - if (ICS) { - ICS->setUserDefined(); - ICS->UserDefined.Before = Best->Conversions[0].Standard; - ICS->UserDefined.After = Best->FinalConversion; - ICS->UserDefined.ConversionFunction = Best->Function; - ICS->UserDefined.EllipsisConversion = false; - assert(ICS->UserDefined.After.ReferenceBinding && - ICS->UserDefined.After.DirectBinding && - "Expected a direct reference binding!"); - return false; - } else { - OwningExprResult InitConversion = - BuildCXXCastArgument(DeclLoc, QualType(), - CastExpr::CK_UserDefinedConversion, - cast<CXXMethodDecl>(Best->Function), - Owned(Init)); - Init = InitConversion.takeAs<Expr>(); - - if (CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion, - /*isLvalue=*/true); - } - break; - - case OR_Ambiguous: - if (ICS) { - ICS->setAmbiguous(); - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); - Cand != CandidateSet.end(); ++Cand) - if (Cand->Viable) - ICS->Ambiguous.addConversion(Cand->Function); - break; - } - Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType() - << Init->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1); - return true; - - case OR_No_Viable_Function: - case OR_Deleted: - // There was no suitable conversion, or we found a deleted - // conversion; continue with other checks. - break; - } - } - - if (BindsDirectly) { - // C++ [dcl.init.ref]p4: - // [...] In all cases where the reference-related or - // reference-compatible relationship of two types is used to - // establish the validity of a reference binding, and T1 is a - // base class of T2, a program that necessitates such a binding - // is ill-formed if T1 is an inaccessible (clause 11) or - // ambiguous (10.2) base class of T2. - // - // Note that we only check this condition when we're allowed to - // complain about errors, because we should not be checking for - // ambiguity (or inaccessibility) unless the reference binding - // actually happens. - if (DerivedToBase) - return CheckDerivedToBaseConversion(T2, T1, DeclLoc, - Init->getSourceRange(), - IgnoreBaseAccess); - else - return false; - } - - // -- Otherwise, the reference shall be to a non-volatile const - // type (i.e., cv1 shall be const), or the reference shall be an - // rvalue reference and the initializer expression shall be an rvalue. - if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { - if (!ICS) - Diag(DeclLoc, diag::err_not_reference_to_const_init) - << T1.isVolatileQualified() - << T1 << int(InitLvalue != Expr::LV_Valid) - << T2 << Init->getSourceRange(); - return true; - } - - // -- If the initializer expression is an rvalue, with T2 a - // class type, and "cv1 T1" is reference-compatible with - // "cv2 T2," the reference is bound in one of the - // following ways (the choice is implementation-defined): - // - // -- The reference is bound to the object represented by - // the rvalue (see 3.10) or to a sub-object within that - // object. - // - // -- A temporary of type "cv1 T2" [sic] is created, and - // a constructor is called to copy the entire rvalue - // object into the temporary. The reference is bound to - // the temporary or to a sub-object within the - // temporary. - // - // The constructor that would be used to make the copy - // shall be callable whether or not the copy is actually - // done. - // - // Note that C++0x [dcl.init.ref]p5 takes away this implementation - // freedom, so we will always take the first option and never build - // a temporary in this case. FIXME: We will, however, have to check - // for the presence of a copy constructor in C++98/03 mode. - if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && - RefRelationship >= Ref_Compatible_With_Added_Qualification) { - if (ICS) { - ICS->setStandard(); - ICS->Standard.First = ICK_Identity; - ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS->Standard.Third = ICK_Identity; - ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.setToType(0, T2); - ICS->Standard.setToType(1, T1); - ICS->Standard.setToType(2, T1); - ICS->Standard.ReferenceBinding = true; - ICS->Standard.DirectBinding = false; - ICS->Standard.RRefBinding = isRValRef; - ICS->Standard.CopyConstructor = 0; - } else { - CastExpr::CastKind CK = CastExpr::CK_NoOp; - if (DerivedToBase) - CK = CastExpr::CK_DerivedToBase; - else if(CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false); - } - return false; - } - - // -- Otherwise, a temporary of type "cv1 T1" is created and - // initialized from the initializer expression using the - // rules for a non-reference copy initialization (8.5). The - // reference is then bound to the temporary. If T1 is - // reference-related to T2, cv1 must be the same - // cv-qualification as, or greater cv-qualification than, - // cv2; otherwise, the program is ill-formed. - if (RefRelationship == Ref_Related) { - // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then - // we would be reference-compatible or reference-compatible with - // added qualification. But that wasn't the case, so the reference - // initialization fails. - if (!ICS) - Diag(DeclLoc, diag::err_reference_init_drops_quals) - << T1 << int(InitLvalue != Expr::LV_Valid) - << T2 << Init->getSourceRange(); - return true; - } - - // If at least one of the types is a class type, the types are not - // related, and we aren't allowed any user conversions, the - // reference binding fails. This case is important for breaking - // recursion, since TryImplicitConversion below will attempt to - // create a temporary through the use of a copy constructor. - if (SuppressUserConversions && RefRelationship == Ref_Incompatible && - (T1->isRecordType() || T2->isRecordType())) { - if (!ICS) - Diag(DeclLoc, diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange(); - return true; - } - - // Actually try to convert the initializer to T1. - if (ICS) { - // C++ [over.ics.ref]p2: - // - // When a parameter of reference type is not bound directly to - // an argument expression, the conversion sequence is the one - // required to convert the argument expression to the - // underlying type of the reference according to - // 13.3.3.1. Conceptually, this conversion sequence corresponds - // to copy-initializing a temporary of the underlying type with - // the argument expression. Any difference in top-level - // cv-qualification is subsumed by the initialization itself - // and does not constitute a conversion. - *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - - // Of course, that's still a reference binding. - if (ICS->isStandard()) { - ICS->Standard.ReferenceBinding = true; - ICS->Standard.RRefBinding = isRValRef; - } else if (ICS->isUserDefined()) { - ICS->UserDefined.After.ReferenceBinding = true; - ICS->UserDefined.After.RRefBinding = isRValRef; - } - return ICS->isBad(); - } else { - ImplicitConversionSequence Conversions; - bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing, - false, false, - Conversions); - if (badConversion) { - if (Conversions.isAmbiguous()) { - Diag(DeclLoc, - diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange(); - for (int j = Conversions.Ambiguous.conversions().size()-1; - j >= 0; j--) { - FunctionDecl *Func = Conversions.Ambiguous.conversions()[j]; - NoteOverloadCandidate(Func); - } - } - else { - if (isRValRef) - Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) - << Init->getSourceRange(); - else - Diag(DeclLoc, diag::err_invalid_initialization) - << DeclType << Init->getType() << Init->getSourceRange(); - } - } - return badConversion; - } -} - static inline bool CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, const FunctionDecl *FnDecl) { @@ -5044,17 +5094,32 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { bool Valid = false; - // FIXME: Check for the one valid template signature - // template <char...> type operator "" name(); - - if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { + // template <char...> type operator "" name() is the only valid template + // signature, and the only valid signature with no parameters. + if (FnDecl->param_size() == 0) { + if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) { + // Must have only one template parameter + TemplateParameterList *Params = TpDecl->getTemplateParameters(); + if (Params->size() == 1) { + NonTypeTemplateParmDecl *PmDecl = + cast<NonTypeTemplateParmDecl>(Params->getParam(0)); + + // The template parameter must be a char parameter pack. + // FIXME: This test will always fail because non-type parameter packs + // have not been implemented. + if (PmDecl && PmDecl->isTemplateParameterPack() && + Context.hasSameType(PmDecl->getType(), Context.CharTy)) + Valid = true; + } + } + } else { // Check the first parameter + FunctionDecl::param_iterator Param = FnDecl->param_begin(); + QualType T = (*Param)->getType(); - // unsigned long long int and long double are allowed, but only - // alone. - // We also allow any character type; their omission seems to be a bug - // in n3000 + // unsigned long long int, long double, and any character type are allowed + // as the only parameters. if (Context.hasSameType(T, Context.UnsignedLongLongTy) || Context.hasSameType(T, Context.LongDoubleTy) || Context.hasSameType(T, Context.CharTy) || @@ -5066,7 +5131,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { goto FinishedParams; } - // Otherwise it must be a pointer to const; let's strip those. + // Otherwise it must be a pointer to const; let's strip those qualifiers. const PointerType *PT = T->getAs<PointerType>(); if (!PT) goto FinishedParams; @@ -5121,13 +5186,12 @@ FinishedParams: Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - const char *Lang, - unsigned StrSize, + llvm::StringRef Lang, SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; - if (strncmp(Lang, "\"C\"", StrSize) == 0) + if (Lang == "\"C\"") Language = LinkageSpecDecl::lang_c; - else if (strncmp(Lang, "\"C++\"", StrSize) == 0) + else if (Lang == "\"C++\"") Language = LinkageSpecDecl::lang_cxx; else { Diag(LangLoc, diag::err_bad_language); @@ -5212,8 +5276,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, Invalid = true; VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, TInfo, VarDecl::None); - + Name, ExDeclType, TInfo, VarDecl::None, + VarDecl::None); + ExDecl->setExceptionVariable(true); + if (!Invalid) { if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) { // C++ [except.handle]p16: @@ -5254,7 +5320,9 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { bool Invalid = D.isInvalidType(); IdentifierInfo *II = D.getIdentifier(); - if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { + if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), + LookupOrdinaryName, + ForRedeclaration)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration. assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl))); @@ -5318,6 +5386,62 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, return DeclPtrTy::make(Decl); } +/// \brief Perform semantic analysis of the given friend type declaration. +/// +/// \returns A friend declaration that. +FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, + TypeSourceInfo *TSInfo) { + assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); + + QualType T = TSInfo->getType(); + SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); + + if (!getLangOptions().CPlusPlus0x) { + // C++03 [class.friend]p2: + // An elaborated-type-specifier shall be used in a friend declaration + // for a class.* + // + // * The class-key of the elaborated-type-specifier is required. + if (!ActiveTemplateInstantiations.empty()) { + // Do not complain about the form of friend template types during + // template instantiation; we will already have complained when the + // template was declared. + } else if (!T->isElaboratedTypeSpecifier()) { + // If we evaluated the type to a record type, suggest putting + // a tag in front. + if (const RecordType *RT = T->getAs<RecordType>()) { + RecordDecl *RD = RT->getDecl(); + + std::string InsertionText = std::string(" ") + RD->getKindName(); + + Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type) + << (unsigned) RD->getTagKind() + << T + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc), + InsertionText); + } else { + Diag(FriendLoc, diag::ext_nonclass_type_friend) + << T + << SourceRange(FriendLoc, TypeRange.getEnd()); + } + } else if (T->getAs<EnumType>()) { + Diag(FriendLoc, diag::ext_enum_friend) + << T + << SourceRange(FriendLoc, TypeRange.getEnd()); + } + } + + // C++0x [class.friend]p3: + // If the type specifier in a friend declaration designates a (possibly + // cv-qualified) class type, that class is declared as a friend; otherwise, + // the friend declaration is ignored. + + // FIXME: C++0x has some syntactic restrictions on friend type declarations + // in [class.friend]p3 that we do not implement. + + return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc); +} + /// Handle a friend type declaration. This works in tandem with /// ActOnTag. /// @@ -5351,6 +5475,9 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (TheDeclarator.isInvalidType()) return DeclPtrTy(); + if (!TSI) + TSI = Context.getTrivialTypeSourceInfo(T, DS.getSourceRange().getBegin()); + // This is definitely an error in C++98. It's probably meant to // be forbidden in C++0x, too, but the specification is just // poorly written. @@ -5370,41 +5497,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, << DS.getSourceRange(); return DeclPtrTy(); } - - // C++ [class.friend]p2: - // An elaborated-type-specifier shall be used in a friend declaration - // for a class.* - // * The class-key of the elaborated-type-specifier is required. - // This is one of the rare places in Clang where it's legitimate to - // ask about the "spelling" of the type. - if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) { - // If we evaluated the type to a record type, suggest putting - // a tag in front. - if (const RecordType *RT = T->getAs<RecordType>()) { - RecordDecl *RD = RT->getDecl(); - - std::string InsertionText = std::string(" ") + RD->getKindName(); - - Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type) - << (unsigned) RD->getTagKind() - << T - << SourceRange(DS.getFriendSpecLoc()) - << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText); - return DeclPtrTy(); - }else { - Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) - << DS.getSourceRange(); - return DeclPtrTy(); - } - } - - // Enum types cannot be friends. - if (T->getAs<EnumType>()) { - Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend) - << SourceRange(DS.getFriendSpecLoc()); - return DeclPtrTy(); - } - + // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . // This is fixed in DR77, which just barely didn't make the C++03 @@ -5417,15 +5510,18 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // friend a member of an arbitrary specialization of your template). Decl *D; - if (TempParams.size()) + if (unsigned NumTempParamLists = TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, - TempParams.size(), + NumTempParamLists, (TemplateParameterList**) TempParams.release(), TSI, DS.getFriendSpecLoc()); else - D = FriendDecl::Create(Context, CurContext, Loc, TSI, - DS.getFriendSpecLoc()); + D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI); + + if (!D) + return DeclPtrTy(); + D->setAccess(AS_public); CurContext->addDecl(D); @@ -5493,11 +5589,11 @@ Sema::ActOnFriendFunctionDecl(Scope *S, LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); if (!ScopeQual.isInvalid() && ScopeQual.isSet()) { - // FIXME: RequireCompleteDeclContext DC = computeDeclContext(ScopeQual); // FIXME: handle dependent contexts if (!DC) return DeclPtrTy(); + if (RequireCompleteDeclContext(ScopeQual, DC)) return DeclPtrTy(); LookupQualifiedName(Previous, DC); @@ -5595,9 +5691,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S, FrD->setAccess(AS_public); CurContext->addDecl(FrD); - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) - FrD->setSpecialization(true); - return DeclPtrTy::make(ND); } @@ -5701,10 +5794,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, // Check if we the conversion from derived to base is valid. if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, - diag::err_covariant_return_inaccessible_base, - diag::err_covariant_return_ambiguous_derived_to_base_conv, - // FIXME: Should this point to the return type? - New->getLocation(), SourceRange(), New->getDeclName())) { + diag::err_covariant_return_inaccessible_base, + diag::err_covariant_return_ambiguous_derived_to_base_conv, + // FIXME: Should this point to the return type? + New->getLocation(), SourceRange(), New->getDeclName(), 0)) { Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } @@ -5830,7 +5923,7 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } -static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) { +static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) { // Ignore dependent types. if (MD->isDependentContext()) return false; @@ -5893,7 +5986,7 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, // We will need to mark all of the virtual members as referenced to build the // vtable. - if (!needsVtable(MD, Context)) + if (!needsVTable(MD, Context)) return; TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); @@ -5944,3 +6037,44 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, MarkVirtualMembersReferenced(Loc, Base); } } + +/// SetIvarInitializers - This routine builds initialization ASTs for the +/// Objective-C implementation whose ivars need be initialized. +void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { + if (!getLangOptions().CPlusPlus) + return; + if (const ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { + llvm::SmallVector<ObjCIvarDecl*, 8> ivars; + CollectIvarsToConstructOrDestruct(OID, ivars); + if (ivars.empty()) + return; + llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; + for (unsigned i = 0; i < ivars.size(); i++) { + FieldDecl *Field = ivars[i]; + CXXBaseOrMemberInitializer *Member; + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDefault(ObjCImplementation->getLocation()); + + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + Sema::OwningExprResult MemberInit = + InitSeq.Perform(*this, InitEntity, InitKind, + Sema::MultiExprArg(*this, 0, 0)); + MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + // Note, MemberInit could actually come back empty if no initialization + // is required (e.g., because it would call a trivial default constructor) + if (!MemberInit.get() || MemberInit.isInvalid()) + continue; + + Member = + new (Context) CXXBaseOrMemberInitializer(Context, + Field, SourceLocation(), + SourceLocation(), + MemberInit.takeAs<Expr>(), + SourceLocation()); + AllToInit.push_back(Member); + } + ObjCImplementation->setIvarInitializers(Context, + AllToInit.data(), AllToInit.size()); + } +} |