Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2245,6 +2245,11 @@ def note_final_dtor_non_final_class_silence : Note< "mark %0 as '%select{final|sealed}1' to silence this warning">; +def warn_missing_custom_copy : Warning< + "class implements custom %select{copy assignment operator|copy constructor}0 " + "but missing custom %select{copy assignment operator|copy constructor}1">, + InGroup>; + // C++11 attributes def err_repeat_attribute : Error<"%0 attribute cannot be repeated">; Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -6279,6 +6279,14 @@ } } + // Warn if the class implements custom copy constructor but missing + // custom copy assignment operator and vice versa. + if (Record->hasUserDeclaredCopyAssignment() != + Record->hasUserDeclaredCopyConstructor()) + Diag(Record->getLocation(), diag::warn_missing_custom_copy) + << Record->hasUserDeclaredCopyConstructor() + << !Record->hasUserDeclaredCopyConstructor(); + // Warn if the class has virtual methods but non-virtual public destructor. if (Record->isPolymorphic() && !Record->isDependentType()) { CXXDestructorDecl *dtor = Record->getDestructor(); Index: test/SemaCXX/warn-custom-copy.cpp =================================================================== --- test/SemaCXX/warn-custom-copy.cpp +++ test/SemaCXX/warn-custom-copy.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wcustom-copy %s +// RUN: %clang_cc1 -fsyntax-only -verify %s + +class Clz // expected-warning {{class implements custom copy assignment operator but missing custom copy constructor}} + +{ + char *buf; + +public: + Clz() : buf(nullptr) {} + Clz &operator=(const Clz &r) { + buf = r.buf; + return *this; + } +}; + +class Clz2 // expected-warning {{class implements custom copy assignment operator but missing custom copy constructor}} + +{ + char *buf; + +public: + Clz2() : buf(nullptr) {} + Clz2(const Clz2 &r) : buf(nullptr) { + (void)buf; + (void)r; + } +}; + +class Clz3 { + char *buf; + +public: + Clz3() : buf(nullptr) {} + Clz3(const Clz3 &r) : buf(nullptr) { + (void)buf; + (void)r; + } + Clz3 &operator=(const Clz3 &r) { + buf = r.buf; + return *this; + } +};