diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp | 1717 |
1 files changed, 822 insertions, 895 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index 66a1121..eeac9b8 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -23,6 +23,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" @@ -127,8 +128,8 @@ namespace { void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method) { - // If we have an MSAny or unknown spec already, don't bother. - if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + // If we have an MSAny spec already, don't bother. + if (!Method || ComputedEST == EST_MSAny) return; const FunctionProtoType *Proto @@ -140,7 +141,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, ExceptionSpecificationType EST = Proto->getExceptionSpecType(); // If this function can throw any exceptions, make a note of that. - if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) { + if (EST == EST_MSAny || EST == EST_None) { ClearExceptions(); ComputedEST = EST; return; @@ -197,7 +198,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, } void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { - if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + if (!E || ComputedEST == EST_MSAny) return; // FIXME: @@ -667,9 +668,9 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, SourceLocation ParamLoc = PD->getLocation(); if (!(*i)->isDependentType() && SemaRef.RequireLiteralType(ParamLoc, *i, - SemaRef.PDiag(diag::err_constexpr_non_literal_param) - << ArgIndex+1 << PD->getSourceRange() - << isa<CXXConstructorDecl>(FD))) + diag::err_constexpr_non_literal_param, + ArgIndex+1, PD->getSourceRange(), + isa<CXXConstructorDecl>(FD))) return false; } return true; @@ -725,7 +726,7 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { QualType RT = NewFD->getResultType(); if (!RT->isDependentType() && RequireLiteralType(NewFD->getLocation(), RT, - PDiag(diag::err_constexpr_non_literal_return))) + diag::err_constexpr_non_literal_return)) return false; } @@ -920,7 +921,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { unsigned Fields = 0; for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++Fields) { - if ((*I)->isAnonymousStructOrUnion()) { + if (I->isAnonymousStructOrUnion()) { AnyAnonStructUnionMembers = true; break; } @@ -1055,8 +1056,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // The class-name in a base-specifier shall not be an incompletely // defined class. if (RequireCompleteType(BaseLoc, BaseType, - PDiag(diag::err_incomplete_base_class) - << SpecifierRange)) { + diag::err_incomplete_base_class, SpecifierRange)) { Class->setInvalidDecl(); return 0; } @@ -1119,6 +1119,8 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, Virtual, Access, TInfo, EllipsisLoc)) return BaseSpec; + else + Class->setInvalidDecl(); return true; } @@ -1403,32 +1405,50 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, return ProcessAccessDeclAttributeList(ASDecl, Attrs); } -/// CheckOverrideControl - Check C++0x override control semantics. -void Sema::CheckOverrideControl(const Decl *D) { +/// CheckOverrideControl - Check C++11 override control semantics. +void Sema::CheckOverrideControl(Decl *D) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); - if (!MD || !MD->isVirtual()) + + // Do we know which functions this declaration might be overriding? + bool OverridesAreKnown = !MD || + (!MD->getParent()->hasAnyDependentBases() && + !MD->getType()->isDependentType()); + + if (!MD || !MD->isVirtual()) { + if (OverridesAreKnown) { + if (OverrideAttr *OA = D->getAttr<OverrideAttr>()) { + Diag(OA->getLocation(), + diag::override_keyword_only_allowed_on_virtual_member_functions) + << "override" << FixItHint::CreateRemoval(OA->getLocation()); + D->dropAttr<OverrideAttr>(); + } + if (FinalAttr *FA = D->getAttr<FinalAttr>()) { + Diag(FA->getLocation(), + diag::override_keyword_only_allowed_on_virtual_member_functions) + << "final" << FixItHint::CreateRemoval(FA->getLocation()); + D->dropAttr<FinalAttr>(); + } + } return; + } - if (MD->isDependentContext()) + if (!OverridesAreKnown) return; - // C++0x [class.virtual]p3: - // If a virtual function is marked with the virt-specifier override and does - // not override a member function of a base class, - // the program is ill-formed. - bool HasOverriddenMethods = + // C++11 [class.virtual]p5: + // If a virtual function is marked with the virt-specifier override and + // does not override a member function of a base class, the program is + // ill-formed. + bool HasOverriddenMethods = MD->begin_overridden_methods() != MD->end_overridden_methods(); - if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) { - Diag(MD->getLocation(), - diag::err_function_marked_override_not_overriding) + if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) + Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding) << MD->getDeclName(); - return; - } } -/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member +/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member /// function overrides a virtual member function marked 'final', according to -/// C++0x [class.virtual]p3. +/// C++11 [class.virtual]p4. bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old) { if (!Old->hasAttr<FinalAttr>()) @@ -1440,16 +1460,26 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, return true; } +static bool InitializationHasSideEffects(const FieldDecl &FD) { + const Type *T = FD.getType()->getBaseElementTypeUnsafe(); + // FIXME: Destruction of ObjC lifetime types has side-effects. + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return !RD->isCompleteDefinition() || + !RD->hasTrivialDefaultConstructor() || + !RD->hasTrivialDestructor(); + return false; +} + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one, 'InitExpr' specifies the initializer if -/// one has been parsed, and 'HasDeferredInit' is true if an initializer is -/// present but parsing it has been deferred. +/// one has been parsed, and 'InitStyle' is set if an in-class initializer is +/// present (but parsing it has been deferred). Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BW, const VirtSpecifiers &VS, - bool HasDeferredInit) { + InClassInitStyle InitStyle) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -1507,12 +1537,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, CXXScopeSpec &SS = D.getCXXScopeSpec(); // Data members must have identifiers for names. - if (Name.getNameKind() != DeclarationName::Identifier) { + if (!Name.isIdentifier()) { Diag(Loc, diag::err_bad_variable_name) << Name; return 0; } - + IdentifierInfo *II = Name.getAsIdentifierInfo(); // Member field could not be with "template" keyword. @@ -1553,10 +1583,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, - HasDeferredInit, AS); + InitStyle, AS); assert(Member && "HandleField never returns null"); } else { - assert(!HasDeferredInit); + assert(InitStyle == ICIS_NoInit); Member = HandleDeclarator(S, D, move(TemplateParameterLists)); if (!Member) { @@ -1596,37 +1626,39 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, FunTmpl->getTemplatedDecl()->setAccess(AS); } - if (VS.isOverrideSpecified()) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); - if (!MD || !MD->isVirtual()) { - Diag(Member->getLocStart(), - diag::override_keyword_only_allowed_on_virtual_member_functions) - << "override" << FixItHint::CreateRemoval(VS.getOverrideLoc()); - } else - MD->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); - } - if (VS.isFinalSpecified()) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); - if (!MD || !MD->isVirtual()) { - Diag(Member->getLocStart(), - diag::override_keyword_only_allowed_on_virtual_member_functions) - << "final" << FixItHint::CreateRemoval(VS.getFinalLoc()); - } else - MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); - } + if (VS.isOverrideSpecified()) + Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); + if (VS.isFinalSpecified()) + Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); if (VS.getLastLocation().isValid()) { // Update the end location of a method that has a virt-specifiers. if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Member)) MD->setRangeEnd(VS.getLastLocation()); } - + CheckOverrideControl(Member); assert((Name || isInstField) && "No identifier for non-field ?"); - if (isInstField) - FieldCollector->Add(cast<FieldDecl>(Member)); + if (isInstField) { + FieldDecl *FD = cast<FieldDecl>(Member); + FieldCollector->Add(FD); + + if (Diags.getDiagnosticLevel(diag::warn_unused_private_field, + FD->getLocation()) + != DiagnosticsEngine::Ignored) { + // Remember all explicit private FieldDecls that have a name, no side + // effects and are not part of a dependent type declaration. + if (!FD->isImplicit() && FD->getDeclName() && + FD->getAccess() == AS_private && + !FD->hasAttr<UnusedAttr>() && + !FD->getParent()->isDependentContext() && + !InitializationHasSideEffects(*FD)) + UnusedPrivateFields.insert(FD); + } + } + return Member; } @@ -1635,9 +1667,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, /// instantiating an in-class initializer in a class template. Such actions /// are deferred until the class is complete. void -Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, +Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc, Expr *InitExpr) { FieldDecl *FD = cast<FieldDecl>(D); + assert(FD->getInClassInitStyle() != ICIS_NoInit && + "must set init style when field is created"); if (!InitExpr) { FD->setInvalidDecl(); @@ -1660,9 +1694,9 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, Expr **Inits = &InitExpr; unsigned NumInits = 1; InitializedEntity Entity = InitializedEntity::InitializeMember(FD); - InitializationKind Kind = EqualLoc.isInvalid() + InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) - : InitializationKind::CreateCopy(InitExpr->getLocStart(), EqualLoc); + : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits); Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (Init.isInvalid()) { @@ -1670,7 +1704,7 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, return; } - CheckImplicitConversions(Init.get(), EqualLoc); + CheckImplicitConversions(Init.get(), InitLoc); } // C++0x [class.base.init]p7: @@ -2010,73 +2044,95 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, << (unsigned)IsPointer; } -/// Checks an initializer expression for use of uninitialized fields, such as -/// containing the field that is being initialized. Returns true if there is an -/// uninitialized field was used an updates the SourceLocation parameter; false -/// otherwise. -static bool InitExprContainsUninitializedFields(const Stmt *S, - const ValueDecl *LhsField, - SourceLocation *L) { - assert(isa<FieldDecl>(LhsField) || isa<IndirectFieldDecl>(LhsField)); - - if (isa<CallExpr>(S)) { - // Do not descend into function calls or constructors, as the use - // of an uninitialized field may be valid. One would have to inspect - // the contents of the function/ctor to determine if it is safe or not. - // i.e. Pass-by-value is never safe, but pass-by-reference and pointers - // may be safe, depending on what the function/ctor does. - return false; - } - if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) { - const NamedDecl *RhsField = ME->getMemberDecl(); - - if (const VarDecl *VD = dyn_cast<VarDecl>(RhsField)) { - // The member expression points to a static data member. - assert(VD->isStaticDataMember() && - "Member points to non-static data member!"); - (void)VD; - return false; +namespace { + class UninitializedFieldVisitor + : public EvaluatedExprVisitor<UninitializedFieldVisitor> { + Sema &S; + ValueDecl *VD; + public: + typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited; + UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context), + S(S), VD(VD) { } - - if (isa<EnumConstantDecl>(RhsField)) { - // The member expression points to an enum. - return false; + + void HandleExpr(Expr *E) { + if (!E) return; + + // Expressions like x(x) sometimes lack the surrounding expressions + // but need to be checked anyways. + HandleValue(E); + Visit(E); } - if (RhsField == LhsField) { - // Initializing a field with itself. Throw a warning. - // But wait; there are exceptions! - // Exception #1: The field may not belong to this record. - // e.g. Foo(const Foo& rhs) : A(rhs.A) {} - const Expr *base = ME->getBase(); - if (base != NULL && !isa<CXXThisExpr>(base->IgnoreParenCasts())) { - // Even though the field matches, it does not belong to this record. - return false; + void HandleValue(Expr *E) { + E = E->IgnoreParens(); + + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (isa<EnumConstantDecl>(ME->getMemberDecl())) + return; + Expr *Base = E; + while (isa<MemberExpr>(Base)) { + ME = dyn_cast<MemberExpr>(Base); + if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl())) + if (VarD->hasGlobalStorage()) + return; + Base = ME->getBase(); + } + + if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) { + S.Diag(ME->getExprLoc(), diag::warn_field_is_uninit); + return; + } + } + + if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + HandleValue(CO->getTrueExpr()); + HandleValue(CO->getFalseExpr()); + return; + } + + if (BinaryConditionalOperator *BCO = + dyn_cast<BinaryConditionalOperator>(E)) { + HandleValue(BCO->getCommon()); + HandleValue(BCO->getFalseExpr()); + return; + } + + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + switch (BO->getOpcode()) { + default: + return; + case(BO_PtrMemD): + case(BO_PtrMemI): + HandleValue(BO->getLHS()); + return; + case(BO_Comma): + HandleValue(BO->getRHS()); + return; + } } - // None of the exceptions triggered; return true to indicate an - // uninitialized field was used. - *L = ME->getMemberLoc(); - return true; } - } else if (isa<UnaryExprOrTypeTraitExpr>(S)) { - // sizeof/alignof doesn't reference contents, do not warn. - return false; - } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(S)) { - // address-of doesn't reference contents (the pointer may be dereferenced - // in the same expression but it would be rare; and weird). - if (UOE->getOpcode() == UO_AddrOf) - return false; - } - for (Stmt::const_child_range it = S->children(); it; ++it) { - if (!*it) { - // An expression such as 'member(arg ?: "")' may trigger this. - continue; + + void VisitImplicitCastExpr(ImplicitCastExpr *E) { + if (E->getCastKind() == CK_LValueToRValue) + HandleValue(E->getSubExpr()); + + Inherited::VisitImplicitCastExpr(E); } - if (InitExprContainsUninitializedFields(*it, LhsField, L)) - return true; + + void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { + Expr *Callee = E->getCallee(); + if (isa<MemberExpr>(Callee)) + HandleValue(Callee); + + Inherited::VisitCXXMemberCallExpr(E); + } + }; + static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E, + ValueDecl *VD) { + UninitializedFieldVisitor(S, VD).HandleExpr(E); } - return false; -} +} // namespace MemInitResult Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, @@ -2106,18 +2162,17 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, Args = InitList->getInits(); NumArgs = InitList->getNumInits(); } - for (unsigned i = 0; i < NumArgs; ++i) { - SourceLocation L; - if (InitExprContainsUninitializedFields(Args[i], Member, &L)) { - // FIXME: Return true in the case when other fields are used before being + + if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc) + != DiagnosticsEngine::Ignored) + for (unsigned i = 0; i < NumArgs; ++i) + // FIXME: Warn about the case when other fields are used before being // uninitialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th // fields are used, as they are not yet initialized. // Right now we are only handling the case where the i'th field uses // itself in its initializer. - Diag(L, diag::warn_field_is_uninit); - } - } + CheckInitExprContainsUninitializedFields(*this, Args[i], Member); SourceRange InitRange = Init->getSourceRange(); @@ -2235,6 +2290,16 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, if (DelegationInit.isInvalid()) return true; + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) + DelegationInit = Owned(Init); + return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(), DelegationInit.takeAs<Expr>(), InitRange.getEnd()); @@ -2694,7 +2759,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, FieldBaseElementType->isObjCRetainableType() && FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None && FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { - // Instant objects: + // ARC: // Default-initialize Objective-C pointers to NULL. CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, @@ -2741,6 +2806,16 @@ struct BaseAndFieldInfo { llvm_unreachable("Invalid ImplicitInitializerKind!"); } + + bool addFieldInitializer(CXXCtorInitializer *Init) { + AllToInit.push_back(Init); + + // Check whether this initializer makes the field "used". + if (Init->getInit() && Init->getInit()->HasSideEffects(S.Context)) + S.UnusedPrivateFields.remove(Init->getAnyMember()); + + return false; + } }; } @@ -2778,12 +2853,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, IndirectFieldDecl *Indirect = 0) { // Overwhelmingly common case: we have a direct initializer for this field. - if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) { - Info.AllToInit.push_back(Init); - return false; - } + if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) + return Info.addFieldInitializer(Init); - // C++0x [class.base.init]p8: if the entity is a non-static data member that + // C++11 [class.base.init]p8: if the entity is a non-static data member that // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { @@ -2798,8 +2871,7 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, SourceLocation(), SourceLocation(), 0, SourceLocation()); - Info.AllToInit.push_back(Init); - return false; + return Info.addFieldInitializer(Init); } // Don't build an implicit initializer for union members if none was @@ -2823,10 +2895,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, Indirect, Init)) return true; - if (Init) - Info.AllToInit.push_back(Init); + if (!Init) + return false; - return false; + return Info.addFieldInitializer(Init); } bool @@ -3397,19 +3469,33 @@ void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) { bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, AbstractDiagSelID SelID) { - if (SelID == -1) - return RequireNonAbstractType(Loc, T, PDiag(DiagID)); - else - return RequireNonAbstractType(Loc, T, PDiag(DiagID) << SelID); + class NonAbstractTypeDiagnoser : public TypeDiagnoser { + unsigned DiagID; + AbstractDiagSelID SelID; + + public: + NonAbstractTypeDiagnoser(unsigned DiagID, AbstractDiagSelID SelID) + : TypeDiagnoser(DiagID == 0), DiagID(DiagID), SelID(SelID) { } + + virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) { + if (Suppressed) return; + if (SelID == -1) + S.Diag(Loc, DiagID) << T; + else + S.Diag(Loc, DiagID) << SelID << T; + } + } Diagnoser(DiagID, SelID); + + return RequireNonAbstractType(Loc, T, Diagnoser); } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, - const PartialDiagnostic &PD) { + TypeDiagnoser &Diagnoser) { if (!getLangOpts().CPlusPlus) return false; if (const ArrayType *AT = Context.getAsArrayType(T)) - return RequireNonAbstractType(Loc, AT->getElementType(), PD); + return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser); if (const PointerType *PT = T->getAs<PointerType>()) { // Find the innermost pointer type. @@ -3417,7 +3503,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, PT = T; if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType())) - return RequireNonAbstractType(Loc, AT->getElementType(), PD); + return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser); } const RecordType *RT = T->getAs<RecordType>(); @@ -3436,7 +3522,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, if (!RD->isAbstract()) return false; - Diag(Loc, PD) << RD->getDeclName(); + Diagnoser.diagnose(*this, Loc, T); DiagnoseAbstractType(RD); return true; @@ -3732,7 +3818,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (CXXRecordDecl::method_iterator M = Record->method_begin(), MEnd = Record->method_end(); M != MEnd; ++M) { - if (!(*M)->isStatic()) + if (!M->isStatic()) DiagnoseHiddenVirtualMethods(Record, *M); } } @@ -3762,8 +3848,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { case TSK_Undeclared: case TSK_ExplicitSpecialization: - RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record), - PDiag(diag::err_constexpr_method_non_literal)); + RequireLiteralType(M->getLocation(), Context.getRecordType(Record), + diag::err_constexpr_method_non_literal); break; } @@ -3781,558 +3867,354 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // instantiated (e.g. meta-functions). This doesn't apply to classes that // have inherited constructors. DeclareInheritedConstructors(Record); - - if (!Record->isDependentType()) - CheckExplicitlyDefaultedMethods(Record); } void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { for (CXXRecordDecl::method_iterator MI = Record->method_begin(), ME = Record->method_end(); - MI != ME; ++MI) { - if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) { - switch (getSpecialMember(*MI)) { - case CXXDefaultConstructor: - CheckExplicitlyDefaultedDefaultConstructor( - cast<CXXConstructorDecl>(*MI)); - break; - - case CXXDestructor: - CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI)); - break; - - case CXXCopyConstructor: - CheckExplicitlyDefaultedCopyConstructor(cast<CXXConstructorDecl>(*MI)); - break; - - case CXXCopyAssignment: - CheckExplicitlyDefaultedCopyAssignment(*MI); - break; - - case CXXMoveConstructor: - CheckExplicitlyDefaultedMoveConstructor(cast<CXXConstructorDecl>(*MI)); - break; - - case CXXMoveAssignment: - CheckExplicitlyDefaultedMoveAssignment(*MI); - break; - - case CXXInvalid: - llvm_unreachable("non-special member explicitly defaulted!"); - } - } - } - + MI != ME; ++MI) + if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) + CheckExplicitlyDefaultedSpecialMember(*MI); +} + +/// Is the special member function which would be selected to perform the +/// specified operation on the specified class type a constexpr constructor? +static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, + Sema::CXXSpecialMember CSM, + bool ConstArg) { + Sema::SpecialMemberOverloadResult *SMOR = + S.LookupSpecialMember(ClassDecl, CSM, ConstArg, + false, false, false, false); + if (!SMOR || !SMOR->getMethod()) + // A constructor we wouldn't select can't be "involved in initializing" + // anything. + return true; + return SMOR->getMethod()->isConstexpr(); } -void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { - assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor()); - - // Whether this was the first-declared instance of the constructor. - // This affects whether we implicitly add an exception spec (and, eventually, - // constexpr). It is also ill-formed to explicitly default a constructor such - // that it would be deleted. (C++0x [decl.fct.def.default]) - bool First = CD == CD->getCanonicalDecl(); +/// Determine whether the specified special member function would be constexpr +/// if it were implicitly defined. +static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, + Sema::CXXSpecialMember CSM, + bool ConstArg) { + if (!S.getLangOpts().CPlusPlus0x) + return false; - bool HadError = false; - if (CD->getNumParams() != 0) { - Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params) - << CD->getSourceRange(); - HadError = true; - } + // C++11 [dcl.constexpr]p4: + // In the definition of a constexpr constructor [...] + switch (CSM) { + case Sema::CXXDefaultConstructor: + // Since default constructor lookup is essentially trivial (and cannot + // involve, for instance, template instantiation), we compute whether a + // defaulted default constructor is constexpr directly within CXXRecordDecl. + // + // This is important for performance; we need to know whether the default + // constructor is constexpr to determine whether the type is a literal type. + return ClassDecl->defaultedDefaultConstructorIsConstexpr(); - ImplicitExceptionSpecification Spec - = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent()); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - if (EPI.ExceptionSpecType == EST_Delayed) { - // Exception specification depends on some deferred part of the class. We'll - // try again when the class's definition has been fully processed. - return; - } - const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), - *ExceptionType = Context.getFunctionType( - Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + case Sema::CXXCopyConstructor: + case Sema::CXXMoveConstructor: + // For copy or move constructors, we need to perform overload resolution. + break; - // C++11 [dcl.fct.def.default]p2: - // An explicitly-defaulted function may be declared constexpr only if it - // would have been implicitly declared as constexpr, - // Do not apply this rule to templates, since core issue 1358 makes such - // functions always instantiate to constexpr functions. - if (CD->isConstexpr() && - CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { - if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) { - Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) - << CXXDefaultConstructor; - HadError = true; - } - } - // and may have an explicit exception-specification only if it is compatible - // with the exception-specification on the implicit declaration. - if (CtorType->hasExceptionSpec()) { - if (CheckEquivalentExceptionSpec( - PDiag(diag::err_incorrect_defaulted_exception_spec) - << CXXDefaultConstructor, - PDiag(), - ExceptionType, SourceLocation(), - CtorType, CD->getLocation())) { - HadError = true; - } + case Sema::CXXCopyAssignment: + case Sema::CXXMoveAssignment: + case Sema::CXXDestructor: + case Sema::CXXInvalid: + return false; } - // If a function is explicitly defaulted on its first declaration, - if (First) { - // -- it is implicitly considered to be constexpr if the implicit - // definition would be, - CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr()); + // -- if the class is a non-empty union, or for each non-empty anonymous + // union member of a non-union class, exactly one non-static data member + // shall be initialized; [DR1359] + // + // If we squint, this is guaranteed, since exactly one non-static data member + // will be initialized (if the constructor isn't deleted), we just don't know + // which one. + if (ClassDecl->isUnion()) + return true; - // -- it is implicitly considered to have the same - // exception-specification as if it had been implicitly declared - // - // FIXME: a compatible, but different, explicit exception specification - // will be silently overridden. We should issue a warning if this happens. - EPI.ExtInfo = CtorType->getExtInfo(); + // -- the class shall not have any virtual base classes; + if (ClassDecl->getNumVBases()) + return false; - // Such a function is also trivial if the implicitly-declared function - // would have been. - CD->setTrivial(CD->getParent()->hasTrivialDefaultConstructor()); - } + // -- every constructor involved in initializing [...] base class + // sub-objects shall be a constexpr constructor; + for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), + BEnd = ClassDecl->bases_end(); + B != BEnd; ++B) { + const RecordType *BaseType = B->getType()->getAs<RecordType>(); + if (!BaseType) continue; - if (HadError) { - CD->setInvalidDecl(); - return; + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, ConstArg)) + return false; } - if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) { - if (First) { - CD->setDeletedAsWritten(); - } else { - Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) - << CXXDefaultConstructor; - CD->setInvalidDecl(); + // -- every constructor involved in initializing non-static data members + // [...] shall be a constexpr constructor; + // -- every non-static data member and base class sub-object shall be + // initialized + for (RecordDecl::field_iterator F = ClassDecl->field_begin(), + FEnd = ClassDecl->field_end(); + F != FEnd; ++F) { + if (F->isInvalidDecl()) + continue; + if (const RecordType *RecordTy = + S.Context.getBaseElementType(F->getType())->getAs<RecordType>()) { + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (!specialMemberIsConstexpr(S, FieldRecDecl, CSM, ConstArg)) + return false; } } -} - -void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { - assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor()); - - // Whether this was the first-declared instance of the constructor. - bool First = CD == CD->getCanonicalDecl(); - - bool HadError = false; - if (CD->getNumParams() != 1) { - Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params) - << CD->getSourceRange(); - HadError = true; - } - ImplicitExceptionSpecification Spec(*this); - bool Const; - llvm::tie(Spec, Const) = - ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent()); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), - *ExceptionType = Context.getFunctionType( - Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); - - // Check for parameter type matching. - // This is a copy ctor so we know it's a cv-qualified reference to T. - QualType ArgType = CtorType->getArgType(0); - if (ArgType->getPointeeType().isVolatileQualified()) { - Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param); - HadError = true; - } - if (ArgType->getPointeeType().isConstQualified() && !Const) { - Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param); - HadError = true; - } + // All OK, it's constexpr! + return true; +} - // C++11 [dcl.fct.def.default]p2: - // An explicitly-defaulted function may be declared constexpr only if it - // would have been implicitly declared as constexpr, - // Do not apply this rule to templates, since core issue 1358 makes such - // functions always instantiate to constexpr functions. - if (CD->isConstexpr() && - CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { - if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) { - Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) - << CXXCopyConstructor; - HadError = true; - } - } - // and may have an explicit exception-specification only if it is compatible - // with the exception-specification on the implicit declaration. - if (CtorType->hasExceptionSpec()) { - if (CheckEquivalentExceptionSpec( - PDiag(diag::err_incorrect_defaulted_exception_spec) - << CXXCopyConstructor, - PDiag(), - ExceptionType, SourceLocation(), - CtorType, CD->getLocation())) { - HadError = true; - } +static Sema::ImplicitExceptionSpecification +computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) { + switch (S.getSpecialMember(MD)) { + case Sema::CXXDefaultConstructor: + return S.ComputeDefaultedDefaultCtorExceptionSpec(Loc, MD); + case Sema::CXXCopyConstructor: + return S.ComputeDefaultedCopyCtorExceptionSpec(MD); + case Sema::CXXCopyAssignment: + return S.ComputeDefaultedCopyAssignmentExceptionSpec(MD); + case Sema::CXXMoveConstructor: + return S.ComputeDefaultedMoveCtorExceptionSpec(MD); + case Sema::CXXMoveAssignment: + return S.ComputeDefaultedMoveAssignmentExceptionSpec(MD); + case Sema::CXXDestructor: + return S.ComputeDefaultedDtorExceptionSpec(MD); + case Sema::CXXInvalid: + break; } + llvm_unreachable("only special members have implicit exception specs"); +} - // If a function is explicitly defaulted on its first declaration, - if (First) { - // -- it is implicitly considered to be constexpr if the implicit - // definition would be, - CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr()); +static void +updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT, + const Sema::ImplicitExceptionSpecification &ExceptSpec) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + ExceptSpec.getEPI(EPI); + const FunctionProtoType *NewFPT = cast<FunctionProtoType>( + S.Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), EPI)); + FD->setType(QualType(NewFPT, 0)); +} + +void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); + if (FPT->getExceptionSpecType() != EST_Unevaluated) + return; - // -- it is implicitly considered to have the same - // exception-specification as if it had been implicitly declared, and - // - // FIXME: a compatible, but different, explicit exception specification - // will be silently overridden. We should issue a warning if this happens. - EPI.ExtInfo = CtorType->getExtInfo(); + // Evaluate the exception specification. + ImplicitExceptionSpecification ExceptSpec = + computeImplicitExceptionSpec(*this, Loc, MD); - // -- [...] it shall have the same parameter type as if it had been - // implicitly declared. - CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + // Update the type of the special member to use it. + updateExceptionSpec(*this, MD, FPT, ExceptSpec); - // Such a function is also trivial if the implicitly-declared function - // would have been. - CD->setTrivial(CD->getParent()->hasTrivialCopyConstructor()); - } + // A user-provided destructor can be defined outside the class. When that + // happens, be sure to update the exception specification on both + // declarations. + const FunctionProtoType *CanonicalFPT = + MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>(); + if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated) + updateExceptionSpec(*this, MD->getCanonicalDecl(), + CanonicalFPT, ExceptSpec); +} - if (HadError) { - CD->setInvalidDecl(); - return; - } +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl); +static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl); - if (ShouldDeleteSpecialMember(CD, CXXCopyConstructor)) { - if (First) { - CD->setDeletedAsWritten(); - } else { - Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) - << CXXCopyConstructor; - CD->setInvalidDecl(); - } - } -} +void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { + CXXRecordDecl *RD = MD->getParent(); + CXXSpecialMember CSM = getSpecialMember(MD); -void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { - assert(MD->isExplicitlyDefaulted()); + assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid && + "not an explicitly-defaulted special member"); - // Whether this was the first-declared instance of the operator + // Whether this was the first-declared instance of the constructor. + // This affects whether we implicitly add an exception spec and constexpr. bool First = MD == MD->getCanonicalDecl(); bool HadError = false; - if (MD->getNumParams() != 1) { - Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params) - << MD->getSourceRange(); - HadError = true; - } - QualType ReturnType = - MD->getType()->getAs<FunctionType>()->getResultType(); - if (!ReturnType->isLValueReferenceType() || - !Context.hasSameType( - Context.getCanonicalType(ReturnType->getPointeeType()), - Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { - Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type); + // C++11 [dcl.fct.def.default]p1: + // A function that is explicitly defaulted shall + // -- be a special member function (checked elsewhere), + // -- have the same type (except for ref-qualifiers, and except that a + // copy operation can take a non-const reference) as an implicit + // declaration, and + // -- not have default arguments. + unsigned ExpectedParams = 1; + if (CSM == CXXDefaultConstructor || CSM == CXXDestructor) + ExpectedParams = 0; + if (MD->getNumParams() != ExpectedParams) { + // This also checks for default arguments: a copy or move constructor with a + // default argument is classified as a default constructor, and assignment + // operations and destructors can't have default arguments. + Diag(MD->getLocation(), diag::err_defaulted_special_member_params) + << CSM << MD->getSourceRange(); HadError = true; } - ImplicitExceptionSpecification Spec(*this); - bool Const; - llvm::tie(Spec, Const) = - ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent()); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(), - *ExceptionType = Context.getFunctionType( - Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>(); - QualType ArgType = OperType->getArgType(0); - if (!ArgType->isLValueReferenceType()) { - Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); - HadError = true; - } else { - if (ArgType->getPointeeType().isVolatileQualified()) { - Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param); + // Compute argument constness, constexpr, and triviality. + bool CanHaveConstParam = false; + bool Trivial; + switch (CSM) { + case CXXDefaultConstructor: + Trivial = RD->hasTrivialDefaultConstructor(); + break; + case CXXCopyConstructor: + CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD); + Trivial = RD->hasTrivialCopyConstructor(); + break; + case CXXCopyAssignment: + CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD); + Trivial = RD->hasTrivialCopyAssignment(); + break; + case CXXMoveConstructor: + Trivial = RD->hasTrivialMoveConstructor(); + break; + case CXXMoveAssignment: + Trivial = RD->hasTrivialMoveAssignment(); + break; + case CXXDestructor: + Trivial = RD->hasTrivialDestructor(); + break; + case CXXInvalid: + llvm_unreachable("non-special member explicitly defaulted!"); + } + + QualType ReturnType = Context.VoidTy; + if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) { + // Check for return type matching. + ReturnType = Type->getResultType(); + QualType ExpectedReturnType = + Context.getLValueReferenceType(Context.getTypeDeclType(RD)); + if (!Context.hasSameType(ReturnType, ExpectedReturnType)) { + Diag(MD->getLocation(), diag::err_defaulted_special_member_return_type) + << (CSM == CXXMoveAssignment) << ExpectedReturnType; HadError = true; } - if (ArgType->getPointeeType().isConstQualified() && !Const) { - Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param); + + // A defaulted special member cannot have cv-qualifiers. + if (Type->getTypeQuals()) { + Diag(MD->getLocation(), diag::err_defaulted_special_member_quals) + << (CSM == CXXMoveAssignment); HadError = true; } } - if (OperType->getTypeQuals()) { - Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals); - HadError = true; - } - - if (OperType->hasExceptionSpec()) { - if (CheckEquivalentExceptionSpec( - PDiag(diag::err_incorrect_defaulted_exception_spec) - << CXXCopyAssignment, - PDiag(), - ExceptionType, SourceLocation(), - OperType, MD->getLocation())) { + // Check for parameter type matching. + QualType ArgType = ExpectedParams ? Type->getArgType(0) : QualType(); + bool HasConstParam = false; + if (ExpectedParams && ArgType->isReferenceType()) { + // Argument must be reference to possibly-const T. + QualType ReferentType = ArgType->getPointeeType(); + HasConstParam = ReferentType.isConstQualified(); + + if (ReferentType.isVolatileQualified()) { + Diag(MD->getLocation(), + diag::err_defaulted_special_member_volatile_param) << CSM; HadError = true; } - } - if (First) { - // We set the declaration to have the computed exception spec here. - // We duplicate the one parameter type. - EPI.RefQualifier = OperType->getRefQualifier(); - EPI.ExtInfo = OperType->getExtInfo(); - MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); - // Such a function is also trivial if the implicitly-declared function - // would have been. - MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment()); - } - - if (HadError) { - MD->setInvalidDecl(); - return; - } - - if (ShouldDeleteSpecialMember(MD, CXXCopyAssignment)) { - if (First) { - MD->setDeletedAsWritten(); - } else { - Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) - << CXXCopyAssignment; - MD->setInvalidDecl(); + if (HasConstParam && !CanHaveConstParam) { + if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment) { + Diag(MD->getLocation(), + diag::err_defaulted_special_member_copy_const_param) + << (CSM == CXXCopyAssignment); + // FIXME: Explain why this special member can't be const. + } else { + Diag(MD->getLocation(), + diag::err_defaulted_special_member_move_const_param) + << (CSM == CXXMoveAssignment); + } + HadError = true; } - } -} - -void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) { - assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor()); - - // Whether this was the first-declared instance of the constructor. - bool First = CD == CD->getCanonicalDecl(); - bool HadError = false; - if (CD->getNumParams() != 1) { - Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params) - << CD->getSourceRange(); + // If a function is explicitly defaulted on its first declaration, it shall + // have the same parameter type as if it had been implicitly declared. + // (Presumably this is to prevent it from being trivial?) + if (!HasConstParam && CanHaveConstParam && First) + Diag(MD->getLocation(), + diag::err_defaulted_special_member_copy_non_const_param) + << (CSM == CXXCopyAssignment); + } else if (ExpectedParams) { + // A copy assignment operator can take its argument by value, but a + // defaulted one cannot. + assert(CSM == CXXCopyAssignment && "unexpected non-ref argument"); + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); HadError = true; } - ImplicitExceptionSpecification Spec( - ComputeDefaultedMoveCtorExceptionSpec(CD->getParent())); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), - *ExceptionType = Context.getFunctionType( - Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); - - // Check for parameter type matching. - // This is a move ctor so we know it's a cv-qualified rvalue reference to T. - QualType ArgType = CtorType->getArgType(0); - if (ArgType->getPointeeType().isVolatileQualified()) { - Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param); - HadError = true; - } - if (ArgType->getPointeeType().isConstQualified()) { - Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param); - HadError = true; + // Rebuild the type with the implicit exception specification added, if we + // are going to need it. + const FunctionProtoType *ImplicitType = 0; + if (First || Type->hasExceptionSpec()) { + FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); + computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI); + ImplicitType = cast<FunctionProtoType>( + Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI)); } // C++11 [dcl.fct.def.default]p2: // An explicitly-defaulted function may be declared constexpr only if it // would have been implicitly declared as constexpr, - // Do not apply this rule to templates, since core issue 1358 makes such - // functions always instantiate to constexpr functions. - if (CD->isConstexpr() && - CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { - if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) { - Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) - << CXXMoveConstructor; - HadError = true; - } + // Do not apply this rule to members of class templates, since core issue 1358 + // makes such functions always instantiate to constexpr functions. For + // non-constructors, this is checked elsewhere. + bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, + HasConstParam); + if (isa<CXXConstructorDecl>(MD) && MD->isConstexpr() && !Constexpr && + MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { + Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM; + // FIXME: Explain why the constructor can't be constexpr. + HadError = true; } // and may have an explicit exception-specification only if it is compatible // with the exception-specification on the implicit declaration. - if (CtorType->hasExceptionSpec()) { - if (CheckEquivalentExceptionSpec( - PDiag(diag::err_incorrect_defaulted_exception_spec) - << CXXMoveConstructor, - PDiag(), - ExceptionType, SourceLocation(), - CtorType, CD->getLocation())) { - HadError = true; - } - } + if (Type->hasExceptionSpec() && + CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) << CSM, + PDiag(), ImplicitType, SourceLocation(), Type, MD->getLocation())) + HadError = true; // If a function is explicitly defaulted on its first declaration, if (First) { // -- it is implicitly considered to be constexpr if the implicit // definition would be, - CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr()); + MD->setConstexpr(Constexpr); - // -- it is implicitly considered to have the same - // exception-specification as if it had been implicitly declared, and - // - // FIXME: a compatible, but different, explicit exception specification - // will be silently overridden. We should issue a warning if this happens. - EPI.ExtInfo = CtorType->getExtInfo(); - - // -- [...] it shall have the same parameter type as if it had been - // implicitly declared. - CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + // -- it is implicitly considered to have the same exception-specification + // as if it had been implicitly declared, + MD->setType(QualType(ImplicitType, 0)); // Such a function is also trivial if the implicitly-declared function // would have been. - CD->setTrivial(CD->getParent()->hasTrivialMoveConstructor()); - } - - if (HadError) { - CD->setInvalidDecl(); - return; + MD->setTrivial(Trivial); } - if (ShouldDeleteSpecialMember(CD, CXXMoveConstructor)) { + if (ShouldDeleteSpecialMember(MD, CSM)) { if (First) { - CD->setDeletedAsWritten(); + MD->setDeletedAsWritten(); } else { - Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) - << CXXMoveConstructor; - CD->setInvalidDecl(); - } - } -} - -void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) { - assert(MD->isExplicitlyDefaulted()); - - // Whether this was the first-declared instance of the operator - bool First = MD == MD->getCanonicalDecl(); - - bool HadError = false; - if (MD->getNumParams() != 1) { - Diag(MD->getLocation(), diag::err_defaulted_move_assign_params) - << MD->getSourceRange(); - HadError = true; - } - - QualType ReturnType = - MD->getType()->getAs<FunctionType>()->getResultType(); - if (!ReturnType->isLValueReferenceType() || - !Context.hasSameType( - Context.getCanonicalType(ReturnType->getPointeeType()), - Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { - Diag(MD->getLocation(), diag::err_defaulted_move_assign_return_type); - HadError = true; - } - - ImplicitExceptionSpecification Spec( - ComputeDefaultedMoveCtorExceptionSpec(MD->getParent())); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(), - *ExceptionType = Context.getFunctionType( - Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); - - QualType ArgType = OperType->getArgType(0); - if (!ArgType->isRValueReferenceType()) { - Diag(MD->getLocation(), diag::err_defaulted_move_assign_not_ref); - HadError = true; - } else { - if (ArgType->getPointeeType().isVolatileQualified()) { - Diag(MD->getLocation(), diag::err_defaulted_move_assign_volatile_param); - HadError = true; - } - if (ArgType->getPointeeType().isConstQualified()) { - Diag(MD->getLocation(), diag::err_defaulted_move_assign_const_param); + // C++11 [dcl.fct.def.default]p4: + // [For a] user-provided explicitly-defaulted function [...] if such a + // function is implicitly defined as deleted, the program is ill-formed. + Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM; HadError = true; } } - if (OperType->getTypeQuals()) { - Diag(MD->getLocation(), diag::err_defaulted_move_assign_quals); - HadError = true; - } - - if (OperType->hasExceptionSpec()) { - if (CheckEquivalentExceptionSpec( - PDiag(diag::err_incorrect_defaulted_exception_spec) - << CXXMoveAssignment, - PDiag(), - ExceptionType, SourceLocation(), - OperType, MD->getLocation())) { - HadError = true; - } - } - if (First) { - // We set the declaration to have the computed exception spec here. - // We duplicate the one parameter type. - EPI.RefQualifier = OperType->getRefQualifier(); - EPI.ExtInfo = OperType->getExtInfo(); - MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); - - // Such a function is also trivial if the implicitly-declared function - // would have been. - MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment()); - } - - if (HadError) { + if (HadError) MD->setInvalidDecl(); - return; - } - - if (ShouldDeleteSpecialMember(MD, CXXMoveAssignment)) { - if (First) { - MD->setDeletedAsWritten(); - } else { - Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) - << CXXMoveAssignment; - MD->setInvalidDecl(); - } - } -} - -void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { - assert(DD->isExplicitlyDefaulted()); - - // Whether this was the first-declared instance of the destructor. - bool First = DD == DD->getCanonicalDecl(); - - ImplicitExceptionSpecification Spec - = ComputeDefaultedDtorExceptionSpec(DD->getParent()); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(), - *ExceptionType = Context.getFunctionType( - Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); - - if (DtorType->hasExceptionSpec()) { - if (CheckEquivalentExceptionSpec( - PDiag(diag::err_incorrect_defaulted_exception_spec) - << CXXDestructor, - PDiag(), - ExceptionType, SourceLocation(), - DtorType, DD->getLocation())) { - DD->setInvalidDecl(); - return; - } - } - if (First) { - // We set the declaration to have the computed exception spec here. - // There are no parameters. - EPI.ExtInfo = DtorType->getExtInfo(); - DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); - - // Such a function is also trivial if the implicitly-declared function - // would have been. - DD->setTrivial(DD->getParent()->hasTrivialDestructor()); - } - - if (ShouldDeleteSpecialMember(DD, CXXDestructor)) { - if (First) { - DD->setDeletedAsWritten(); - } else { - Diag(DD->getLocation(), diag::err_out_of_line_default_deletes) - << CXXDestructor; - DD->setInvalidDecl(); - } - } } namespace { @@ -4385,9 +4267,15 @@ struct SpecialMemberDeletionInfo { bool inUnion() const { return MD->getParent()->isUnion(); } /// Look up the corresponding special member in the given class. - Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class) { + Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class, + unsigned Quals) { unsigned TQ = MD->getTypeQualifiers(); - return S.LookupSpecialMember(Class, CSM, ConstArg, VolatileArg, + // cv-qualifiers on class members don't affect default ctor / dtor calls. + if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor) + Quals = 0; + return S.LookupSpecialMember(Class, CSM, + ConstArg || (Quals & Qualifiers::Const), + VolatileArg || (Quals & Qualifiers::Volatile), MD->getRefQualifier() == RQ_RValue, TQ & Qualifiers::Const, TQ & Qualifiers::Volatile); @@ -4399,7 +4287,8 @@ struct SpecialMemberDeletionInfo { bool shouldDeleteForField(FieldDecl *FD); bool shouldDeleteForAllConstMembers(); - bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj); + bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj, + unsigned Quals); bool shouldDeleteForSubobjectCall(Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR, bool IsDtorCallInCtor); @@ -4480,9 +4369,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( } /// Check whether we should delete a special member function due to having a -/// direct or virtual base class or static data member of class type M. +/// direct or virtual base class or non-static data member of class type M. bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( - CXXRecordDecl *Class, Subobject Subobj) { + CXXRecordDecl *Class, Subobject Subobj, unsigned Quals) { FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>(); // C++11 [class.ctor]p5: @@ -4501,7 +4390,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( // that is deleted or inaccessible if (!(CSM == Sema::CXXDefaultConstructor && Field && Field->hasInClassInitializer()) && - shouldDeleteForSubobjectCall(Subobj, lookupIn(Class), false)) + shouldDeleteForSubobjectCall(Subobj, lookupIn(Class, Quals), false)) return true; // C++11 [class.ctor]p5, C++11 [class.copy]p11: @@ -4522,7 +4411,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( /// having a particular direct or virtual base class. bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl(); - return shouldDeleteForClassSubobject(BaseClass, Base); + return shouldDeleteForClassSubobject(BaseClass, Base, 0); } /// Check whether we should delete a special member function due to the class @@ -4549,7 +4438,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) - << MD->getParent() << FD << FieldType << /*Const*/1; + << MD->getParent() << FD << FD->getType() << /*Const*/1; return true; } @@ -4577,7 +4466,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { // -- a non-static data member of const non-class type (or array thereof) if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_assign_field) - << IsMove << MD->getParent() << FD << FieldType << /*Const*/1; + << IsMove << MD->getParent() << FD << FD->getType() << /*Const*/1; return true; } } @@ -4599,7 +4488,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl(); if (UnionFieldRecord && - shouldDeleteForClassSubobject(UnionFieldRecord, *UI)) + shouldDeleteForClassSubobject(UnionFieldRecord, *UI, + UnionFieldType.getCVRQualifiers())) return true; } @@ -4618,7 +4508,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { return false; } - if (shouldDeleteForClassSubobject(FieldRecord, FD)) + if (shouldDeleteForClassSubobject(FieldRecord, FD, + FieldType.getCVRQualifiers())) return true; } @@ -4647,7 +4538,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { /// C++11 [class.copy]p23, and C++11 [class.dtor]p5. bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, bool Diagnose) { - assert(!MD->isInvalidDecl()); + if (MD->isInvalidDecl()) + return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) @@ -4803,7 +4695,7 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual, MD->getLocation()) == DiagnosticsEngine::Ignored) return; - if (MD->getDeclName().getNameKind() != DeclarationName::Identifier) + if (!MD->getDeclName().isIdentifier()) return; CXXBasePaths Paths(/*FindAmbiguities=*/true, // true to look in all bases. @@ -4850,6 +4742,14 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, AdjustDeclIfTemplate(TagDecl); + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + if (l->getKind() != AttributeList::AT_Visibility) + continue; + l->setInvalid(); + Diag(l->getLoc(), diag::warn_attribute_after_definition_ignored) << + l->getName(); + } + ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( // strict aliasing violation! reinterpret_cast<Decl**>(FieldCollector->getCurFields()), @@ -5572,6 +5472,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, } } + ActOnDocumentableDecl(Namespc); + // Although we could have an invalid decl (i.e. the namespace name is a // redefinition), push it as current DeclContext and try to continue parsing. // FIXME: We should be able to push Namespc here, so that the each DeclContext @@ -6734,6 +6636,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (!Redeclaration) PushOnScopeChains(NewND, S); + ActOnDocumentableDecl(NewND); return NewND; } @@ -6816,7 +6719,10 @@ namespace { } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, + CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -6863,7 +6769,21 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); else if (!F->isInvalidDecl()) - ExceptSpec.SetDelayed(); + // DR1351: + // If the brace-or-equal-initializer of a non-static data member + // invokes a defaulted default constructor of its class or of an + // enclosing class in a potentially evaluated subexpression, the + // program is ill-formed. + // + // This resolution is unworkable: the exception specification of the + // default constructor can be needed in an unevaluated context, in + // particular, in the operand of a noexcept-expression, and we can be + // unable to compute an exception specification for an enclosed class. + // + // We do not allow an in-class initializer to require the evaluation + // of the exception specification for any in-class initializer whose + // definition is not lexically complete. + Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD; } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -6892,9 +6812,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( assert(!ClassDecl->hasUserDeclaredConstructor() && "Should not build implicit default constructor!"); - ImplicitExceptionSpecification Spec = - ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, + CXXDefaultConstructor, + false); // Create the actual constructor declaration. CanQualType ClassType @@ -6904,16 +6824,20 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( = Context.DeclarationNames.getCXXConstructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create( - Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0, + Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, - /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() && - getLangOpts().CPlusPlus0x); + Constexpr); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); - + + // Build an exception specification pointing back at this constructor. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = DefaultCon; + DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; @@ -6948,7 +6872,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } SourceLocation Loc = Constructor->getLocation(); - Constructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); + Constructor->setBody(new (Context) CompoundStmt(Loc)); Constructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); @@ -6958,58 +6882,14 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } } -/// Get any existing defaulted default constructor for the given class. Do not -/// implicitly define one if it does not exist. -static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self, - CXXRecordDecl *D) { - ASTContext &Context = Self.Context; - QualType ClassType = Context.getTypeDeclType(D); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); - Con != ConEnd; ++Con) { - // A function template cannot be defaulted. - if (isa<FunctionTemplateDecl>(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isDefaultConstructor()) - return Constructor->isDefaulted() ? Constructor : 0; - } - return 0; -} - void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { if (!D) return; AdjustDeclIfTemplate(D); CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D); - CXXConstructorDecl *CtorDecl - = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl); - - if (!CtorDecl) return; - // Compute the exception specification for the default constructor. - const FunctionProtoType *CtorTy = - CtorDecl->getType()->castAs<FunctionProtoType>(); - if (CtorTy->getExceptionSpecType() == EST_Delayed) { - // FIXME: Don't do this unless the exception spec is needed. - ImplicitExceptionSpecification Spec = - ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - assert(EPI.ExceptionSpecType != EST_Delayed); - - CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); - } - - // If the default constructor is explicitly defaulted, checking the exception - // specification is deferred until now. - if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() && - !ClassDecl->isDependentType()) - CheckExplicitlyDefaultedDefaultConstructor(CtorDecl); + if (!ClassDecl->isDependentType()) + CheckExplicitlyDefaultedMethods(ClassDecl); } void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { @@ -7193,7 +7073,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. @@ -7240,14 +7122,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. - - ImplicitExceptionSpecification Spec = - ComputeDefaultedDtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); // Create the actual destructor declaration. - QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); - CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); SourceLocation ClassLoc = ClassDecl->getLocation(); @@ -7255,24 +7131,27 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0, - /*isInline=*/true, + = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + QualType(), 0, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setDefaulted(); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); - + + // Build an exception specification pointing back at this destructor. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = Destructor; + Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; - + // Introduce this destructor into its scope. if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(Destructor, S, false); ClassDecl->addDecl(Destructor); - - // This could be uniqued if it ever proves significant. - Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); AddOverriddenMethods(ClassDecl, Destructor); @@ -7309,7 +7188,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } SourceLocation Loc = Destructor->getLocation(); - Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); + Destructor->setBody(new (Context) CompoundStmt(Loc)); Destructor->setImplicitlyDefined(true); Destructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); @@ -7322,15 +7201,6 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, /// \brief Perform any semantic analysis which needs to be delayed until all /// pending class member declarations have been parsed. void Sema::ActOnFinishCXXMemberDecls() { - // Now we have parsed all exception specifications, determine the implicit - // exception specifications for destructors. - for (unsigned i = 0, e = DelayedDestructorExceptionSpecs.size(); - i != e; ++i) { - CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecs[i]; - AdjustDestructorExceptionSpec(Dtor->getParent(), Dtor, true); - } - DelayedDestructorExceptionSpecs.clear(); - // Perform any deferred checking of exception specifications for virtual // destructors. for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size(); @@ -7345,44 +7215,33 @@ void Sema::ActOnFinishCXXMemberDecls() { DelayedDestructorExceptionSpecChecks.clear(); } -void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, - CXXDestructorDecl *destructor, - bool WasDelayed) { +void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, + CXXDestructorDecl *Destructor) { + assert(getLangOpts().CPlusPlus0x && + "adjusting dtor exception specs was introduced in c++11"); + // C++11 [class.dtor]p3: // A declaration of a destructor that does not have an exception- // specification is implicitly considered to have the same exception- // specification as an implicit declaration. - const FunctionProtoType *dtorType = destructor->getType()-> + const FunctionProtoType *DtorType = Destructor->getType()-> getAs<FunctionProtoType>(); - if (!WasDelayed && dtorType->hasExceptionSpec()) + if (DtorType->hasExceptionSpec()) return; - ImplicitExceptionSpecification exceptSpec = - ComputeDefaultedDtorExceptionSpec(classDecl); - // Replace the destructor's type, building off the existing one. Fortunately, // the only thing of interest in the destructor type is its extended info. // The return and arguments are fixed. - FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo(); - epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); - epi.NumExceptions = exceptSpec.size(); - epi.Exceptions = exceptSpec.data(); - QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi); - - destructor->setType(ty); - - // If we can't compute the exception specification for this destructor yet - // (because it depends on an exception specification which we have not parsed - // yet), make a note that we need to try again when the class is complete. - if (epi.ExceptionSpecType == EST_Delayed) { - assert(!WasDelayed && "couldn't compute destructor exception spec"); - DelayedDestructorExceptionSpecs.push_back(destructor); - } + FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = Destructor; + Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this // change in behavior can break conforming C++03 programs at runtime. - // However, we don't have a body yet, so it needs to be done somewhere else. + // However, we don't have a body or an exception specification yet, so it + // needs to be done somewhere else. } /// \brief Builds a statement that copies/moves the given entity from \p From to @@ -7584,11 +7443,13 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Loc, Copy.take()); } -std::pair<Sema::ImplicitExceptionSpecification, bool> -Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( - CXXRecordDecl *ClassDecl) { +/// Determine whether an implicit copy assignment operator for ClassDecl has a +/// const argument. +/// FIXME: It ought to be possible to store this on the record. +static bool isImplicitCopyAssignmentArgConst(Sema &S, + CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(*this), false); + return true; // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy @@ -7599,37 +7460,34 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // X& X::operator=(const X&) // // if - bool HasConstCopyAssignment = true; - // -- each direct base class B of X has a copy assignment operator // whose parameter is of type const B&, const volatile B& or B, // and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); - HasConstCopyAssignment && Base != BaseEnd; ++Base) { + Base != BaseEnd; ++Base) { // We'll handle this below - if (LangOpts.CPlusPlus0x && Base->isVirtual()) + if (S.getLangOpts().CPlusPlus0x && Base->isVirtual()) continue; assert(!Base->getType()->isDependentType() && "Cannot generate implicit members for class with dependent bases."); CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - HasConstCopyAssignment &= - (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, - false, 0); + if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0)) + return false; } // In C++11, the above citation has "or virtual" added - if (LangOpts.CPlusPlus0x) { + if (S.getLangOpts().CPlusPlus0x) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); - HasConstCopyAssignment && Base != BaseEnd; ++Base) { + Base != BaseEnd; ++Base) { assert(!Base->getType()->isDependentType() && "Cannot generate implicit members for class with dependent bases."); CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - HasConstCopyAssignment &= - (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, - false, 0); + if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, + false, 0)) + return false; } } @@ -7639,23 +7497,36 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // const volatile M& or M. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); - HasConstCopyAssignment && Field != FieldEnd; - ++Field) { - QualType FieldType = Context.getBaseElementType((*Field)->getType()); - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - HasConstCopyAssignment &= - (bool)LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, - false, 0); - } + Field != FieldEnd; ++Field) { + QualType FieldType = S.Context.getBaseElementType(Field->getType()); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) + if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, + false, 0)) + return false; } // Otherwise, the implicitly declared copy assignment operator will // have the form // // X& X::operator=(X&) - + + return true; +} + +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + + ImplicitExceptionSpecification ExceptSpec(*this); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>(); + assert(T->getNumArgs() == 1 && "not a copy assignment op"); + unsigned ArgQuals = T->getArgType(0).getNonReferenceType().getCVRQualifiers(); + // C++ [except.spec]p14: - // An implicitly declared special member function (Clause 12) shall have an + // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] // It is unspecified whether or not an implicit copy assignment operator @@ -7664,8 +7535,6 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // Based on a similar decision made for constness in C++0x, we're erring on // the side of assuming such calls to be made regardless of whether they // actually happen. - ImplicitExceptionSpecification ExceptSpec(*this); - unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { @@ -7693,15 +7562,17 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { - QualType FieldType = Context.getBaseElementType((*Field)->getType()); + QualType FieldType = Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *CopyAssign = - LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0)) + LookupCopyingAssignment(FieldClassDecl, + ArgQuals | FieldType.getCVRQualifiers(), + false, 0)) ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign); } } - return std::make_pair(ExceptSpec, HasConstCopyAssignment); + return ExceptSpec; } CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { @@ -7710,26 +7581,19 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // for determining the argument type of the operator. Note also that // operators taking an object instead of a reference are allowed. - ImplicitExceptionSpecification Spec(*this); - bool Const; - llvm::tie(Spec, Const) = - ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl); - QualType ArgType = Context.getTypeDeclType(ClassDecl); QualType RetType = Context.getLValueReferenceType(ArgType); - if (Const) + if (isImplicitCopyAssignmentArgConst(*this, ClassDecl)) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); // An implicitly-declared copy assignment operator is an inline public // member of its class. - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *CopyAssignment - = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(RetType, &ArgType, 1, EPI), + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, /*isInline=*/true, /*isConstexpr=*/false, @@ -7738,7 +7602,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); - + + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = CopyAssignment; + CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI)); + // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassLoc, ClassLoc, /*Id=*/0, @@ -8076,9 +7946,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { - ImplicitExceptionSpecification ExceptSpec(*this); +Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -8103,7 +7974,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, - false, 0)) + 0, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } @@ -8113,7 +7984,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, - false, 0)) + 0, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } @@ -8121,10 +7992,12 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { - QualType FieldType = Context.getBaseElementType((*Field)->getType()); + QualType FieldType = Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl, - false, 0)) + if (CXXMethodDecl *MoveAssign = + LookupMovingAssignment(FieldClassDecl, + FieldType.getCVRQualifiers(), + false, 0)) ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign); } } @@ -8167,7 +8040,7 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) { // reference types, are supposed to return false here, but that appears // to be a standard defect. CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl(); - if (!ClassDecl) + if (!ClassDecl || !ClassDecl->getDefinition()) return true; if (Type.isTriviallyCopyableType(S.Context)) @@ -8209,7 +8082,7 @@ static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl *ClassDecl, for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { - if (!hasMoveOrIsTriviallyCopyable(S, (*Field)->getType(), IsConstructor)) + if (!hasMoveOrIsTriviallyCopyable(S, Field->getType(), IsConstructor)) return false; } @@ -8244,22 +8117,17 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { // Note: The following rules are largely analoguous to the move // constructor rules. - ImplicitExceptionSpecification Spec( - ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl)); - QualType ArgType = Context.getTypeDeclType(ClassDecl); QualType RetType = Context.getLValueReferenceType(ArgType); ArgType = Context.getRValueReferenceType(ArgType); // An implicitly-declared move assignment operator is an inline public // member of its class. - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *MoveAssignment - = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(RetType, &ArgType, 1, EPI), + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, /*isInline=*/true, @@ -8270,6 +8138,12 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { MoveAssignment->setImplicit(); MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment()); + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = MoveAssignment; + MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI)); + // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, ClassLoc, ClassLoc, /*Id=*/0, @@ -8620,10 +8494,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } } -std::pair<Sema::ImplicitExceptionSpecification, bool> -Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { +/// Determine whether an implicit copy constructor for ClassDecl has a const +/// argument. +/// FIXME: It ought to be possible to store this on the record. +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(*this), false); + return true; // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will @@ -8632,60 +8508,71 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { // X::X(const X&) // // if - // FIXME: It ought to be possible to store this on the record. - bool HasConstCopyConstructor = true; - // -- each direct or virtual base class B of X has a copy // constructor whose first parameter is of type const B& or // const volatile B&, and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); - HasConstCopyConstructor && Base != BaseEnd; - ++Base) { + Base != BaseEnd; ++Base) { // Virtual bases are handled below. if (Base->isVirtual()) continue; - + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - HasConstCopyConstructor &= - (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const); + // FIXME: This lookup is wrong. If the copy ctor for a member or base is + // ambiguous, we should still produce a constructor with a const-qualified + // parameter. + if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const)) + return false; } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); - HasConstCopyConstructor && Base != BaseEnd; - ++Base) { + Base != BaseEnd; ++Base) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - HasConstCopyConstructor &= - (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const); + if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const)) + return false; } - + // -- for all the nonstatic data members of X that are of a // class type M (or array thereof), each such class type // has a copy constructor whose first parameter is of type // const M& or const volatile M&. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); - HasConstCopyConstructor && Field != FieldEnd; - ++Field) { - QualType FieldType = Context.getBaseElementType((*Field)->getType()); + Field != FieldEnd; ++Field) { + QualType FieldType = S.Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - HasConstCopyConstructor &= - (bool)LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const); + if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const)) + return false; } } + // Otherwise, the implicitly declared copy constructor will have // the form // // X::X(X&) - + + return true; +} + +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + + ImplicitExceptionSpecification ExceptSpec(*this); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>(); + assert(T->getNumArgs() >= 1 && "not a copy ctor"); + unsigned Quals = T->getArgType(0).getNonReferenceType().getCVRQualifiers(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(*this); - unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; @@ -8714,15 +8601,16 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { - QualType FieldType = Context.getBaseElementType((*Field)->getType()); + QualType FieldType = Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXConstructorDecl *CopyConstructor = - LookupCopyingConstructor(FieldClassDecl, Quals)) + LookupCopyingConstructor(FieldClassDecl, + Quals | FieldType.getCVRQualifiers())) ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor); } } - return std::make_pair(ExceptSpec, HasConstCopyConstructor); + return ExceptSpec; } CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( @@ -8731,18 +8619,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // If the class definition does not explicitly declare a copy // constructor, one is declared implicitly. - ImplicitExceptionSpecification Spec(*this); - bool Const; - llvm::tie(Spec, Const) = - ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl); - QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; + bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl); if (Const) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + + bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, + CXXCopyConstructor, + Const); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( @@ -8753,15 +8639,20 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // An implicitly-declared copy constructor is an inline public // member of its class. CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create( - Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0, + Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, - /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() && - getLangOpts().CPlusPlus0x); + Constexpr); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = CopyConstructor; + CopyConstructor->setType( + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; @@ -8825,7 +8716,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -8842,7 +8735,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + CXXConstructorDecl *Constructor = + LookupMovingConstructor(BaseClassDecl, 0); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) @@ -8856,7 +8750,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + CXXConstructorDecl *Constructor = + LookupMovingConstructor(BaseClassDecl, 0); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) @@ -8868,10 +8763,10 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { - if (const RecordType *RecordTy - = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { - CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); - CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl); + QualType FieldType = Context.getBaseElementType(F->getType()); + if (CXXRecordDecl *FieldRecDecl = FieldType->getAsCXXRecordDecl()) { + CXXConstructorDecl *Constructor = + LookupMovingConstructor(FieldRecDecl, FieldType.getCVRQualifiers()); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. // In particular, the problem is that this function never gets called. It @@ -8906,13 +8801,12 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( return 0; } - ImplicitExceptionSpecification Spec( - ComputeDefaultedMoveCtorExceptionSpec(ClassDecl)); - QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = Context.getRValueReferenceType(ClassType); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + + bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, + CXXMoveConstructor, + false); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( @@ -8924,15 +8818,20 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( // An implicitly-declared copy/move constructor is an inline public // member of its class. CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create( - Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0, + Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, - /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() && - getLangOpts().CPlusPlus0x); + Constexpr); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor()); + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = MoveConstructor; + MoveConstructor->setType( + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, ClassLoc, ClassLoc, @@ -9046,8 +8945,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( // will fill in the actual details. Invoke->setUsed(); Invoke->setReferenced(); - Invoke->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(), - Conv->getLocation())); + Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation())); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); @@ -9171,13 +9069,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); - for (specific_attr_iterator<NonNullAttr> - i = Constructor->specific_attr_begin<NonNullAttr>(), - e = Constructor->specific_attr_end<NonNullAttr>(); i != e; ++i) { - const NonNullAttr *NonNull = *i; - CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc); - } - MarkFunctionReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, @@ -9243,7 +9134,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, - SourceLocation Loc, + SourceLocation Loc, ASTOwningVector<Expr*> &ConvertedArgs, bool AllowExplicit) { // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall. @@ -9271,7 +9162,8 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size()); - // FIXME: Missing call to CheckFunctionCall or equivalent + CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(), + Proto, Loc); return Invalid; } @@ -9329,7 +9221,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, diag::err_operator_new_delete_too_few_parameters) << FnDecl->getDeclName(); - // Check the the first parameter type is not dependent. + // Check the first parameter type is not dependent. QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); if (FirstParamType->isDependentType()) return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag) @@ -9568,7 +9460,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { TemplateParameterList *Params = TpDecl->getTemplateParameters(); if (Params->size() == 1) { NonTypeTemplateParmDecl *PmDecl = - cast<NonTypeTemplateParmDecl>(Params->getParam(0)); + dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(0)); // The template parameter must be a char parameter pack. if (PmDecl && PmDecl->isTemplateParameterPack() && @@ -9769,7 +9661,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Diag(Loc, diag::err_objc_object_catch); Invalid = true; } else if (T->isObjCObjectPointerType()) { - if (!getLangOpts().ObjCNonFragileABI) + // FIXME: should this be a test for macosx-fragile specifically? + if (getLangOpts().ObjCRuntime.isFragile()) Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile); } } @@ -9881,37 +9774,49 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, - Expr *AssertMessageExpr_, + Expr *AssertMessageExpr, SourceLocation RParenLoc) { - StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_); + StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr); - if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) { + if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) + return 0; + + return BuildStaticAssertDeclaration(StaticAssertLoc, AssertExpr, + AssertMessage, RParenLoc, false); +} + +Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, + Expr *AssertExpr, + StringLiteral *AssertMessage, + SourceLocation RParenLoc, + bool Failed) { + if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() && + !Failed) { // In a static_assert-declaration, the constant-expression shall be a // constant expression that can be contextually converted to bool. ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr); if (Converted.isInvalid()) - return 0; + Failed = true; llvm::APSInt Cond; - if (VerifyIntegerConstantExpression(Converted.get(), &Cond, - PDiag(diag::err_static_assert_expression_is_not_constant), + if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond, + diag::err_static_assert_expression_is_not_constant, /*AllowFold=*/false).isInvalid()) - return 0; + Failed = true; - if (!Cond) { + if (!Failed && !Cond) { llvm::SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); - AssertMessage->printPretty(Msg, Context, 0, getPrintingPolicy()); + AssertMessage->printPretty(Msg, 0, getPrintingPolicy()); Diag(StaticAssertLoc, diag::err_static_assert_failed) << Msg.str() << AssertExpr->getSourceRange(); + Failed = true; } } - if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) - return 0; - Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc, - AssertExpr, AssertMessage, RParenLoc); + AssertExpr, AssertMessage, RParenLoc, + Failed); CurContext->addDecl(Decl); return Decl; @@ -10116,7 +10021,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, /// friend class A<T>::B<unsigned>; /// We permit this as a special case; if there are any template /// parameters present at all, require proper matching, i.e. -/// template <> template <class T> friend class A<int>::B; +/// template <> template \<class T> friend class A<int>::B; Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TempParams) { SourceLocation Loc = DS.getLocStart(); @@ -10438,9 +10343,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, FrD->setAccess(AS_public); CurContext->addDecl(FrD); - if (ND->isInvalidDecl()) + if (ND->isInvalidDecl()) { FrD->setInvalidDecl(); - else { + } else { + if (DC->isRecord()) CheckFriendAccess(ND); + FunctionDecl *FD; if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND)) FD = FTD->getTemplatedDecl(); @@ -10464,8 +10371,13 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { return; } if (const FunctionDecl *Prev = Fn->getPreviousDecl()) { - Diag(DelLoc, diag::err_deleted_decl_not_first); - Diag(Prev->getLocation(), diag::note_previous_declaration); + // Don't consider the implicit declaration we generate for explicit + // specializations. FIXME: Do not generate these implicit declarations. + if ((Prev->getTemplateSpecializationKind() != TSK_ExplicitSpecialization + || Prev->getPreviousDecl()) && !Prev->isDefined()) { + Diag(DelLoc, diag::err_deleted_decl_not_first); + Diag(Prev->getLocation(), diag::note_previous_declaration); + } // If the declaration wasn't the first, we delete the function anyway for // recovery. } @@ -10531,10 +10443,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { if (Primary == Primary->getCanonicalDecl()) return; + CheckExplicitlyDefaultedSpecialMember(MD); + switch (Member) { case CXXDefaultConstructor: { CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); - CheckExplicitlyDefaultedDefaultConstructor(CD); if (!CD->isInvalidDecl()) DefineImplicitDefaultConstructor(DefaultLoc, CD); break; @@ -10542,14 +10455,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { case CXXCopyConstructor: { CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); - CheckExplicitlyDefaultedCopyConstructor(CD); if (!CD->isInvalidDecl()) DefineImplicitCopyConstructor(DefaultLoc, CD); break; } case CXXCopyAssignment: { - CheckExplicitlyDefaultedCopyAssignment(MD); if (!MD->isInvalidDecl()) DefineImplicitCopyAssignment(DefaultLoc, MD); break; @@ -10557,7 +10468,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { case CXXDestructor: { CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD); - CheckExplicitlyDefaultedDestructor(DD); if (!DD->isInvalidDecl()) DefineImplicitDestructor(DefaultLoc, DD); break; @@ -10565,14 +10475,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { case CXXMoveConstructor: { CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); - CheckExplicitlyDefaultedMoveConstructor(CD); if (!CD->isInvalidDecl()) DefineImplicitMoveConstructor(DefaultLoc, CD); break; } case CXXMoveAssignment: { - CheckExplicitlyDefaultedMoveAssignment(MD); if (!MD->isInvalidDecl()) DefineImplicitMoveAssignment(DefaultLoc, MD); break; @@ -10650,8 +10558,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, if (const RecordType *RT = NewClassTy->getAs<RecordType>()) { if (!RT->isBeingDefined() && RequireCompleteType(New->getLocation(), NewClassTy, - PDiag(diag::err_covariant_return_incomplete) - << New->getDeclName())) + diag::err_covariant_return_incomplete, + New->getDeclName())) return true; } @@ -10857,7 +10765,7 @@ bool Sema::DefineUsedVTables() { // Note: The VTableUses vector could grow as a result of marking // the members of a class as "used", so we check the size each - // time through the loop and prefer indices (with are stable) to + // time through the loop and prefer indices (which are stable) to // iterators (which are not). bool DefinedAnything = false; for (unsigned I = 0; I != VTableUses.size(); ++I) { @@ -10867,6 +10775,8 @@ bool Sema::DefineUsedVTables() { SourceLocation Loc = VTableUses[I].second; + bool DefineVTable = true; + // If this class has a key function, but that key function is // defined in another translation unit, we don't need to emit the // vtable even though we're using it. @@ -10877,7 +10787,8 @@ bool Sema::DefineUsedVTables() { case TSK_ExplicitSpecialization: case TSK_ExplicitInstantiationDeclaration: // The key function is in another translation unit. - continue; + DefineVTable = false; + break; case TSK_ExplicitInstantiationDefinition: case TSK_ImplicitInstantiation: @@ -10906,7 +10817,15 @@ bool Sema::DefineUsedVTables() { } if (IsExplicitInstantiationDeclaration) - continue; + DefineVTable = false; + } + + // The exception specifications for all virtual members may be needed even + // if we are not providing an authoritative form of the vtable in this TU. + // We may choose to emit it available_externally anyway. + if (!DefineVTable) { + MarkVirtualMemberExceptionSpecsNeeded(Loc, Class); + continue; } // Mark all of the virtual members of this class as referenced, so @@ -10935,6 +10854,14 @@ bool Sema::DefineUsedVTables() { return DefinedAnything; } +void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, + const CXXRecordDecl *RD) { + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) + if ((*I)->isVirtual() && !(*I)->isPure()) + ResolveExceptionSpec(Loc, (*I)->getType()->castAs<FunctionProtoType>()); +} + void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD) { // Mark all functions which will appear in RD's vtable as used. @@ -11171,8 +11098,8 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { switch (Proto->getExceptionSpecType()) { case EST_Uninstantiated: + case EST_Unevaluated: case EST_BasicNoexcept: - case EST_Delayed: case EST_DynamicNone: case EST_MSAny: case EST_None: @@ -11299,7 +11226,7 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST, if (!NoexceptExpr->isValueDependent()) NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0, - PDiag(diag::err_noexcept_needs_constant_expression), + diag::err_noexcept_needs_constant_expression, /*AllowFold*/ false).take(); EPI.NoexceptExpr = NoexceptExpr; } |