From 36155c14b691720ee3e94bfe99886229650bbfb5 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 13 Jun 2013 03:23:42 +0000 Subject: [PATCH] C++11: If a class has a user-declared copy operation or destructor, the implicit definition of a copy operation is deprecated. Add a warning for this to -Wdeprecated. This warning is disabled by default for now, pending investigation into how common this situation is. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183884 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 5 ++ lib/Sema/SemaDeclCXX.cpp | 68 +++++++++++++++++++++- test/SemaCXX/deprecated.cpp | 24 ++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f296c5268a..589fd4529f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -294,6 +294,11 @@ def warn_exception_spec_deprecated : Warning< "dynamic exception specifications are deprecated">, InGroup, DefaultIgnore; def note_exception_spec_deprecated : Note<"use '%0' instead">; +def warn_deprecated_copy_operation : Warning< + "definition of implicit copy %select{constructor|assignment operator}1 " + "for %0 is deprecated because it has a user-declared " + "%select{copy %select{assignment operator|constructor}1|destructor}2">, + InGroup, DefaultIgnore; def warn_global_constructor : Warning< "declaration requires a global constructor">, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a4549fb892..d09b0ee2a5 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -8808,6 +8808,58 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { return CopyAssignment; } +/// Diagnose an implicit copy operation for a class which is odr-used, but +/// which is deprecated because the class has a user-declared copy constructor, +/// copy assignment operator, or destructor. +static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp, + SourceLocation UseLoc) { + assert(CopyOp->isImplicit()); + + CXXRecordDecl *RD = CopyOp->getParent(); + CXXMethodDecl *UserDeclaredOperation = 0; + + // In Microsoft mode, assignment operations don't affect constructors and + // vice versa. + if (RD->hasUserDeclaredDestructor()) { + UserDeclaredOperation = RD->getDestructor(); + } else if (!isa(CopyOp) && + RD->hasUserDeclaredCopyConstructor() && + !S.getLangOpts().MicrosoftMode) { + // Find any user-declared copy constructor. + for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), + E = RD->ctor_end(); I != E; ++I) { + if (I->isCopyConstructor()) { + UserDeclaredOperation = *I; + break; + } + } + assert(UserDeclaredOperation); + } else if (isa(CopyOp) && + RD->hasUserDeclaredCopyAssignment() && + !S.getLangOpts().MicrosoftMode) { + // Find any user-declared move assignment operator. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + if (I->isCopyAssignmentOperator()) { + UserDeclaredOperation = *I; + break; + } + } + assert(UserDeclaredOperation); + } + + if (UserDeclaredOperation) { + S.Diag(UserDeclaredOperation->getLocation(), + diag::warn_deprecated_copy_operation) + << RD << /*copy assignment*/!isa(CopyOp) + << /*destructor*/isa(UserDeclaredOperation); + S.Diag(UseLoc, diag::note_member_synthesized_at) + << (isa(CopyOp) ? Sema::CXXCopyConstructor + : Sema::CXXCopyAssignment) + << RD; + } +} + void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *CopyAssignOperator) { assert((CopyAssignOperator->isDefaulted() && @@ -8823,7 +8875,14 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CopyAssignOperator->setInvalidDecl(); return; } - + + // C++11 [class.copy]p18: + // The [definition of an implicitly declared copy assignment operator] is + // deprecated if the class has a user-declared copy constructor or a + // user-declared destructor. + if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit()) + diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation); + CopyAssignOperator->setUsed(); SynthesizedFunctionScope Scope(*this, CopyAssignOperator); @@ -9631,6 +9690,13 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); + // C++11 [class.copy]p7: + // The [definition of an implicitly declared copy constructro] is + // deprecated if the class has a user-declared copy assignment operator + // or a user-declared destructor. + if (getLangOpts().CPlusPlus11 && CopyConstructor->isImplicit()) + diagnoseDeprecatedCopyOperation(*this, CopyConstructor, CurrentLocation); + SynthesizedFunctionScope Scope(*this, CopyConstructor); DiagnosticErrorTrap Trap(Diags); diff --git a/test/SemaCXX/deprecated.cpp b/test/SemaCXX/deprecated.cpp index 74dbf25356..b69dcb09dd 100644 --- a/test/SemaCXX/deprecated.cpp +++ b/test/SemaCXX/deprecated.cpp @@ -33,3 +33,27 @@ struct T : private S { // expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}} #endif }; + +#if __cplusplus >= 201103L +namespace DeprecatedCopy { + struct Assign { + Assign &operator=(const Assign&); // expected-warning {{definition of implicit copy constructor for 'Assign' is deprecated because it has a user-declared copy assignment operator}} + }; + Assign a1, a2(a1); // expected-note {{implicit default copy constructor for 'Assign' first required here}} + + struct Ctor { + Ctor(); + Ctor(const Ctor&); // expected-warning {{definition of implicit copy assignment operator for 'Ctor' is deprecated because it has a user-declared copy constructor}} + }; + Ctor b1, b2; + void f() { b1 = b2; } // expected-note {{implicit default copy assignment operator for 'Ctor' first required here}} + + struct Dtor { + ~Dtor(); + // expected-warning@-1 {{definition of implicit copy constructor for 'Dtor' is deprecated because it has a user-declared destructor}} + // expected-warning@-2 {{definition of implicit copy assignment operator for 'Dtor' is deprecated because it has a user-declared destructor}} + }; + Dtor c1, c2(c1); // expected-note {{implicit default copy constructor for 'Dtor' first required here}} + void g() { c1 = c2; } // expected-note {{implicit default copy assignment operator for 'Dtor' first required here}} +} +#endif -- 2.40.0