aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td31
-rw-r--r--include/clang/Sema/Sema.h26
-rw-r--r--lib/Sema/SemaDeclCXX.cpp267
-rw-r--r--lib/Sema/SemaExpr.cpp21
-rw-r--r--lib/Sema/SemaExprCXX.cpp3
-rw-r--r--lib/Sema/SemaInit.cpp48
-rw-r--r--lib/Sema/SemaLookup.cpp20
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp4
-rw-r--r--test/CXX/special/class.copy/implicit-move.cpp6
-rw-r--r--test/CXX/special/class.copy/p11.0x.copy.cpp36
-rw-r--r--test/CXX/special/class.copy/p11.0x.move.cpp4
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp59
-rw-r--r--test/CXX/special/class.dtor/p5-0x.cpp55
-rw-r--r--test/SemaCXX/cxx0x-deleted-default-ctor.cpp46
-rw-r--r--test/SemaCXX/cxx98-compat-flags.cpp6
-rw-r--r--test/SemaCXX/cxx98-compat.cpp6
-rw-r--r--test/SemaCXX/defaulted-private-dtor.cpp6
-rw-r--r--test/SemaCXX/dr1301.cpp22
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp4
-rw-r--r--test/SemaCXX/value-initialization.cpp5
20 files changed, 410 insertions, 265 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 30780104d6..32ac7be9e5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2821,6 +2821,37 @@ def warn_cxx98_compat_friend_redefinition : Warning<
"friend function %0 would be implicitly redefined in C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def note_deleted_dtor_no_operator_delete : Note<
+ "virtual destructor requires an unambiguous, accessible 'operator delete'">;
+def note_deleted_special_member_class_subobject : Note<
+ "%select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}0 of "
+ "%select{||||union }4%1 is implicitly deleted because "
+ "%select{base class %3|field %3}2 has "
+ "%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 "
+ "%select{%select{default constructor|copy constructor|move constructor|copy "
+ "assignment operator|move assignment operator|destructor}0|destructor}5"
+ "%select{||s||}4">;
+def note_deleted_default_ctor_uninit_field : Note<
+ "default constructor of %0 is implicitly deleted because field %1 of "
+ "%select{reference|const-qualified}3 type %2 would not be initialized">;
+def note_deleted_default_ctor_all_const : Note<
+ "default constructor of %0 is implicitly deleted because all "
+ "%select{data members|data members of an anonymous union member}1"
+ " are const-qualified">;
+def note_deleted_copy_ctor_rvalue_reference : Note<
+ "copy constructor of %0 is implicitly deleted because field %1 is of "
+ "rvalue reference type %2">;
+def note_deleted_copy_user_declared_move : Note<
+ "copy %select{constructor|assignment operator}0 is implicitly deleted because"
+ " %1 has a user-declared move %select{constructor|assignment operator}2">;
+def note_deleted_assign_field : Note<
+ "%select{copy|move}0 assignment operator of %0 is implicitly deleted "
+ "because field %1 is of %select{reference|const-qualified}3 type %2">;
+def note_deleted_move_assign_virtual_base : Note<
+ "move assignment operator of %0 is implicitly deleted because it has a "
+ "virtual base class %1">;
+
// This should eventually be an error.
def warn_undefined_internal : Warning<
"%select{function|variable}0 %q1 has internal linkage but is not defined">,
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index cd8b1e96d9..045b2fa69a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -660,7 +660,17 @@ public:
/// This is used for determining parameter types of other objects and is
/// utterly meaningless on other types of special members.
class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode {
+ public:
+ enum Kind {
+ NoMemberOrDeleted,
+ Ambiguous,
+ SuccessNonConst,
+ SuccessConst
+ };
+
+ private:
llvm::PointerIntPair<CXXMethodDecl*, 2> Pair;
+
public:
SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID)
: FastFoldingSetNode(ID)
@@ -669,15 +679,11 @@ public:
CXXMethodDecl *getMethod() const { return Pair.getPointer(); }
void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); }
- bool hasSuccess() const { return Pair.getInt() & 0x1; }
- void setSuccess(bool B) {
- Pair.setInt(unsigned(B) | hasConstParamMatch() << 1);
- }
+ Kind getKind() const { return static_cast<Kind>(Pair.getInt()); }
+ void setKind(Kind K) { Pair.setInt(K); }
- bool hasConstParamMatch() const { return Pair.getInt() & 0x2; }
- void setConstParamMatch(bool B) {
- Pair.setInt(B << 1 | unsigned(hasSuccess()));
- }
+ bool hasSuccess() const { return getKind() >= SuccessNonConst; }
+ bool hasConstParamMatch() const { return getKind() == SuccessConst; }
};
/// \brief A cache of special member function overload resolution results
@@ -2421,6 +2427,7 @@ public:
bool CanUseDecl(NamedDecl *D);
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass=0);
+ void NoteDeletedFunction(FunctionDecl *FD);
std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD);
bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
ObjCMethodDecl *Getter,
@@ -3127,7 +3134,8 @@ public:
/// \brief Determine if a special member function should have a deleted
/// definition when it is defaulted.
- bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM);
+ bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose = false);
/// \brief Declare the implicit default constructor for the given class.
///
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c59e97af72..5a64d09bae 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -4333,6 +4333,7 @@ struct SpecialMemberDeletionInfo {
Sema &S;
CXXMethodDecl *MD;
Sema::CXXSpecialMember CSM;
+ bool Diagnose;
// Properties of the special member, computed for convenience.
bool IsConstructor, IsAssignment, IsMove, ConstArg, VolatileArg;
@@ -4341,8 +4342,8 @@ struct SpecialMemberDeletionInfo {
bool AllFieldsAreConst;
SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
- Sema::CXXSpecialMember CSM)
- : S(S), MD(MD), CSM(CSM),
+ Sema::CXXSpecialMember CSM, bool Diagnose)
+ : S(S), MD(MD), CSM(CSM), Diagnose(Diagnose),
IsConstructor(false), IsAssignment(false), IsMove(false),
ConstArg(false), VolatileArg(false), Loc(MD->getLocation()),
AllFieldsAreConst(true) {
@@ -4385,35 +4386,76 @@ struct SpecialMemberDeletionInfo {
TQ & Qualifiers::Volatile);
}
- bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, FieldDecl *Field);
+ typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject;
- bool shouldDeleteForBase(CXXRecordDecl *BaseDecl, bool IsVirtualBase);
+ bool shouldDeleteForBase(CXXBaseSpecifier *Base);
bool shouldDeleteForField(FieldDecl *FD);
bool shouldDeleteForAllConstMembers();
+
+ bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj);
+ bool shouldDeleteForSubobjectCall(Subobject Subobj,
+ Sema::SpecialMemberOverloadResult *SMOR,
+ bool IsDtorCallInCtor);
};
}
+/// 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,
+ bool IsDtorCallInCtor) {
+ CXXMethodDecl *Decl = SMOR->getMethod();
+ FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
+
+ int DiagKind = -1;
+
+ if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
+ DiagKind = !Decl ? 0 : 1;
+ else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ DiagKind = 2;
+ else if (S.CheckDirectMemberAccess(Loc, Decl, S.PDiag())
+ != Sema::AR_accessible)
+ DiagKind = 3;
+ else if (!IsDtorCallInCtor && Field && Field->getParent()->isUnion() &&
+ !Decl->isTrivial()) {
+ // A member of a union must have a trivial corresponding special member.
+ // As a weird special case, a destructor call from a union's constructor
+ // must be accessible and non-deleted, but need not be trivial. Such a
+ // destructor is never actually called, but is semantically checked as
+ // if it were.
+ DiagKind = 4;
+ }
+
+ if (DiagKind == -1)
+ return false;
+
+ if (Diagnose) {
+ if (Field) {
+ S.Diag(Field->getLocation(),
+ diag::note_deleted_special_member_class_subobject)
+ << CSM << MD->getParent() << /*IsField*/true
+ << Field << DiagKind << IsDtorCallInCtor;
+ } else {
+ CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>();
+ S.Diag(Base->getLocStart(),
+ diag::note_deleted_special_member_class_subobject)
+ << CSM << MD->getParent() << /*IsField*/false
+ << Base->getType() << DiagKind << IsDtorCallInCtor;
+ }
+
+ if (DiagKind == 1)
+ S.NoteDeletedFunction(Decl);
+ // FIXME: Explain inaccessibility if DiagKind == 3.
+ }
+
+ return true;
+}
+
/// Check whether we should delete a special member function due to having a
/// direct or virtual base class or static data member of class type M.
bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
- CXXRecordDecl *Class, FieldDecl *Field) {
- // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5:
- // -- any direct or virtual base class [...] has a type with a destructor
- // that is deleted or inaccessible
- if (!IsAssignment) {
- CXXDestructorDecl *Dtor = S.LookupDestructor(Class);
- if (Dtor->isDeleted())
- return true;
- if (S.CheckDestructorAccess(Loc, Dtor, S.PDiag()) != Sema::AR_accessible)
- return true;
-
- // C++11 [class.dtor]p5:
- // -- X is a union-like class that has a variant member with a non-trivial
- // destructor
- if (CSM == Sema::CXXDestructor && Field && Field->getParent()->isUnion() &&
- !Dtor->isTrivial())
- return true;
- }
+ CXXRecordDecl *Class, Subobject Subobj) {
+ FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
// C++11 [class.ctor]p5:
// -- any direct or virtual base class, or non-static data member with no
@@ -4426,58 +4468,62 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
// overload resolution, as applied to B's corresponding special member,
// results in an ambiguity or a function that is deleted or inaccessible
// from the defaulted special member
- if (CSM != Sema::CXXDestructor &&
- !(CSM == Sema::CXXDefaultConstructor &&
+ // C++11 [class.dtor]p5:
+ // -- any direct or virtual base class [...] has a type with a destructor
+ // that is deleted or inaccessible
+ if (!(CSM == Sema::CXXDefaultConstructor &&
Field && Field->hasInClassInitializer())) {
Sema::SpecialMemberOverloadResult *SMOR = lookupIn(Class);
- if (!SMOR->hasSuccess())
- return true;
-
CXXMethodDecl *Member = SMOR->getMethod();
- // A member of a union must have a trivial corresponding special member.
- if (Field && Field->getParent()->isUnion() && !Member->isTrivial())
+ if (shouldDeleteForSubobjectCall(Subobj, SMOR, false))
return true;
- if (IsConstructor) {
+ // FIXME: CWG 1402 moves these bullets elsewhere.
+ if (CSM == Sema::CXXMoveConstructor) {
CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(Member);
- if (S.CheckConstructorAccess(Loc, Ctor, Ctor->getAccess(), S.PDiag())
- != Sema::AR_accessible)
- return true;
-
// -- for the move constructor, a [...] direct or virtual base class with
// a type that does not have a move constructor and is not trivially
// copyable.
- if (IsMove && !Ctor->isMoveConstructor() && !Class->isTriviallyCopyable())
+ if (!Ctor->isMoveConstructor() && !Class->isTriviallyCopyable())
return true;
- } else {
- assert(IsAssignment && "unexpected kind of special member");
- if (S.CheckDirectMemberAccess(Loc, Member, S.PDiag())
- != Sema::AR_accessible)
- return true;
-
+ } else if (CSM == Sema::CXXMoveAssignment) {
// -- for the move assignment operator, a direct base class with a type
// that does not have a move assignment operator and is not trivially
// copyable.
- if (IsMove && !Member->isMoveAssignmentOperator() &&
- !Class->isTriviallyCopyable())
+ if (!Member->isMoveAssignmentOperator() && !Class->isTriviallyCopyable())
return true;
}
}
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11:
+ // -- 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 =
+ S.LookupSpecialMember(Class, Sema::CXXDestructor,
+ false, false, false, false, false);
+ if (shouldDeleteForSubobjectCall(Subobj, SMOR, true))
+ return true;
+ }
+
return false;
}
/// Check whether we should delete a special member function due to the class
/// having a particular direct or virtual base class.
-bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXRecordDecl *BaseDecl,
- bool IsVirtualBase) {
+bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
// C++11 [class.copy]p23:
// -- for the move assignment operator, any direct or indirect virtual
// base class.
- if (CSM == Sema::CXXMoveAssignment && IsVirtualBase)
+ if (CSM == Sema::CXXMoveAssignment && Base->isVirtual()) {
+ if (Diagnose)
+ S.Diag(Base->getLocStart(), diag::note_deleted_move_assign_virtual_base)
+ << MD->getParent() << Base->getType();
return true;
+ }
- if (shouldDeleteForClassSubobject(BaseDecl, 0))
+ if (shouldDeleteForClassSubobject(Base->getType()->getAsCXXRecordDecl(),
+ Base))
return true;
return false;
@@ -4492,29 +4538,52 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (CSM == Sema::CXXDefaultConstructor) {
// For a default constructor, all references must be initialized in-class
// and, if a union, it must have a non-const member.
- if (FieldType->isReferenceType() && !FD->hasInClassInitializer())
+ if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
+ << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
-
- if (inUnion() && !FieldType.isConstQualified())
- AllFieldsAreConst = false;
-
+ }
// C++11 [class.ctor]p5: any non-variant non-static data member of
// const-qualified type (or array thereof) with no
// brace-or-equal-initializer does not have a user-provided default
// constructor.
if (!inUnion() && FieldType.isConstQualified() &&
!FD->hasInClassInitializer() &&
- (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor()))
+ (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
+ << MD->getParent() << FD << FieldType << /*Const*/1;
return true;
+ }
+
+ if (inUnion() && !FieldType.isConstQualified())
+ AllFieldsAreConst = false;
} else if (CSM == Sema::CXXCopyConstructor) {
// For a copy constructor, data members must not be of rvalue reference
// type.
- if (FieldType->isRValueReferenceType())
+ if (FieldType->isRValueReferenceType()) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_copy_ctor_rvalue_reference)
+ << MD->getParent() << FD << FieldType;
return true;
+ }
} else if (IsAssignment) {
// For an assignment operator, data members must not be of reference type.
- if (FieldType->isReferenceType())
+ if (FieldType->isReferenceType()) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
+ << IsMove << MD->getParent() << FD << FieldType << /*Reference*/0;
+ return true;
+ }
+ if (!FieldRecord && FieldType.isConstQualified()) {
+ // C++11 [class.copy]p23:
+ // -- a non-static data member of const non-class type (or array thereof)
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
+ << IsMove << MD->getParent() << FD << FieldType << /*Const*/1;
return true;
+ }
}
if (FieldRecord) {
@@ -4540,8 +4609,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
// At least one member in each anonymous union must be non-const
if (CSM == Sema::CXXDefaultConstructor && AllVariantFieldsAreConst &&
- FieldRecord->field_begin() != FieldRecord->field_end())
+ FieldRecord->field_begin() != FieldRecord->field_end()) {
+ if (Diagnose)
+ S.Diag(FieldRecord->getLocation(),
+ diag::note_deleted_default_ctor_all_const)
+ << MD->getParent() << /*anonymous union*/1;
return true;
+ }
// Don't check the implicit member of the anonymous union type.
// This is technically non-conformant, but sanity demands it.
@@ -4550,10 +4624,6 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (shouldDeleteForClassSubobject(FieldRecord, FD))
return true;
- } else if (IsAssignment && FieldType.isConstQualified()) {
- // C++11 [class.copy]p23:
- // -- a non-static data member of const non-class type (or array thereof)
- return true;
}
return false;
@@ -4565,40 +4635,81 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
// This is a silly definition, because it gives an empty union a deleted
// default constructor. Don't do that.
- return CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst &&
- (MD->getParent()->field_begin() != MD->getParent()->field_end());
+ if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst &&
+ (MD->getParent()->field_begin() != MD->getParent()->field_end())) {
+ if (Diagnose)
+ S.Diag(MD->getParent()->getLocation(),
+ diag::note_deleted_default_ctor_all_const)
+ << MD->getParent() << /*not anonymous union*/0;
+ return true;
+ }
+ return false;
}
/// Determine whether a defaulted special member function should be defined as
/// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11,
/// C++11 [class.copy]p23, and C++11 [class.dtor]p5.
-bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) {
+bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose) {
assert(!MD->isInvalidDecl());
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
- // FIXME: Provide the ability to diagnose why a special member was deleted.
-
// C++11 [expr.lambda.prim]p19:
// The closure type associated with a lambda-expression has a
// deleted (8.4.3) default constructor and a deleted copy
// assignment operator.
if (RD->isLambda() &&
- (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment))
+ (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) {
+ if (Diagnose)
+ Diag(RD->getLocation(), diag::note_lambda_decl);
return true;
+ }
+
+ // C++11 [class.copy]p7, p18:
+ // If the class definition declares a move constructor or move assignment
+ // operator, an implicitly declared copy constructor or copy assignment
+ // operator is defined as deleted.
+ if (MD->isImplicit() &&
+ (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)) {
+ CXXMethodDecl *UserDeclaredMove = 0;
+
+ // In Microsoft mode, a user-declared move only causes the deletion of the
+ // corresponding copy operation, not both copy operations.
+ if (RD->hasUserDeclaredMoveConstructor() &&
+ (!getLangOpts().MicrosoftMode || CSM == CXXCopyConstructor)) {
+ if (!Diagnose) return true;
+ UserDeclaredMove = RD->getMoveConstructor();
+ } else if (RD->hasUserDeclaredMoveAssignment() &&
+ (!getLangOpts().MicrosoftMode || CSM == CXXCopyAssignment)) {
+ if (!Diagnose) return true;
+ UserDeclaredMove = RD->getMoveAssignmentOperator();
+ }
+
+ if (UserDeclaredMove) {
+ Diag(UserDeclaredMove->getLocation(),
+ diag::note_deleted_copy_user_declared_move)
+ << (CSM == CXXMoveAssignment) << RD
+ << UserDeclaredMove->isMoveAssignmentOperator();
+ return true;
+ }
+ }
// C++11 [class.dtor]p5:
// -- for a virtual destructor, lookup of the non-array deallocation function
// results in an ambiguity or in a function that is deleted or inaccessible
- if (CSM == Sema::CXXDestructor && MD->isVirtual()) {
+ if (CSM == CXXDestructor && MD->isVirtual()) {
FunctionDecl *OperatorDelete = 0;
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name,
- OperatorDelete, false))
+ OperatorDelete, false)) {
+ if (Diagnose)
+ Diag(RD->getLocation(), diag::note_deleted_dtor_no_operator_delete);
return true;
+ }
}
// For an anonymous struct or union, the copy and assignment special members
@@ -4611,17 +4722,17 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) {
// Do access control from the special member function
ContextRAII MethodContext(*this, MD);
- SpecialMemberDeletionInfo SMI(*this, MD, CSM);
+ SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose);
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
BE = RD->bases_end(); BI != BE; ++BI)
if (!BI->isVirtual() &&
- SMI.shouldDeleteForBase(BI->getType()->getAsCXXRecordDecl(), false))
+ SMI.shouldDeleteForBase(BI))
return true;
for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
BE = RD->vbases_end(); BI != BE; ++BI)
- if (SMI.shouldDeleteForBase(BI->getType()->getAsCXXRecordDecl(), true))
+ if (SMI.shouldDeleteForBase(BI))
return true;
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
@@ -7603,12 +7714,9 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// assignment operator, there is no user-declared move constructor, and
// there is no user-declared move assignment operator, a copy assignment
// operator is implicitly declared as defaulted.
- if ((ClassDecl->hasUserDeclaredMoveConstructor() &&
- !getLangOpts().MicrosoftMode) ||
- ClassDecl->hasUserDeclaredMoveAssignment() ||
- ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
+ if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
CopyAssignment->setDeletedAsWritten();
-
+
AddOverriddenMethods(ClassDecl, CopyAssignment);
return CopyAssignment;
}
@@ -8522,12 +8630,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// constructor, there is no user-declared move constructor, and there is no
// user-declared move assignment operator, a copy constructor is implicitly
// declared as defaulted.
- if (ClassDecl->hasUserDeclaredMoveConstructor() ||
- (ClassDecl->hasUserDeclaredMoveAssignment() &&
- !getLangOpts().MicrosoftMode) ||
- ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
+ if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
CopyConstructor->setDeletedAsWritten();
-
+
return CopyConstructor;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 88ef8cd5d8..97cb647229 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -108,6 +108,25 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
return Result;
}
+/// \brief Emit a note explaining that this function is deleted or unavailable.
+void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl);
+
+ if (Method && Method->isImplicit()) {
+ CXXSpecialMember CSM = getSpecialMember(Method);
+ // It is possible for us to no longer be able to determine why the special
+ // member function was deleted, due to a field or base class having acquired
+ // a new special member function by the addition of a default argument.
+ // FIXME: Add a test and a special-case diagnostic for this.
+ if (CSM != CXXInvalid &&
+ ShouldDeleteSpecialMember(Method, CSM, /*Diagnose=*/true))
+ return;
+ }
+
+ Diag(Decl->getLocation(), diag::note_unavailable_here)
+ << 1 << Decl->isDeleted();
+}
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -151,7 +170,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
Diag(Loc, diag::err_deleted_function_use);
- Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true;
+ NoteDeletedFunction(FD);
return true;
}
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index ec2332cc3c..4692bf8b4b 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1899,8 +1899,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
if (Operator->isDeleted()) {
if (Diagnose) {
Diag(StartLoc, diag::err_deleted_function_use);
- Diag(Operator->getLocation(), diag::note_unavailable_here)
- << /*function*/ 1 << /*deleted*/ 1;
+ NoteDeletedFunction(Operator);
}
return true;
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 570b240332..125149edc2 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -4482,8 +4482,7 @@ static ExprResult CopyObject(Sema &S,
S.Diag(Loc, diag::err_temp_copy_deleted)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
- S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << 1 << Best->Function->isDeleted();
+ S.NoteDeletedFunction(Best->Function);
return ExprError();
}
@@ -4592,8 +4591,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
case OR_Deleted:
S.Diag(Loc, Diag);
- S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << 1 << Best->Function->isDeleted();
+ S.NoteDeletedFunction(Best->Function);
break;
}
}
@@ -5362,26 +5360,6 @@ InitializationSequence::Perform(Sema &S,
return move(CurInit);
}
-/// \brief Provide some notes that detail why a function was implicitly
-/// deleted.
-static void diagnoseImplicitlyDeletedFunction(Sema &S, CXXMethodDecl *Method) {
- // FIXME: This is a work in progress. It should dig deeper to figure out
- // why the function was deleted (e.g., because one of its members doesn't
- // have a copy constructor, for the copy-constructor case).
- if (!Method->isImplicit()) {
- S.Diag(Method->getLocation(), diag::note_callee_decl)
- << Method->getDeclName();
- }
-
- if (Method->getParent()->isLambda()) {
- S.Diag(Method->getParent()->getLocation(), diag::note_lambda_decl);
- return;
- }
-
- S.Diag(Method->getParent()->getLocation(), diag::note_defined_here)
- << Method->getParent();
-}
-
//===----------------------------------------------------------------------===//
// Diagnose initialization failures
//===----------------------------------------------------------------------===//
@@ -5469,8 +5447,7 @@ bool InitializationSequence::Diagnose(Sema &S,
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best,
true);
if (Ovl == OR_Deleted) {
- S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << 1 << Best->Function->isDeleted();
+ S.NoteDeletedFunction(Best->Function);
} else {
llvm_unreachable("Inconsistent overload resolution?");
}
@@ -5661,20 +5638,15 @@ bool InitializationSequence::Diagnose(Sema &S,
// If this is a defaulted or implicitly-declared function, then
// it was implicitly deleted. Make it clear that the deletion was
// implicit.
- if (S.isImplicitlyDeleted(Best->Function)) {
+ if (S.isImplicitlyDeleted(Best->Function))
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_special_init)
- << S.getSpecialMember(cast<CXXMethodDecl>(Best->Function))
+ << S.getSpecialMember(cast<CXXMethodDecl>(Best->Function))
<< DestType << ArgsRange;
-
- diagnoseImplicitlyDeletedFunction(S,
- cast<CXXMethodDecl>(Best->Function));
- break;
- }
-
- S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
- << true << DestType << ArgsRange;
- S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << 1 << Best->Function->isDeleted();
+ else
+ S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
+ << true << DestType << ArgsRange;
+
+ S.NoteDeletedFunction(Best->Function);
break;
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index ed5a8da61c..a8d7b1e971 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -2274,8 +2274,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
- Result->setSuccess(!DD->isDeleted());
- Result->setConstParamMatch(false);
+ Result->setKind(DD->isDeleted() ?
+ SpecialMemberOverloadResult::NoMemberOrDeleted :
+ SpecialMemberOverloadResult::SuccessNonConst);
return Result;
}
@@ -2345,7 +2346,8 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// will always be a (possibly implicit) declaration to shadow any others.
OverloadCandidateSet OCS((SourceLocation()));
DeclContext::lookup_iterator I, E;
- Result->setConstParamMatch(false);
+ SpecialMemberOverloadResult::Kind SuccessKind =
+ SpecialMemberOverloadResult::SuccessNonConst;
llvm::tie(I, E) = RD->lookup(Name);
assert((I != E) &&
@@ -2384,7 +2386,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);
if (!ArgType->isReferenceType() ||
ArgType->getPointeeType().isConstQualified())
- Result->setConstParamMatch(true);
+ SuccessKind = SpecialMemberOverloadResult::SuccessConst;
}
} else if (FunctionTemplateDecl *Tmpl =
dyn_cast<FunctionTemplateDecl>(Cand)) {
@@ -2406,18 +2408,22 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) {
case OR_Success:
Result->setMethod(cast<CXXMethodDecl>(Best->Function));
- Result->setSuccess(true);
+ Result->setKind(SuccessKind);
break;
case OR_Deleted:
Result->setMethod(cast<CXXMethodDecl>(Best->Function));
- Result->setSuccess(false);
+ Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted);
break;