diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp | 1429 |
1 files changed, 766 insertions, 663 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index f265f4c..c05e5f0 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -467,7 +467,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // If only one of these is a local function declaration, then they are // declared in different scopes, even though isDeclInScope may think // they're in the same scope. (If both are local, the scope check is - // sufficent, and if neither is local, then they are in the same scope.) + // sufficient, and if neither is local, then they are in the same scope.) continue; } @@ -547,17 +547,23 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Diag(OldParam->getLocation(), diag::note_previous_definition) << OldParam->getDefaultArgRange(); } else if (OldParamHasDfl) { - // Merge the old default argument into the new parameter. - // It's important to use getInit() here; getDefaultArg() - // strips off any top-level ExprWithCleanups. - NewParam->setHasInheritedDefaultArg(); - if (OldParam->hasUnparsedDefaultArg()) - NewParam->setUnparsedDefaultArg(); - else if (OldParam->hasUninstantiatedDefaultArg()) - NewParam->setUninstantiatedDefaultArg( - OldParam->getUninstantiatedDefaultArg()); - else - NewParam->setDefaultArg(OldParam->getInit()); + // Merge the old default argument into the new parameter unless the new + // function is a friend declaration in a template class. In the latter + // case the default arguments will be inherited when the friend + // declaration will be instantiated. + if (New->getFriendObjectKind() == Decl::FOK_None || + !New->getLexicalDeclContext()->isDependentContext()) { + // It's important to use getInit() here; getDefaultArg() + // strips off any top-level ExprWithCleanups. + NewParam->setHasInheritedDefaultArg(); + if (OldParam->hasUnparsedDefaultArg()) + NewParam->setUnparsedDefaultArg(); + else if (OldParam->hasUninstantiatedDefaultArg()) + NewParam->setUninstantiatedDefaultArg( + OldParam->getUninstantiatedDefaultArg()); + else + NewParam->setDefaultArg(OldParam->getInit()); + } } else if (NewParamHasDfl) { if (New->getDescribedFunctionTemplate()) { // Paragraph 4, quoted above, only applies to non-template functions. @@ -638,7 +644,12 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Diag(Old->getLocation(), diag::note_previous_declaration); Invalid = true; } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && - Old->isDefined(Def)) { + Old->isDefined(Def) && + // If a friend function is inlined but does not have 'inline' + // specifier, it is a definition. Do not report attribute conflict + // in this case, redefinition will be diagnosed later. + (New->isInlineSpecified() || + New->getFriendObjectKind() == Decl::FOK_None)) { // C++11 [dcl.fcn.spec]p4: // If the definition of a function appears in a translation unit before its // first declaration as inline, the program is ill-formed. @@ -647,6 +658,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Invalid = true; } + // FIXME: It's not clear what should happen if multiple declarations of a + // deduction guide have different explicitness. For now at least we simply + // reject any case where the explicitness changes. + auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New); + if (NewGuide && NewGuide->isExplicitSpecified() != + cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) { + Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch) + << NewGuide->isExplicitSpecified(); + Diag(Old->getLocation(), diag::note_previous_declaration); + } + // C++11 [dcl.fct.default]p4: If a friend declaration specifies a default // argument expression, that declaration shall be a definition and shall be // the only declaration of the function or function template in the @@ -970,7 +992,8 @@ namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; } static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, llvm::APSInt &Size) { - EnterExpressionEvaluationContext ContextRAII(S, Sema::ConstantEvaluated); + EnterExpressionEvaluationContext ContextRAII( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); DeclarationName Value = S.PP.getIdentifierInfo("value"); LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName); @@ -2705,8 +2728,7 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>()) return; CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); - if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>() || - isa<CXXDestructorDecl>(MD)) + if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>()) return; SourceLocation Loc = MD->getLocation(); @@ -2716,10 +2738,12 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { SpellingLoc = getSourceManager().getSpellingLoc(SpellingLoc); if (SpellingLoc.isValid() && getSourceManager().isInSystemHeader(SpellingLoc)) return; - + if (MD->size_overridden_methods() > 0) { - Diag(MD->getLocation(), diag::warn_function_marked_not_override_overriding) - << MD->getDeclName(); + unsigned DiagID = isa<CXXDestructorDecl>(MD) + ? diag::warn_destructor_marked_not_override_overriding + : diag::warn_function_marked_not_override_overriding; + Diag(MD->getLocation(), DiagID) << MD->getDeclName(); const CXXMethodDecl *OMD = *MD->begin_overridden_methods(); Diag(OMD->getLocation(), diag::note_overridden_virtual_function); } @@ -2758,6 +2782,56 @@ static AttributeList *getMSPropertyAttr(AttributeList *list) { return nullptr; } +// Check if there is a field shadowing. +void Sema::CheckShadowInheritedFields(const SourceLocation &Loc, + DeclarationName FieldName, + const CXXRecordDecl *RD) { + if (Diags.isIgnored(diag::warn_shadow_field, Loc)) + return; + + // To record a shadowed field in a base + std::map<CXXRecordDecl*, NamedDecl*> Bases; + auto FieldShadowed = [&](const CXXBaseSpecifier *Specifier, + CXXBasePath &Path) { + const auto Base = Specifier->getType()->getAsCXXRecordDecl(); + // Record an ambiguous path directly + if (Bases.find(Base) != Bases.end()) + return true; + for (const auto Field : Base->lookup(FieldName)) { + if ((isa<FieldDecl>(Field) || isa<IndirectFieldDecl>(Field)) && + Field->getAccess() != AS_private) { + assert(Field->getAccess() != AS_none); + assert(Bases.find(Base) == Bases.end()); + Bases[Base] = Field; + return true; + } + } + return false; + }; + + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/true); + if (!RD->lookupInBases(FieldShadowed, Paths)) + return; + + for (const auto &P : Paths) { + auto Base = P.back().Base->getType()->getAsCXXRecordDecl(); + auto It = Bases.find(Base); + // Skip duplicated bases + if (It == Bases.end()) + continue; + auto BaseField = It->second; + assert(BaseField->getAccess() != AS_private); + if (AS_none != + CXXRecordDecl::MergeAccess(P.Access, BaseField->getAccess())) { + Diag(Loc, diag::warn_shadow_field) + << FieldName.getAsString() << RD->getName() << Base->getName(); + Diag(BaseField->getLocation(), diag::note_shadow_field); + Bases.erase(It); + } + } +} + /// 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 @@ -2957,6 +3031,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (!Member) return nullptr; } + + CheckShadowInheritedFields(Loc, Name, cast<CXXRecordDecl>(CurContext)); } else { Member = HandleDeclarator(S, D, TemplateParameterLists); if (!Member) @@ -3673,6 +3749,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD, BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo); } else if (DS.getTypeSpecType() == TST_decltype) { BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + } else if (DS.getTypeSpecType() == TST_decltype_auto) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); + return true; } else { LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); LookupParsedName(R, S, &SS); @@ -3699,6 +3778,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (BaseType.isNull()) return true; + TInfo = Context.CreateTypeSourceInfo(BaseType); + DependentNameTypeLoc TL = + TInfo->getTypeLoc().castAs<DependentNameTypeLoc>(); + if (!TL.isNull()) { + TL.setNameLoc(IdLoc); + TL.setElaboratedKeywordLoc(SourceLocation()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); + } + R.clear(); R.setLookupName(MemberOrBase); } @@ -4332,11 +4420,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, } } - if (SemaRef.getLangOpts().ObjCAutoRefCount && - FieldBaseElementType->isObjCRetainableType() && - FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None && - FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { - // ARC: + if (FieldBaseElementType.hasNonTrivialObjCLifetime()) { + // ARC and Weak: // Default-initialize Objective-C pointers to NULL. CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, @@ -5015,6 +5100,10 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, DiagnoseUseOfDecl(Dtor, Location); } + // We only potentially invoke the destructors of potentially constructed + // subobjects. + bool VisitVirtualBases = !ClassDecl->isAbstract(); + llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases; // Bases. @@ -5023,8 +5112,11 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, const RecordType *RT = Base.getType()->getAs<RecordType>(); // Remember direct virtual bases. - if (Base.isVirtual()) + if (Base.isVirtual()) { + if (!VisitVirtualBases) + continue; DirectVirtualBases.insert(RT); + } CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); // If our base class is invalid, we probably can't get its dtor anyway. @@ -5046,6 +5138,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, MarkFunctionReferenced(Location, Dtor); DiagnoseUseOfDecl(Dtor, Location); } + + if (!VisitVirtualBases) + return; // Virtual bases. for (const auto &VBase : ClassDecl->vbases()) { @@ -5378,7 +5473,7 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { // Synthesize and instantiate non-trivial implicit methods, explicitly // defaulted methods, and the copy and move assignment operators. The // latter are exported even if they are trivial, because the address of - // an operator can be taken and should compare equal accross libraries. + // an operator can be taken and should compare equal across libraries. DiagnosticErrorTrap Trap(S.Diags); S.MarkFunctionReferenced(Class->getLocation(), MD); if (Trap.hasErrorOccurred()) { @@ -5631,6 +5726,53 @@ static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD, } } +/// Determine whether a type is permitted to be passed or returned in +/// registers, per C++ [class.temporary]p3. +static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { + if (D->isDependentType() || D->isInvalidDecl()) + return false; + + // Per C++ [class.temporary]p3, the relevant condition is: + // each copy constructor, move constructor, and destructor of X is + // either trivial or deleted, and X has at least one non-deleted copy + // or move constructor + bool HasNonDeletedCopyOrMove = false; + + if (D->needsImplicitCopyConstructor() && + !D->defaultedCopyConstructorIsDeleted()) { + if (!D->hasTrivialCopyConstructor()) + return false; + HasNonDeletedCopyOrMove = true; + } + + if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() && + !D->defaultedMoveConstructorIsDeleted()) { + if (!D->hasTrivialMoveConstructor()) + return false; + HasNonDeletedCopyOrMove = true; + } + + if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() && + !D->hasTrivialDestructor()) + return false; + + for (const CXXMethodDecl *MD : D->methods()) { + if (MD->isDeleted()) + continue; + + auto *CD = dyn_cast<CXXConstructorDecl>(MD); + if (CD && CD->isCopyOrMoveConstructor()) + HasNonDeletedCopyOrMove = true; + else if (!isa<CXXDestructorDecl>(MD)) + continue; + + if (!MD->isTrivial()) + return false; + } + + return HasNonDeletedCopyOrMove; +} + /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -5775,6 +5917,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } checkClassLevelDLLAttribute(Record); + + Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record)); } /// Look up the special member function that would be called by a special @@ -5786,7 +5930,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { /// \param ConstRHS True if this is a copy operation with a const object /// on its RHS, that is, if the argument to the outer special member /// function is 'const' and this is not a field marked 'mutable'. -static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember( +static Sema::SpecialMemberOverloadResult lookupCallFromSpecialMember( Sema &S, CXXRecordDecl *Class, Sema::CXXSpecialMember CSM, unsigned FieldQuals, bool ConstRHS) { unsigned LHSQuals = 0; @@ -5909,13 +6053,13 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, if (CSM == Sema::CXXDefaultConstructor) return ClassDecl->hasConstexprDefaultConstructor(); - Sema::SpecialMemberOverloadResult *SMOR = + Sema::SpecialMemberOverloadResult SMOR = lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS); - if (!SMOR || !SMOR->getMethod()) + if (!SMOR.getMethod()) // A constructor we wouldn't select can't be "involved in initializing" // anything. return true; - return SMOR->getMethod()->isConstexpr(); + return SMOR.getMethod()->isConstexpr(); } /// Determine whether the specified special member function would be constexpr @@ -6025,27 +6169,23 @@ static bool defaultedSpecialMemberIsConstexpr( } static Sema::ImplicitExceptionSpecification +ComputeDefaultedSpecialMemberExceptionSpec( + Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI); + +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; - } - assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() && + auto CSM = S.getSpecialMember(MD); + if (CSM != Sema::CXXInvalid) + return ComputeDefaultedSpecialMemberExceptionSpec(S, Loc, MD, CSM, nullptr); + + auto *CD = cast<CXXConstructorDecl>(MD); + assert(CD->getInheritedConstructor() && "only special members have implicit exception specs"); - return S.ComputeInheritingCtorExceptionSpec(Loc, - cast<CXXConstructorDecl>(MD)); + Sema::InheritedConstructorInfo ICI( + S, Loc, CD->getInheritedConstructor().getShadowDecl()); + return ComputeDefaultedSpecialMemberExceptionSpec( + S, Loc, CD, Sema::CXXDefaultConstructor, &ICI); } static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S, @@ -6300,45 +6440,35 @@ void Sema::CheckDelayedMemberExceptionSpecs() { } namespace { -struct SpecialMemberDeletionInfo { +/// CRTP base class for visiting operations performed by a special member +/// function (or inherited constructor). +template<typename Derived> +struct SpecialMemberVisitor { Sema &S; CXXMethodDecl *MD; Sema::CXXSpecialMember CSM; Sema::InheritedConstructorInfo *ICI; - bool Diagnose; // Properties of the special member, computed for convenience. - bool IsConstructor, IsAssignment, IsMove, ConstArg; - SourceLocation Loc; - - bool AllFieldsAreConst; + bool IsConstructor = false, IsAssignment = false, ConstArg = false; - SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD, - Sema::CXXSpecialMember CSM, - Sema::InheritedConstructorInfo *ICI, bool Diagnose) - : S(S), MD(MD), CSM(CSM), ICI(ICI), Diagnose(Diagnose), - IsConstructor(false), IsAssignment(false), IsMove(false), - ConstArg(false), Loc(MD->getLocation()), AllFieldsAreConst(true) { + SpecialMemberVisitor(Sema &S, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI) + : S(S), MD(MD), CSM(CSM), ICI(ICI) { switch (CSM) { - case Sema::CXXDefaultConstructor: - case Sema::CXXCopyConstructor: - IsConstructor = true; - break; - case Sema::CXXMoveConstructor: - IsConstructor = true; - IsMove = true; - break; - case Sema::CXXCopyAssignment: - IsAssignment = true; - break; - case Sema::CXXMoveAssignment: - IsAssignment = true; - IsMove = true; - break; - case Sema::CXXDestructor: - break; - case Sema::CXXInvalid: - llvm_unreachable("invalid special member kind"); + case Sema::CXXDefaultConstructor: + case Sema::CXXCopyConstructor: + case Sema::CXXMoveConstructor: + IsConstructor = true; + break; + case Sema::CXXCopyAssignment: + case Sema::CXXMoveAssignment: + IsAssignment = true; + break; + case Sema::CXXDestructor: + break; + case Sema::CXXInvalid: + llvm_unreachable("invalid special member kind"); } if (MD->getNumParams()) { @@ -6348,21 +6478,109 @@ struct SpecialMemberDeletionInfo { } } - bool inUnion() const { return MD->getParent()->isUnion(); } + Derived &getDerived() { return static_cast<Derived&>(*this); } - Sema::CXXSpecialMember getEffectiveCSM() { - return ICI ? Sema::CXXInvalid : CSM; + /// Is this a "move" special member? + bool isMove() const { + return CSM == Sema::CXXMoveConstructor || CSM == Sema::CXXMoveAssignment; } /// Look up the corresponding special member in the given class. - Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class, - unsigned Quals, bool IsMutable) { + Sema::SpecialMemberOverloadResult lookupIn(CXXRecordDecl *Class, + unsigned Quals, bool IsMutable) { return lookupCallFromSpecialMember(S, Class, CSM, Quals, ConstArg && !IsMutable); } + /// Look up the constructor for the specified base class to see if it's + /// overridden due to this being an inherited constructor. + Sema::SpecialMemberOverloadResult lookupInheritedCtor(CXXRecordDecl *Class) { + if (!ICI) + return {}; + assert(CSM == Sema::CXXDefaultConstructor); + auto *BaseCtor = + cast<CXXConstructorDecl>(MD)->getInheritedConstructor().getConstructor(); + if (auto *MD = ICI->findConstructorForBase(Class, BaseCtor).first) + return MD; + return {}; + } + + /// A base or member subobject. typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject; + /// Get the location to use for a subobject in diagnostics. + static SourceLocation getSubobjectLoc(Subobject Subobj) { + // FIXME: For an indirect virtual base, the direct base leading to + // the indirect virtual base would be a more useful choice. + if (auto *B = Subobj.dyn_cast<CXXBaseSpecifier*>()) + return B->getBaseTypeLoc(); + else + return Subobj.get<FieldDecl*>()->getLocation(); + } + + enum BasesToVisit { + /// Visit all non-virtual (direct) bases. + VisitNonVirtualBases, + /// Visit all direct bases, virtual or not. + VisitDirectBases, + /// Visit all non-virtual bases, and all virtual bases if the class + /// is not abstract. + VisitPotentiallyConstructedBases, + /// Visit all direct or virtual bases. + VisitAllBases + }; + + // Visit the bases and members of the class. + bool visit(BasesToVisit Bases) { + CXXRecordDecl *RD = MD->getParent(); + + if (Bases == VisitPotentiallyConstructedBases) + Bases = RD->isAbstract() ? VisitNonVirtualBases : VisitAllBases; + + for (auto &B : RD->bases()) + if ((Bases == VisitDirectBases || !B.isVirtual()) && + getDerived().visitBase(&B)) + return true; + + if (Bases == VisitAllBases) + for (auto &B : RD->vbases()) + if (getDerived().visitBase(&B)) + return true; + + for (auto *F : RD->fields()) + if (!F->isInvalidDecl() && !F->isUnnamedBitfield() && + getDerived().visitField(F)) + return true; + + return false; + } +}; +} + +namespace { +struct SpecialMemberDeletionInfo + : SpecialMemberVisitor<SpecialMemberDeletionInfo> { + bool Diagnose; + + SourceLocation Loc; + + bool AllFieldsAreConst; + + SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD, + Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI, bool Diagnose) + : SpecialMemberVisitor(S, MD, CSM, ICI), Diagnose(Diagnose), + Loc(MD->getLocation()), AllFieldsAreConst(true) {} + + bool inUnion() const { return MD->getParent()->isUnion(); } + + Sema::CXXSpecialMember getEffectiveCSM() { + return ICI ? Sema::CXXInvalid : CSM; + } + + bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); } + bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); } + bool shouldDeleteForBase(CXXBaseSpecifier *Base); bool shouldDeleteForField(FieldDecl *FD); bool shouldDeleteForAllConstMembers(); @@ -6370,7 +6588,7 @@ struct SpecialMemberDeletionInfo { bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj, unsigned Quals); bool shouldDeleteForSubobjectCall(Subobject Subobj, - Sema::SpecialMemberOverloadResult *SMOR, + Sema::SpecialMemberOverloadResult SMOR, bool IsDtorCallInCtor); bool isAccessible(Subobject Subobj, CXXMethodDecl *D); @@ -6400,16 +6618,16 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj, /// Check whether we should delete a special member due to the implicit /// definition containing a call to a special member of a subobject. bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( - Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR, + Subobject Subobj, Sema::SpecialMemberOverloadResult SMOR, bool IsDtorCallInCtor) { - CXXMethodDecl *Decl = SMOR->getMethod(); + CXXMethodDecl *Decl = SMOR.getMethod(); FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>(); int DiagKind = -1; - if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) + if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) DiagKind = !Decl ? 0 : 1; - else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous) + else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous) DiagKind = 2; else if (!isAccessible(Subobj, Decl)) DiagKind = 3; @@ -6479,7 +6697,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( // -- any direct or virtual base class or non-static data member has a // type with a destructor that is deleted or inaccessible if (IsConstructor) { - Sema::SpecialMemberOverloadResult *SMOR = + Sema::SpecialMemberOverloadResult SMOR = S.LookupSpecialMember(Class, Sema::CXXDestructor, false, false, false, false, false); if (shouldDeleteForSubobjectCall(Subobj, SMOR, true)) @@ -6499,23 +6717,20 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { return false; // If we have an inheriting constructor, check whether we're calling an // inherited constructor instead of a default constructor. - if (ICI) { - assert(CSM == Sema::CXXDefaultConstructor); - auto *BaseCtor = - ICI->findConstructorForBase(BaseClass, cast<CXXConstructorDecl>(MD) - ->getInheritedConstructor() - .getConstructor()) - .first; - if (BaseCtor) { - if (BaseCtor->isDeleted() && Diagnose) { - S.Diag(Base->getLocStart(), - diag::note_deleted_special_member_class_subobject) - << getEffectiveCSM() << MD->getParent() << /*IsField*/false - << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false; - S.NoteDeletedFunction(BaseCtor); - } - return BaseCtor->isDeleted(); + Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass); + if (auto *BaseCtor = SMOR.getMethod()) { + // Note that we do not check access along this path; other than that, + // this is the same as shouldDeleteForSubobjectCall(Base, BaseCtor, false); + // FIXME: Check that the base has a usable destructor! Sink this into + // shouldDeleteForClassSubobject. + if (BaseCtor->isDeleted() && Diagnose) { + S.Diag(Base->getLocStart(), + diag::note_deleted_special_member_class_subobject) + << getEffectiveCSM() << MD->getParent() << /*IsField*/false + << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false; + S.NoteDeletedFunction(BaseCtor); } + return BaseCtor->isDeleted(); } return shouldDeleteForClassSubobject(BaseClass, Base, 0); } @@ -6564,7 +6779,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (FieldType->isReferenceType()) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_assign_field) - << IsMove << MD->getParent() << FD << FieldType << /*Reference*/0; + << isMove() << MD->getParent() << FD << FieldType << /*Reference*/0; return true; } if (!FieldRecord && FieldType.isConstQualified()) { @@ -6572,7 +6787,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 << FD->getType() << /*Const*/1; + << isMove() << MD->getParent() << FD << FD->getType() << /*Const*/1; return true; } } @@ -6743,24 +6958,15 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose); - for (auto &BI : RD->bases()) - if ((SMI.IsAssignment || !BI.isVirtual()) && - SMI.shouldDeleteForBase(&BI)) - return true; - // Per DR1611, do not consider virtual bases of constructors of abstract - // classes, since we are not going to construct them. For assignment - // operators, we only assign (and thus only consider) direct bases. - if ((!RD->isAbstract() || !SMI.IsConstructor) && !SMI.IsAssignment) { - for (auto &BI : RD->vbases()) - if (SMI.shouldDeleteForBase(&BI)) - return true; - } - - for (auto *FI : RD->fields()) - if (!FI->isInvalidDecl() && !FI->isUnnamedBitfield() && - SMI.shouldDeleteForField(FI)) - return true; + // classes, since we are not going to construct them. + // Per DR1658, do not consider virtual bases of destructors of abstract + // classes either. + // Per DR2180, for assignment operators we only assign (and thus only + // consider) direct bases. + if (SMI.visit(SMI.IsAssignment ? SMI.VisitDirectBases + : SMI.VisitPotentiallyConstructedBases)) + return true; if (SMI.shouldDeleteForAllConstMembers()) return true; @@ -6874,18 +7080,18 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, case Sema::CXXMoveConstructor: case Sema::CXXMoveAssignment: NeedOverloadResolution: - Sema::SpecialMemberOverloadResult *SMOR = + Sema::SpecialMemberOverloadResult SMOR = lookupCallFromSpecialMember(S, RD, CSM, Quals, ConstRHS); // The standard doesn't describe how to behave if the lookup is ambiguous. // We treat it as not making the member non-trivial, just like the standard // mandates for the default constructor. This should rarely matter, because // the member will also be deleted. - if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous) + if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous) return true; - if (!SMOR->getMethod()) { - assert(SMOR->getKind() == + if (!SMOR.getMethod()) { + assert(SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted); return false; } @@ -6893,8 +7099,8 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // We deliberately don't check if we found a deleted special member. We're // not supposed to! if (Selected) - *Selected = SMOR->getMethod(); - return SMOR->getMethod()->isTrivial(); + *Selected = SMOR.getMethod(); + return SMOR.getMethod()->isTrivial(); } llvm_unreachable("unknown special method kind"); @@ -7009,8 +7215,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, // [...] nontrivally ownership-qualified types are [...] not trivially // default constructible, copy constructible, move constructible, copy // assignable, move assignable, or destructible [...] - if (S.getLangOpts().ObjCAutoRefCount && - FieldType.hasNonTrivialObjCLifetime()) { + if (FieldType.hasNonTrivialObjCLifetime()) { if (Diagnose) S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership) << RD << FieldType.getObjCLifetime(); @@ -7340,8 +7545,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, reinterpret_cast<Decl**>(FieldCollector->getCurFields()), FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); - CheckCompletedCXXClass( - dyn_cast_or_null<CXXRecordDecl>(TagDecl)); + CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl)); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared @@ -8033,6 +8237,154 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { return Conversion; } +namespace { +/// Utility class to accumulate and print a diagnostic listing the invalid +/// specifier(s) on a declaration. +struct BadSpecifierDiagnoser { + BadSpecifierDiagnoser(Sema &S, SourceLocation Loc, unsigned DiagID) + : S(S), Diagnostic(S.Diag(Loc, DiagID)) {} + ~BadSpecifierDiagnoser() { + Diagnostic << Specifiers; + } + + template<typename T> void check(SourceLocation SpecLoc, T Spec) { + return check(SpecLoc, DeclSpec::getSpecifierName(Spec)); + } + void check(SourceLocation SpecLoc, DeclSpec::TST Spec) { + return check(SpecLoc, + DeclSpec::getSpecifierName(Spec, S.getPrintingPolicy())); + } + void check(SourceLocation SpecLoc, const char *Spec) { + if (SpecLoc.isInvalid()) return; + Diagnostic << SourceRange(SpecLoc, SpecLoc); + if (!Specifiers.empty()) Specifiers += " "; + Specifiers += Spec; + } + + Sema &S; + Sema::SemaDiagnosticBuilder Diagnostic; + std::string Specifiers; +}; +} + +/// Check the validity of a declarator that we parsed for a deduction-guide. +/// These aren't actually declarators in the grammar, so we need to check that +/// the user didn't specify any pieces that are not part of the deduction-guide +/// grammar. +void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, + StorageClass &SC) { + TemplateName GuidedTemplate = D.getName().TemplateName.get().get(); + TemplateDecl *GuidedTemplateDecl = GuidedTemplate.getAsTemplateDecl(); + assert(GuidedTemplateDecl && "missing template decl for deduction guide"); + + // C++ [temp.deduct.guide]p3: + // A deduction-gide shall be declared in the same scope as the + // corresponding class template. + if (!CurContext->getRedeclContext()->Equals( + GuidedTemplateDecl->getDeclContext()->getRedeclContext())) { + Diag(D.getIdentifierLoc(), diag::err_deduction_guide_wrong_scope) + << GuidedTemplateDecl; + Diag(GuidedTemplateDecl->getLocation(), diag::note_template_decl_here); + } + + auto &DS = D.getMutableDeclSpec(); + // We leave 'friend' and 'virtual' to be rejected in the normal way. + if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() || + DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() || + DS.isNoreturnSpecified() || DS.isConstexprSpecified() || + DS.isConceptSpecified()) { + BadSpecifierDiagnoser Diagnoser( + *this, D.getIdentifierLoc(), + diag::err_deduction_guide_invalid_specifier); + + Diagnoser.check(DS.getStorageClassSpecLoc(), DS.getStorageClassSpec()); + DS.ClearStorageClassSpecs(); + SC = SC_None; + + // 'explicit' is permitted. + Diagnoser.check(DS.getInlineSpecLoc(), "inline"); + Diagnoser.check(DS.getNoreturnSpecLoc(), "_Noreturn"); + Diagnoser.check(DS.getConstexprSpecLoc(), "constexpr"); + Diagnoser.check(DS.getConceptSpecLoc(), "concept"); + DS.ClearConstexprSpec(); + DS.ClearConceptSpec(); + + Diagnoser.check(DS.getConstSpecLoc(), "const"); + Diagnoser.check(DS.getRestrictSpecLoc(), "__restrict"); + Diagnoser.check(DS.getVolatileSpecLoc(), "volatile"); + Diagnoser.check(DS.getAtomicSpecLoc(), "_Atomic"); + Diagnoser.check(DS.getUnalignedSpecLoc(), "__unaligned"); + DS.ClearTypeQualifiers(); + + Diagnoser.check(DS.getTypeSpecComplexLoc(), DS.getTypeSpecComplex()); + Diagnoser.check(DS.getTypeSpecSignLoc(), DS.getTypeSpecSign()); + Diagnoser.check(DS.getTypeSpecWidthLoc(), DS.getTypeSpecWidth()); + Diagnoser.check(DS.getTypeSpecTypeLoc(), DS.getTypeSpecType()); + DS.ClearTypeSpecType(); + } + + if (D.isInvalidType()) + return; + + // Check the declarator is simple enough. + bool FoundFunction = false; + for (const DeclaratorChunk &Chunk : llvm::reverse(D.type_objects())) { + if (Chunk.Kind == DeclaratorChunk::Paren) + continue; + if (Chunk.Kind != DeclaratorChunk::Function || FoundFunction) { + Diag(D.getDeclSpec().getLocStart(), + diag::err_deduction_guide_with_complex_decl) + << D.getSourceRange(); + break; + } + if (!Chunk.Fun.hasTrailingReturnType()) { + Diag(D.getName().getLocStart(), + diag::err_deduction_guide_no_trailing_return_type); + break; + } + + // Check that the return type is written as a specialization of + // the template specified as the deduction-guide's name. + ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType(); + TypeSourceInfo *TSI = nullptr; + QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI); + assert(TSI && "deduction guide has valid type but invalid return type?"); + bool AcceptableReturnType = false; + bool MightInstantiateToSpecialization = false; + if (auto RetTST = + TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) { + TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); + bool TemplateMatches = + Context.hasSameTemplateName(SpecifiedName, GuidedTemplate); + if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches) + AcceptableReturnType = true; + else { + // This could still instantiate to the right type, unless we know it + // names the wrong class template. + auto *TD = SpecifiedName.getAsTemplateDecl(); + MightInstantiateToSpecialization = !(TD && isa<ClassTemplateDecl>(TD) && + !TemplateMatches); + } + } else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) { + MightInstantiateToSpecialization = true; + } + + if (!AcceptableReturnType) { + Diag(TSI->getTypeLoc().getLocStart(), + diag::err_deduction_guide_bad_trailing_return_type) + << GuidedTemplate << TSI->getType() << MightInstantiateToSpecialization + << TSI->getTypeLoc().getSourceRange(); + } + + // Keep going to check that we don't have any inner declarator pieces (we + // could still have a function returning a pointer to a function). + FoundFunction = true; + } + + if (D.isFunctionDefinition()) + Diag(D.getIdentifierLoc(), diag::err_deduction_guide_defines_function); +} + //===----------------------------------------------------------------------===// // Namespace Handling //===----------------------------------------------------------------------===// @@ -8161,6 +8513,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, Namespc->setInvalidDecl(); ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); + AddPragmaAttributes(DeclRegionScope, Namespc); // FIXME: Should we be merging attributes? if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>()) @@ -8397,7 +8750,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) { CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); } -bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) { +bool Sema::isInitListConstructor(const FunctionDecl *Ctor) { // C++ [dcl.init.list]p2: // A constructor is an initializer-list constructor if its first parameter // is of type std::initializer_list<E> or reference to possibly cv-qualified @@ -8613,6 +8966,9 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, Diag(Name.getLocStart(), diag::err_using_decl_template_id) << SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc); return nullptr; + + case UnqualifiedId::IK_DeductionGuideName: + llvm_unreachable("cannot parse qualified deduction guide name"); } DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); @@ -9169,15 +9525,18 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, HasTypenameKeyword, IsInstantiation, SS.getScopeRep(), dyn_cast<CXXRecordDecl>(CurContext)), CTK_ErrorRecovery)) { - // We reject any correction for which ND would be NULL. - NamedDecl *ND = Corrected.getCorrectionDecl(); - // We reject candidates where DroppedSpecifier == true, hence the // literal '0' below. diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest) << NameInfo.getName() << LookupContext << 0 << SS.getRange()); + // If we picked a correction with no attached Decl we can't do anything + // useful with it, bail out. + NamedDecl *ND = Corrected.getCorrectionDecl(); + if (!ND) + return BuildInvalid(); + // If we corrected to an inheriting constructor, handle it as one. auto *RD = dyn_cast<CXXRecordDecl>(ND); if (RD && RD->isInjectedClassName()) { @@ -9641,6 +10000,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, NewTD->setInvalidDecl(); ProcessDeclAttributeList(S, NewTD, AttrList); + AddPragmaAttributes(S, NewTD); CheckTypedefForVariablyModifiedType(S, NewTD); Invalid |= NewTD->isInvalidDecl(); @@ -9816,123 +10176,113 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, return AliasDecl; } -Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, - CXXMethodDecl *MD) { - CXXRecordDecl *ClassDecl = MD->getParent(); +namespace { +struct SpecialMemberExceptionSpecInfo + : SpecialMemberVisitor<SpecialMemberExceptionSpecInfo> { + SourceLocation Loc; + Sema::ImplicitExceptionSpecification ExceptSpec; - // C++ [except.spec]p14: - // An implicitly declared special member function (Clause 12) shall have an - // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(*this); - if (ClassDecl->isInvalidDecl()) - return ExceptSpec; + SpecialMemberExceptionSpecInfo(Sema &S, CXXMethodDecl *MD, + Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI, + SourceLocation Loc) + : SpecialMemberVisitor(S, MD, CSM, ICI), Loc(Loc), ExceptSpec(S) {} - // Direct base-class constructors. - for (const auto &B : ClassDecl->bases()) { - if (B.isVirtual()) // Handled below. - continue; - - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) { - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); - // 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) - ExceptSpec.CalledDecl(B.getLocStart(), Constructor); - } - } + bool visitBase(CXXBaseSpecifier *Base); + bool visitField(FieldDecl *FD); - // Virtual base-class constructors. - for (const auto &B : ClassDecl->vbases()) { - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) { - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); - // 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) - ExceptSpec.CalledDecl(B.getLocStart(), Constructor); - } - } - - // Field constructors. - for (auto *F : ClassDecl->fields()) { - if (F->hasInClassInitializer()) { - Expr *E = F->getInClassInitializer(); - if (!E) - // FIXME: It's a little wasteful to build and throw away a - // CXXDefaultInitExpr here. - E = BuildCXXDefaultInitExpr(Loc, F).get(); - if (E) - ExceptSpec.CalledExpr(E); - } else if (const RecordType *RecordTy - = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { - CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); - CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); - // 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 - // might just be ill-formed because this function attempts to refer to - // a deleted function here. - if (Constructor) - ExceptSpec.CalledDecl(F->getLocation(), Constructor); - } - } + void visitClassSubobject(CXXRecordDecl *Class, Subobject Subobj, + unsigned Quals); - return ExceptSpec; + void visitSubobjectCall(Subobject Subobj, + Sema::SpecialMemberOverloadResult SMOR); +}; } -Sema::ImplicitExceptionSpecification -Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc, - CXXConstructorDecl *CD) { - CXXRecordDecl *ClassDecl = CD->getParent(); +bool SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) { + auto *RT = Base->getType()->getAs<RecordType>(); + if (!RT) + return false; - // C++ [except.spec]p14: - // An inheriting constructor [...] shall have an exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(*this); - if (ClassDecl->isInvalidDecl()) - return ExceptSpec; + auto *BaseClass = cast<CXXRecordDecl>(RT->getDecl()); + Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass); + if (auto *BaseCtor = SMOR.getMethod()) { + visitSubobjectCall(Base, BaseCtor); + return false; + } - auto Inherited = CD->getInheritedConstructor(); - InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl()); + visitClassSubobject(BaseClass, Base, 0); + return false; +} - // Direct and virtual base-class constructors. - for (bool VBase : {false, true}) { - for (CXXBaseSpecifier &B : - VBase ? ClassDecl->vbases() : ClassDecl->bases()) { - // Don't visit direct vbases twice. - if (B.isVirtual() != VBase) - continue; +bool SpecialMemberExceptionSpecInfo::visitField(FieldDecl *FD) { + if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer()) { + Expr *E = FD->getInClassInitializer(); + if (!E) + // FIXME: It's a little wasteful to build and throw away a + // CXXDefaultInitExpr here. + // FIXME: We should have a single context note pointing at Loc, and + // this location should be MD->getLocation() instead, since that's + // the location where we actually use the default init expression. + E = S.BuildCXXDefaultInitExpr(Loc, FD).get(); + if (E) + ExceptSpec.CalledExpr(E); + } else if (auto *RT = S.Context.getBaseElementType(FD->getType()) + ->getAs<RecordType>()) { + visitClassSubobject(cast<CXXRecordDecl>(RT->getDecl()), FD, + FD->getType().getCVRQualifiers()); + } + return false; +} - CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl(); - if (!BaseClass) - continue; +void SpecialMemberExceptionSpecInfo::visitClassSubobject(CXXRecordDecl *Class, + Subobject Subobj, + unsigned Quals) { + FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>(); + bool IsMutable = Field && Field->isMutable(); + visitSubobjectCall(Subobj, lookupIn(Class, Quals, IsMutable)); +} - CXXConstructorDecl *Constructor = - ICI.findConstructorForBase(BaseClass, Inherited.getConstructor()) - .first; - if (!Constructor) - Constructor = LookupDefaultConstructor(BaseClass); - if (Constructor) - ExceptSpec.CalledDecl(B.getLocStart(), Constructor); - } - } +void SpecialMemberExceptionSpecInfo::visitSubobjectCall( + Subobject Subobj, Sema::SpecialMemberOverloadResult SMOR) { + // Note, if lookup fails, it doesn't matter what exception specification we + // choose because the special member will be deleted. + if (CXXMethodDecl *MD = SMOR.getMethod()) + ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD); +} - // Field constructors. - for (const auto *F : ClassDecl->fields()) { - if (F->hasInClassInitializer()) { - if (Expr *E = F->getInClassInitializer()) - ExceptSpec.CalledExpr(E); - } else if (const RecordType *RecordTy - = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { - CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); - CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); - if (Constructor) - ExceptSpec.CalledDecl(F->getLocation(), Constructor); - } - } +static Sema::ImplicitExceptionSpecification +ComputeDefaultedSpecialMemberExceptionSpec( + Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI) { + CXXRecordDecl *ClassDecl = MD->getParent(); - return ExceptSpec; + // C++ [except.spec]p14: + // An implicitly declared special member function (Clause 12) shall have an + // exception-specification. [...] + SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc); + if (ClassDecl->isInvalidDecl()) + return Info.ExceptSpec; + + // C++1z [except.spec]p7: + // [Look for exceptions thrown by] a constructor selected [...] to + // initialize a potentially constructed subobject, + // C++1z [except.spec]p8: + // The exception specification for an implicitly-declared destructor, or a + // destructor without a noexcept-specifier, is potentially-throwing if and + // only if any of the destructors for any of its potentially constructed + // subojects is potentially throwing. + // FIXME: We respect the first rule but ignore the "potentially constructed" + // in the second rule to resolve a core issue (no number yet) that would have + // us reject: + // struct A { virtual void f() = 0; virtual ~A() noexcept(false) = 0; }; + // struct B : A {}; + // struct C : B { void f(); }; + // ... due to giving B::~B() a non-throwing exception specification. + Info.visit(Info.IsConstructor ? Info.VisitPotentiallyConstructedBases + : Info.VisitAllBases); + + return Info.ExceptSpec; } namespace { @@ -9944,19 +10294,34 @@ struct DeclaringSpecialMember { bool WasAlreadyBeingDeclared; DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM) - : S(S), D(RD, CSM), SavedContext(S, RD) { + : S(S), D(RD, CSM), SavedContext(S, RD) { WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second; if (WasAlreadyBeingDeclared) // This almost never happens, but if it does, ensure that our cache // doesn't contain a stale result. S.SpecialMemberCache.clear(); - - // FIXME: Register a note to be produced if we encounter an error while - // declaring the special member. + else { + // Register a note to be produced if we encounter an error while + // declaring the special member. + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::DeclaringSpecialMember; + // FIXME: We don't have a location to use here. Using the class's + // location maintains the fiction that we declare all special members + // with the class, but (1) it's not clear that lying about that helps our + // users understand what's going on, and (2) there may be outer contexts + // on the stack (some of which are relevant) and printing them exposes + // our lies. + Ctx.PointOfInstantiation = RD->getLocation(); + Ctx.Entity = RD; + Ctx.SpecialMember = CSM; + S.pushCodeSynthesisContext(Ctx); + } } ~DeclaringSpecialMember() { - if (!WasAlreadyBeingDeclared) + if (!WasAlreadyBeingDeclared) { S.SpecialMembersBeingDeclared.erase(D); + S.popCodeSynthesisContext(); + } } /// \brief Are we already trying to declare this special member? @@ -9978,7 +10343,7 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) { R.resolveKind(); R.suppressDiagnostics(); - CheckFunctionDeclaration(S, FD, R, /*IsExplicitSpecialization*/false); + CheckFunctionDeclaration(S, FD, R, /*IsMemberSpecialization*/false); } CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( @@ -10051,32 +10416,33 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, !Constructor->doesThisDeclarationHaveABody() && !Constructor->isDeleted()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); + if (Constructor->willHaveBody() || Constructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); SynthesizedFunctionScope Scope(*this, Constructor); - DiagnosticErrorTrap Trap(Diags); - if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); - Constructor->setInvalidDecl(); - return; - } // The exception specification is needed because we are defining the // function. ResolveExceptionSpec(CurrentLocation, Constructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + if (SetCtorInitializers(Constructor, /*AnyErrors=*/false)) { + Constructor->setInvalidDecl(); + return; + } SourceLocation Loc = Constructor->getLocEnd().isValid() ? Constructor->getLocEnd() : Constructor->getLocation(); Constructor->setBody(new (Context) CompoundStmt(Loc)); - Constructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10186,9 +10552,22 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, assert(Constructor->getInheritedConstructor() && !Constructor->doesThisDeclarationHaveABody() && !Constructor->isDeleted()); - if (Constructor->isInvalidDecl()) + if (Constructor->willHaveBody() || Constructor->isInvalidDecl()) return; + // Initializations are performed "as if by a defaulted default constructor", + // so enter the appropriate scope. + SynthesizedFunctionScope Scope(*this, Constructor); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Constructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + ConstructorUsingShadowDecl *Shadow = Constructor->getInheritedConstructor().getShadowDecl(); CXXConstructorDecl *InheritedCtor = @@ -10203,11 +10582,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, CXXRecordDecl *RD = Shadow->getParent(); SourceLocation InitLoc = Shadow->getLocation(); - // Initializations are performed "as if by a defaulted default constructor", - // so enter the appropriate scope. - SynthesizedFunctionScope Scope(*this, Constructor); - DiagnosticErrorTrap Trap(Diags); - // Build explicit initializers for all base classes from which the // constructor was inherited. SmallVector<CXXCtorInitializer*, 8> Inits; @@ -10238,22 +10612,13 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, // We now proceed as if for a defaulted default constructor, with the relevant // initializers replaced. - bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits); - if (HadError || Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD; + if (SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits)) { Constructor->setInvalidDecl(); return; } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - Constructor->getType()->castAs<FunctionProtoType>()); - Constructor->setBody(new (Context) CompoundStmt(InitLoc)); - Constructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10262,45 +10627,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, DiagnoseUninitializedFields(*this, Constructor); } -Sema::ImplicitExceptionSpecification -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. - ImplicitExceptionSpecification ExceptSpec(*this); - if (ClassDecl->isInvalidDecl()) - return ExceptSpec; - - // Direct base-class destructors. - for (const auto &B : ClassDecl->bases()) { - if (B.isVirtual()) // Handled below. - continue; - - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) - ExceptSpec.CalledDecl(B.getLocStart(), - LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); - } - - // Virtual base-class destructors. - for (const auto &B : ClassDecl->vbases()) { - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) - ExceptSpec.CalledDecl(B.getLocStart(), - LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); - } - - // Field destructors. - for (const auto *F : ClassDecl->fields()) { - if (const RecordType *RecordTy - = Context.getBaseElementType(F->getType())->getAs<RecordType>()) - ExceptSpec.CalledDecl(F->getLocation(), - LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); - } - - return ExceptSpec; -} - CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // C++ [class.dtor]p2: // If a class has no user-declared destructor, a destructor is @@ -10368,37 +10694,36 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, !Destructor->doesThisDeclarationHaveABody() && !Destructor->isDeleted()) && "DefineImplicitDestructor - call it for implicit default dtor"); + if (Destructor->willHaveBody() || Destructor->isInvalidDecl()) + return; + CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); - if (Destructor->isInvalidDecl()) - return; - SynthesizedFunctionScope Scope(*this, Destructor); - DiagnosticErrorTrap Trap(Diags); + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Destructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); - if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDestructor << Context.getTagDeclType(ClassDecl); - + if (CheckDestructor(Destructor)) { Destructor->setInvalidDecl(); return; } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - Destructor->getType()->castAs<FunctionProtoType>()); - SourceLocation Loc = Destructor->getLocEnd().isValid() ? Destructor->getLocEnd() : Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Loc)); Destructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Destructor); @@ -10852,7 +11177,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc), IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), BO_NE, S.Context.BoolTy, - VK_RValue, OK_Ordinary, Loc, false); + VK_RValue, OK_Ordinary, Loc, FPOptions()); // Create the pre-increment of the iteration variable. Expr *Increment @@ -10887,62 +11212,6 @@ buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, return Result; } -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->getNumParams() == 1 && "not a copy assignment op"); - unsigned ArgQuals = - T->getParamType(0).getNonReferenceType().getCVRQualifiers(); - - // C++ [except.spec]p14: - // An implicitly declared special member function (Clause 12) shall have an - // exception-specification. [...] - - // It is unspecified whether or not an implicit copy assignment operator - // attempts to deduplicate calls to assignment operators of virtual bases are - // made. As such, this exception specification is effectively unspecified. - // 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. - for (const auto &Base : ClassDecl->bases()) { - if (Base.isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, - ArgQuals, false, 0)) - ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign); - } - - for (const auto &Base : ClassDecl->vbases()) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, - ArgQuals, false, 0)) - ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign); - } - - for (const auto *Field : ClassDecl->fields()) { - QualType FieldType = Context.getBaseElementType(Field->getType()); - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - if (CXXMethodDecl *CopyAssign = - LookupCopyingAssignment(FieldClassDecl, - ArgQuals | FieldType.getCVRQualifiers(), - false, 0)) - ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign); - } - } - - return ExceptSpec; -} - CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // Note: The following rules are largely analoguous to the copy // constructor rules. Note that virtual bases are not taken into account @@ -11022,8 +11291,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { /// Diagnose an implicit copy operation for a class which is odr-used, but /// which is deprecated because the class has a user-declared copy constructor, /// copy assignment operator, or destructor. -static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp, - SourceLocation UseLoc) { +static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { assert(CopyOp->isImplicit()); CXXRecordDecl *RD = CopyOp->getParent(); @@ -11062,10 +11330,6 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp, diag::warn_deprecated_copy_operation) << RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp) << /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation); - S.Diag(UseLoc, diag::note_member_synthesized_at) - << (isa<CXXConstructorDecl>(CopyOp) ? Sema::CXXCopyConstructor - : Sema::CXXCopyAssignment) - << RD; } } @@ -11077,25 +11341,31 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, !CopyAssignOperator->doesThisDeclarationHaveABody() && !CopyAssignOperator->isDeleted()) && "DefineImplicitCopyAssignment called for wrong function"); + if (CopyAssignOperator->willHaveBody() || CopyAssignOperator->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); - - if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) { + if (ClassDecl->isInvalidDecl()) { CopyAssignOperator->setInvalidDecl(); return; } + SynthesizedFunctionScope Scope(*this, CopyAssignOperator); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyAssignOperator->getType()->castAs<FunctionProtoType>()); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // C++11 [class.copy]p18: // The [definition of an implicitly declared copy assignment operator] is // deprecated if the class has a user-declared copy constructor or a // user-declared destructor. if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit()) - diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation); - - CopyAssignOperator->markUsed(Context); - - SynthesizedFunctionScope Scope(*this, CopyAssignOperator); - DiagnosticErrorTrap Trap(Diags); + diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator); // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator @@ -11161,8 +11431,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/true, /*Copying=*/true); if (Copy.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } @@ -11188,8 +11456,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11200,8 +11466,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11234,8 +11498,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/false, /*Copying=*/true); if (Copy.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } @@ -11251,22 +11513,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; - else { + else Statements.push_back(Return.getAs<Stmt>()); - - if (Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); - Invalid = true; - } - } } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - CopyAssignOperator->getType()->castAs<FunctionProtoType>()); - if (Invalid) { CopyAssignOperator->setInvalidDecl(); return; @@ -11280,65 +11530,13 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } CopyAssignOperator->setBody(Body.getAs<Stmt>()); + CopyAssignOperator->markUsed(Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyAssignOperator); } } -Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) { - CXXRecordDecl *ClassDecl = MD->getParent(); - - ImplicitExceptionSpecification ExceptSpec(*this); - if (ClassDecl->isInvalidDecl()) - return ExceptSpec; - - // C++0x [except.spec]p14: - // An implicitly declared special member function (Clause 12) shall have an - // exception-specification. [...] - - // It is unspecified whether or not an implicit move assignment operator - // attempts to deduplicate calls to assignment operators of virtual bases are - // made. As such, this exception specification is effectively unspecified. - // 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. - // Note that a move constructor is not implicitly declared when there are - // virtual bases, but it can still be user-declared and explicitly defaulted. - for (const auto &Base : ClassDecl->bases()) { - if (Base.isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, - 0, false, 0)) - ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign); - } - - for (const auto &Base : ClassDecl->vbases()) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, - 0, false, 0)) - ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign); - } - - for (const auto *Field : ClassDecl->fields()) { - QualType FieldType = Context.getBaseElementType(Field->getType()); - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - if (CXXMethodDecl *MoveAssign = - LookupMovingAssignment(FieldClassDecl, - FieldType.getCVRQualifiers(), - false, 0)) - ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign); - } - } - - return ExceptSpec; -} - CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { assert(ClassDecl->needsImplicitMoveAssignment()); @@ -11449,13 +11647,13 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class, // If we're not actually going to call a move assignment for this base, // or the selected move assignment is trivial, skip it. - Sema::SpecialMemberOverloadResult *SMOR = + Sema::SpecialMemberOverloadResult SMOR = S.LookupSpecialMember(Base, Sema::CXXMoveAssignment, /*ConstArg*/false, /*VolatileArg*/false, /*RValueThis*/true, /*ConstThis*/false, /*VolatileThis*/false); - if (!SMOR->getMethod() || SMOR->getMethod()->isTrivial() || - !SMOR->getMethod()->isMoveAssignmentOperator()) + if (!SMOR.getMethod() || SMOR.getMethod()->isTrivial() || + !SMOR.getMethod()->isMoveAssignmentOperator()) continue; if (BaseSpec->isVirtual()) { @@ -11486,7 +11684,7 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class, // Only walk over bases that have defaulted move assignment operators. // We assume that any user-provided move assignment operator handles // the multiple-moves-of-vbase case itself somehow. - if (!SMOR->getMethod()->isDefaulted()) + if (!SMOR.getMethod()->isDefaulted()) continue; // We're going to move the base classes of Base. Add them to the list. @@ -11505,19 +11703,15 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, !MoveAssignOperator->doesThisDeclarationHaveABody() && !MoveAssignOperator->isDeleted()) && "DefineImplicitMoveAssignment called for wrong function"); + if (MoveAssignOperator->willHaveBody() || MoveAssignOperator->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent(); - - if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) { + if (ClassDecl->isInvalidDecl()) { MoveAssignOperator->setInvalidDecl(); return; } - MoveAssignOperator->markUsed(Context); - - SynthesizedFunctionScope Scope(*this, MoveAssignOperator); - DiagnosticErrorTrap Trap(Diags); - // C++0x [class.copy]p28: // The implicitly-defined or move assignment operator for a non-union class // X performs memberwise move assignment of its subobjects. The direct base @@ -11530,6 +11724,16 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // from a virtual base more than once. checkMoveAssignmentForRepeatedMove(*this, ClassDecl, CurrentLocation); + SynthesizedFunctionScope Scope(*this, MoveAssignOperator); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveAssignOperator->getType()->castAs<FunctionProtoType>()); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // The statements that form the synthesized function body. SmallVector<Stmt*, 8> Statements; @@ -11594,8 +11798,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/true, /*Copying=*/false); if (Move.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } @@ -11621,8 +11823,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11633,8 +11833,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11670,8 +11868,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/false, /*Copying=*/false); if (Move.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } @@ -11688,22 +11884,10 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; - else { + else Statements.push_back(Return.getAs<Stmt>()); - - if (Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); - Invalid = true; - } - } } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - MoveAssignOperator->getType()->castAs<FunctionProtoType>()); - if (Invalid) { MoveAssignOperator->setInvalidDecl(); return; @@ -11717,58 +11901,13 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } MoveAssignOperator->setBody(Body.getAs<Stmt>()); + MoveAssignOperator->markUsed(Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveAssignOperator); } } -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->getNumParams() >= 1 && "not a copy ctor"); - unsigned Quals = T->getParamType(0).getNonReferenceType().getCVRQualifiers(); - - // C++ [except.spec]p14: - // An implicitly declared special member function (Clause 12) shall have an - // exception-specification. [...] - for (const auto &Base : ClassDecl->bases()) { - // Virtual bases are handled below. - if (Base.isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - if (CXXConstructorDecl *CopyConstructor = - LookupCopyingConstructor(BaseClassDecl, Quals)) - ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor); - } - for (const auto &Base : ClassDecl->vbases()) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - if (CXXConstructorDecl *CopyConstructor = - LookupCopyingConstructor(BaseClassDecl, Quals)) - ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor); - } - for (const auto *Field : ClassDecl->fields()) { - QualType FieldType = Context.getBaseElementType(Field->getType()); - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - if (CXXConstructorDecl *CopyConstructor = - LookupCopyingConstructor(FieldClassDecl, - Quals | FieldType.getCVRQualifiers())) - ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor); - } - } - - return ExceptSpec; -} - CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CXXRecordDecl *ClassDecl) { // C++ [class.copy]p4: @@ -11838,8 +11977,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyConstructor); - if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) + if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) { + ClassDecl->setImplicitCopyConstructorIsDeleted(); SetDeclDeleted(CopyConstructor, ClassLoc); + } if (S) PushOnScopeChains(CopyConstructor, S, false); @@ -11849,30 +11990,37 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *CopyConstructor) { + CXXConstructorDecl *CopyConstructor) { assert((CopyConstructor->isDefaulted() && CopyConstructor->isCopyConstructor() && !CopyConstructor->doesThisDeclarationHaveABody() && !CopyConstructor->isDeleted()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); + if (CopyConstructor->willHaveBody() || CopyConstructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); + SynthesizedFunctionScope Scope(*this, CopyConstructor); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyConstructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // C++11 [class.copy]p7: // The [definition of an implicitly declared copy constructor] is // deprecated if the class has a user-declared copy assignment operator // or a user-declared destructor. if (getLangOpts().CPlusPlus11 && CopyConstructor->isImplicit()) - diagnoseDeprecatedCopyOperation(*this, CopyConstructor, CurrentLocation); + diagnoseDeprecatedCopyOperation(*this, CopyConstructor); - SynthesizedFunctionScope Scope(*this, CopyConstructor); - DiagnosticErrorTrap Trap(Diags); - - if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false)) { CopyConstructor->setInvalidDecl(); } else { SourceLocation Loc = CopyConstructor->getLocEnd().isValid() @@ -11881,80 +12029,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>()); + CopyConstructor->markUsed(Context); } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - CopyConstructor->getType()->castAs<FunctionProtoType>()); - - CopyConstructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyConstructor); } } -Sema::ImplicitExceptionSpecification -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. [...] - ImplicitExceptionSpecification ExceptSpec(*this); - if (ClassDecl->isInvalidDecl()) - return ExceptSpec; - - // Direct base-class constructors. - for (const auto &B : ClassDecl->bases()) { - if (B.isVirtual()) // Handled below. - continue; - - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) { - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - 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) - ExceptSpec.CalledDecl(B.getLocStart(), Constructor); - } - } - - // Virtual base-class constructors. - for (const auto &B : ClassDecl->vbases()) { - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) { - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - 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) - ExceptSpec.CalledDecl(B.getLocStart(), Constructor); - } - } - - // Field constructors. - for (const auto *F : ClassDecl->fields()) { - 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 - // might just be ill-formed because this function attempts to refer to - // a deleted function here. - if (Constructor) - ExceptSpec.CalledDecl(F->getLocation(), Constructor); - } - } - - return ExceptSpec; -} - CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( CXXRecordDecl *ClassDecl) { assert(ClassDecl->needsImplicitMoveConstructor()); @@ -12031,41 +12113,41 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( } void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *MoveConstructor) { + CXXConstructorDecl *MoveConstructor) { assert((MoveConstructor->isDefaulted() && MoveConstructor->isMoveConstructor() && !MoveConstructor->doesThisDeclarationHaveABody() && !MoveConstructor->isDeleted()) && "DefineImplicitMoveConstructor - call it for implicit move ctor"); + if (MoveConstructor->willHaveBody() || MoveConstructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = MoveConstructor->getParent(); assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor"); SynthesizedFunctionScope Scope(*this, MoveConstructor); - DiagnosticErrorTrap Trap(Diags); - if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveConstructor << Context.getTagDeclType(ClassDecl); + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveConstructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false)) { MoveConstructor->setInvalidDecl(); - } else { + } else { SourceLocation Loc = MoveConstructor->getLocEnd().isValid() ? MoveConstructor->getLocEnd() : MoveConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt( Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>()); + MoveConstructor->markUsed(Context); } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - MoveConstructor->getType()->castAs<FunctionProtoType>()); - - MoveConstructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveConstructor); } @@ -12078,6 +12160,8 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { void Sema::DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { + SynthesizedFunctionScope Scope(*this, Conv); + CXXRecordDecl *Lambda = Conv->getParent(); CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); // If we are defining a specialization of a conversion to function-ptr @@ -12100,6 +12184,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( "Conversion operator must have a corresponding call operator"); CallOp = cast<CXXMethodDecl>(CallOpSpec); } + // Mark the call operator referenced (and add to pending instantiations // if necessary). // For both the conversion and static-invoker template specializations @@ -12107,9 +12192,6 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( // to the PendingInstantiations. MarkFunctionReferenced(CurrentLocation, CallOp); - SynthesizedFunctionScope Scope(*this, Conv); - DiagnosticErrorTrap Trap(Diags); - // Retrieve the static invoker... CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker(); // ... and get the corresponding specialization for a generic lambda. @@ -12147,7 +12229,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); L->CompletedImplicitDefinition(Invoker); - } + } } @@ -12158,10 +12240,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( { assert(!Conv->getParent()->isGenericLambda()); - Conv->markUsed(Context); - SynthesizedFunctionScope Scope(*this, Conv); - DiagnosticErrorTrap Trap(Diags); // Copy-initialize the lambda object as needed to capture it. Expr *This = ActOnCXXThis(CurrentLocation).get(); @@ -12198,8 +12277,9 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( // Set the body of the conversion function. Stmt *ReturnS = Return.get(); Conv->setBody(new (Context) CompoundStmt(Context, ReturnS, - Conv->getLocation(), + Conv->getLocation(), Conv->getLocation())); + Conv->markUsed(Context); // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { @@ -12750,7 +12830,7 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef, PmArgs->getType()->getAs<TemplateTypeParmType>(); if (TArgs && TArgs->getDepth() == PmType->getDepth() && TArgs->getIndex() == PmType->getIndex()) { - if (SemaRef.ActiveTemplateInstantiations.empty()) + if (!SemaRef.inTemplateInstantiation()) SemaRef.Diag(TpDecl->getLocation(), diag::ext_string_literal_operator_template); return false; @@ -13076,7 +13156,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, if (!Invalid && !ExDeclType->isDependentType()) { if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) { // Insulate this from anything else we might currently be parsing. - EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated); + EnterExpressionEvaluationContext scope( + *this, ExpressionEvaluationContext::PotentiallyEvaluated); // C++ [except.handle]p16: // The object declared in an exception-declaration or, if the @@ -13221,6 +13302,14 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, } } + ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc, + /*DiscardedValue*/false, + /*IsConstexpr*/true); + if (FullAssertExpr.isInvalid()) + Failed = true; + else + AssertExpr = FullAssertExpr.get(); + Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc, AssertExpr, AssertMessage, RParenLoc, Failed); @@ -13245,10 +13334,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, // for a class.* // // * The class-key of the elaborated-type-specifier is required. - if (!ActiveTemplateInstantiations.empty()) { - // Do not complain about the form of friend template types during - // template instantiation; we will already have complained when the - // template was declared. + if (!CodeSynthesisContexts.empty()) { + // Do not complain about the form of friend template types during any kind + // of code synthesis. For template instantiation, we will have complained + // when the template was defined. } else { if (!T->isElaboratedTypeSpecifier()) { // If we evaluated the type to a record type, suggest putting @@ -13313,13 +13402,13 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, MultiTemplateParamsArg TempParamLists) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); - bool isExplicitSpecialization = false; + bool IsMemberSpecialization = false; bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( TagLoc, NameLoc, SS, nullptr, TempParamLists, /*friend*/ true, - isExplicitSpecialization, Invalid)) { + IsMemberSpecialization, Invalid)) { if (TemplateParams->size() > 0) { // This is a declaration of a class template. if (Invalid) @@ -13334,7 +13423,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) << TypeWithKeyword::getTagTypeKindName(Kind) << Name; - isExplicitSpecialization = true; + IsMemberSpecialization = true; } } @@ -13364,7 +13453,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, /*ScopedEnumKWLoc=*/SourceLocation(), /*ScopedEnumUsesClassTag=*/false, /*UnderlyingType=*/TypeResult(), - /*IsTypeSpecifier=*/false); + /*IsTypeSpecifier=*/false, + /*IsTemplateParamOrArg=*/false); } NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); @@ -13744,6 +13834,9 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, case UnqualifiedId::IK_ConversionFunctionId: DiagArg = 2; break; + case UnqualifiedId::IK_DeductionGuideName: + DiagArg = 3; + break; case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_LiteralOperatorId: @@ -13845,6 +13938,9 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { return; } + // Deleted function does not have a body. + Fn->setWillHaveBody(false); + if (const FunctionDecl *Prev = Fn->getPreviousDecl()) { // Don't consider the implicit declaration we generate for explicit // specializations. FIXME: Do not generate these implicit declarations. @@ -13923,6 +14019,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { MD->setDefaulted(); MD->setExplicitlyDefaulted(); + // Unset that we will have a body for this function. We might not, + // if it turns out to be trivial, and we don't need this marking now + // that we've marked it as defaulted. + MD->setWillHaveBody(false); + // If this definition appears within the record, do the checking when // the record is complete. const FunctionDecl *Primary = MD; @@ -14157,7 +14258,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // new expression evaluation context that is associated with this static // data member. if (isStaticDataMember(D)) - PushExpressionEvaluationContext(PotentiallyEvaluated, D); + PushExpressionEvaluationContext( + ExpressionEvaluationContext::PotentiallyEvaluated, D); } /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an @@ -14619,6 +14721,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { case EST_ComputedNoexcept: if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) return true; + LLVM_FALLTHROUGH; case EST_Dynamic: for (const auto &E : Proto->exceptions()) { |