From 2246c83369a0fac1e8f976cbe2d3342c6b1860c1 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 24 Feb 2017 01:29:42 +0000 Subject: [PATCH] Refactor computation of exception specification for special members to remove some of the repetition. llvm-svn: 296067 --- clang/include/clang/AST/DeclCXX.h | 5 + clang/lib/Sema/SemaDeclCXX.cpp | 508 +++++++++--------------------- 2 files changed, 146 insertions(+), 367 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index d321d19068bf..637a20aa6c9c 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -203,6 +203,11 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + /// \brief Get the location at which the base class type was written. + SourceLocation getBaseTypeLoc() const LLVM_READONLY { + return BaseTypeInfo->getTypeLoc().getLocStart(); + } + /// \brief Determines whether the base class is a virtual base class (or not). bool isVirtual() const { return Virtual; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c31ec7deef70..602c3814ca3e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6090,28 +6090,35 @@ static bool defaultedSpecialMemberIsConstexpr( return true; } +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)) { + switch (auto CSM = S.getSpecialMember(MD)) { case Sema::CXXDefaultConstructor: - return S.ComputeDefaultedDefaultCtorExceptionSpec(Loc, MD); + return ComputeDefaultedSpecialMemberExceptionSpec( + S, Loc, MD, Sema::CXXDefaultConstructor, nullptr); 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); + return ComputeDefaultedSpecialMemberExceptionSpec( + S, MD->getLocation(), MD, CSM, nullptr); case Sema::CXXInvalid: break; } - assert(cast(MD)->getInheritedConstructor() && + + auto *CD = cast(MD); + assert(CD->getInheritedConstructor() && "only special members have implicit exception specs"); - return S.ComputeInheritingCtorExceptionSpec(Loc, - cast(MD)); + Sema::InheritedConstructorInfo ICI( + S, Loc, CD->getInheritedConstructor().getShadowDecl()); + return ComputeDefaultedSpecialMemberExceptionSpec( + S, Loc, CD, Sema::CXXDefaultConstructor, &ICI); } static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S, @@ -10036,123 +10043,143 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, return AliasDecl; } -Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, - CXXMethodDecl *MD) { +namespace { +struct SpecialMemberExceptionSpecInfo { + Sema &S; + CXXMethodDecl *MD; + Sema::CXXSpecialMember CSM; + Sema::InheritedConstructorInfo *ICI; + + SourceLocation Loc; + Sema::ImplicitExceptionSpecification ExceptSpec; + + bool ConstArg = false; + + SpecialMemberExceptionSpecInfo(Sema &S, CXXMethodDecl *MD, + Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI, + SourceLocation Loc) + : S(S), MD(MD), CSM(CSM), ICI(ICI), Loc(Loc), ExceptSpec(S) { + if (MD->getNumParams()) { + if (const ReferenceType *RT = + MD->getParamDecl(0)->getType()->getAs()) + ConstArg = RT->getPointeeType().isConstQualified(); + } + } + + typedef llvm::PointerUnion Subobject; + static SourceLocation getSubobjectLoc(Subobject Subobj) { + if (auto *B = Subobj.dyn_cast()) + return B->getBaseTypeLoc(); + else + return Subobj.get()->getLocation(); + } + + Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class, + unsigned Quals, bool IsMutable) { + return lookupCallFromSpecialMember(S, Class, CSM, Quals, + ConstArg && !IsMutable); + } + + void visitBase(CXXBaseSpecifier *Base); + void visitField(FieldDecl *FD); + + void visitClassSubobject(CXXRecordDecl *Class, Subobject Subobj, + unsigned Quals); + + void visitSubobjectCall(Subobject Subobj, + Sema::SpecialMemberOverloadResult *SMOR); + void visitSubobjectCall(Subobject Subobj, CXXMethodDecl *MD); +}; +} + +void SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) { + auto *RT = Base->getType()->getAs(); + if (!RT) + return; + + auto *BaseClass = cast(RT->getDecl()); + if (ICI) { + assert(CSM == Sema::CXXDefaultConstructor); + if (auto *BaseCtor = ICI->findConstructorForBase( + BaseClass, cast(MD) + ->getInheritedConstructor() + .getConstructor()) + .first) + return visitSubobjectCall(Base, BaseCtor); + } + + visitClassSubobject(BaseClass, Base, 0); +} + +void 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()) { + visitClassSubobject(cast(RT->getDecl()), FD, + FD->getType().getCVRQualifiers()); + } +} + +void SpecialMemberExceptionSpecInfo::visitClassSubobject(CXXRecordDecl *Class, + Subobject Subobj, + unsigned Quals) { + FieldDecl *Field = Subobj.dyn_cast(); + bool IsMutable = Field && Field->isMutable(); + visitSubobjectCall(Subobj, lookupIn(Class, Quals, IsMutable)); +} + +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()) + visitSubobjectCall(Subobj, MD); +} + +void SpecialMemberExceptionSpecInfo::visitSubobjectCall(Subobject Subobj, + CXXMethodDecl *MD) { + ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD); +} + +static Sema::ImplicitExceptionSpecification +ComputeDefaultedSpecialMemberExceptionSpec( + Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI) { CXXRecordDecl *ClassDecl = MD->getParent(); // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(*this); + SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc); if (ClassDecl->isInvalidDecl()) - return ExceptSpec; + return Info.ExceptSpec; // Direct base-class constructors. - for (const auto &B : ClassDecl->bases()) { - if (B.isVirtual()) // Handled below. - continue; - - if (const RecordType *BaseType = B.getType()->getAs()) { - CXXRecordDecl *BaseClassDecl = cast(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); - } - } + for (auto &B : ClassDecl->bases()) + if (!B.isVirtual()) // Handled below. + Info.visitBase(&B); // Virtual base-class constructors. - for (const auto &B : ClassDecl->vbases()) { - if (const RecordType *BaseType = B.getType()->getAs()) { - CXXRecordDecl *BaseClassDecl = cast(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); - } - } + // FIXME: Implement potentially-constructed subobjects rule. + for (auto &B : ClassDecl->vbases()) + Info.visitBase(&B); // 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()) { - CXXRecordDecl *FieldRecDecl = cast(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); - } - } + for (auto *F : ClassDecl->fields()) + Info.visitField(F); - return ExceptSpec; -} - -Sema::ImplicitExceptionSpecification -Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc, - CXXConstructorDecl *CD) { - CXXRecordDecl *ClassDecl = CD->getParent(); - - // C++ [except.spec]p14: - // An inheriting constructor [...] shall have an exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(*this); - if (ClassDecl->isInvalidDecl()) - return ExceptSpec; - - auto Inherited = CD->getInheritedConstructor(); - InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl()); - - // 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; - - CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl(); - if (!BaseClass) - continue; - - CXXConstructorDecl *Constructor = - ICI.findConstructorForBase(BaseClass, Inherited.getConstructor()) - .first; - if (!Constructor) - Constructor = LookupDefaultConstructor(BaseClass); - if (Constructor) - ExceptSpec.CalledDecl(B.getLocStart(), Constructor); - } - } - - // 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()) { - CXXRecordDecl *FieldRecDecl = cast(RecordTy->getDecl()); - CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); - if (Constructor) - ExceptSpec.CalledDecl(F->getLocation(), Constructor); - } - } - - return ExceptSpec; + return Info.ExceptSpec; } namespace { @@ -10497,45 +10524,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()) - ExceptSpec.CalledDecl(B.getLocStart(), - LookupDestructor(cast(BaseType->getDecl()))); - } - - // Virtual base-class destructors. - for (const auto &B : ClassDecl->vbases()) { - if (const RecordType *BaseType = B.getType()->getAs()) - ExceptSpec.CalledDecl(B.getLocStart(), - LookupDestructor(cast(BaseType->getDecl()))); - } - - // Field destructors. - for (const auto *F : ClassDecl->fields()) { - if (const RecordType *RecordTy - = Context.getBaseElementType(F->getType())->getAs()) - ExceptSpec.CalledDecl(F->getLocation(), - LookupDestructor(cast(RecordTy->getDecl()))); - } - - return ExceptSpec; -} - CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // C++ [class.dtor]p2: // If a class has no user-declared destructor, a destructor is @@ -11122,62 +11110,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(); - 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(Base.getType()->getAs()->getDecl()); - if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, - ArgQuals, false, 0)) - ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign); - } - - for (const auto &Base : ClassDecl->vbases()) { - CXXRecordDecl *BaseClassDecl - = cast(Base.getType()->getAs()->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 @@ -11521,59 +11453,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } } -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(Base.getType()->getAs()->getDecl()); - if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, - 0, false, 0)) - ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign); - } - - for (const auto &Base : ClassDecl->vbases()) { - CXXRecordDecl *BaseClassDecl - = cast(Base.getType()->getAs()->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()); @@ -11958,52 +11837,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } } -Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) { - CXXRecordDecl *ClassDecl = MD->getParent(); - - ImplicitExceptionSpecification ExceptSpec(*this); - if (ClassDecl->isInvalidDecl()) - return ExceptSpec; - - const FunctionProtoType *T = MD->getType()->castAs(); - 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(Base.getType()->getAs()->getDecl()); - if (CXXConstructorDecl *CopyConstructor = - LookupCopyingConstructor(BaseClassDecl, Quals)) - ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor); - } - for (const auto &Base : ClassDecl->vbases()) { - CXXRecordDecl *BaseClassDecl - = cast(Base.getType()->getAs()->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: @@ -12131,65 +11964,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } } -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()) { - CXXRecordDecl *BaseClassDecl = cast(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()) { - CXXRecordDecl *BaseClassDecl = cast(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());