Refactor computation of exception specification for special members to remove
some of the repetition. llvm-svn: 296067
This commit is contained in:
parent
1db609f882
commit
2246c83369
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue