Refactor computation of exception specification for special members to remove

some of the repetition.

llvm-svn: 296067
This commit is contained in:
Richard Smith 2017-02-24 01:29:42 +00:00
parent 1db609f882
commit 2246c83369
2 changed files with 146 additions and 367 deletions

View File

@ -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; }

View File

@ -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<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
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,
@ -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<ReferenceType>())
ConstArg = RT->getPointeeType().isConstQualified();
}
}
typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject;
static SourceLocation getSubobjectLoc(Subobject Subobj) {
if (auto *B = Subobj.dyn_cast<CXXBaseSpecifier*>())
return B->getBaseTypeLoc();
else
return Subobj.get<FieldDecl*>()->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<RecordType>();
if (!RT)
return;
auto *BaseClass = cast<CXXRecordDecl>(RT->getDecl());
if (ICI) {
assert(CSM == Sema::CXXDefaultConstructor);
if (auto *BaseCtor = ICI->findConstructorForBase(
BaseClass, cast<CXXConstructorDecl>(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<RecordType>()) {
visitClassSubobject(cast<CXXRecordDecl>(RT->getDecl()), FD,
FD->getType().getCVRQualifiers());
}
}
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));
}
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<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);
}
}
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<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);
}
}
// 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<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);
}
}
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<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(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<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
@ -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<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
@ -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<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());
@ -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<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:
@ -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<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());