aaron.ballman created this revision. aaron.ballman added reviewers: rsmith, dblaikie. aaron.ballman added a subscriber: cfe-commits.
All copy operations were created equal (as far as the core language is concerned), but some copy operations are more equal than others (as far as the library is concerned). The same is true of move operations. This patch diagnoses copy and move operations (constructors and assignment operators) that are non-idiomatic so that users are not surprised when their copyable type cannot be placed in a standard library container or used with a standard library algorithm. Idiomatic copy and move operations are (where T is the class type for the object): Copy Constructor: takes a const T& Move constructor: takes a T&& Copy Assignment: takes a const T&, returns a T&, and has no ref-qualifiers Move Assignment: takes a T&&, returns a T&, and has no ref-qualifiers This patch does not diagnose *all* non-idiomatic uses because of false positives in practice. Specifically, it does not diagnose when a non-idiomatic operation is overloaded with an idiomatic one (T(const T&); T(T&);) or when there are multiple non-idiomatic operation overloads (T(volatile T&); T(T&);). In both cases, it is reasonable to assume that the user knows they have non-idiomatic signatures. This means that the diagnostic can always be suppressed by either converting the operation into an idiomatic one, or by adding an overload that is deleted (or is private, as in pre-C++11 code bases), depending on the behavior they desire. One thing this patch does could have are fix-it hints to correct the types involved. However, I cannot find a way to get the full source range for the type, including qualifiers. For a parameter of type 'const volatile T&', the TypeLoc appears to only track the location of T&, but not the qualifiers. Assistance in understanding how to do this would be appreciated. http://reviews.llvm.org/D15456 Files: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDeclCXX.cpp test/Analysis/NewDelete-checker-test.cpp test/Analysis/inlining/path-notes.cpp test/Analysis/operator-calls.cpp test/CXX/basic/basic.types/p10.cpp test/CXX/class.access/p4.cpp test/CXX/class/class.union/p1.cpp test/CXX/class/p6-0x.cpp test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp test/CXX/drs/dr0xx.cpp test/CXX/drs/dr1xx.cpp test/CXX/drs/dr3xx.cpp test/CXX/drs/dr5xx.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp test/CXX/special/class.copy/implicit-move.cpp test/CXX/special/class.copy/p11.0x.copy.cpp test/CXX/special/class.copy/p12-0x.cpp test/CXX/special/class.copy/p18-cxx11.cpp test/CXX/special/class.copy/p20.cpp test/CXX/special/class.copy/p23-cxx11.cpp test/CXX/special/class.copy/p25-0x.cpp test/CXX/special/class.copy/p8-cxx11.cpp test/CXX/special/class.copy/p9.cpp test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp test/CXX/stmt.stmt/stmt.dcl/p3.cpp test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp test/CodeGenCXX/copy-assign-synthesis-3.cpp test/OpenMP/for_firstprivate_messages.cpp test/OpenMP/for_lastprivate_messages.cpp test/OpenMP/for_reduction_messages.cpp test/OpenMP/for_simd_lastprivate_messages.cpp test/OpenMP/for_simd_reduction_messages.cpp test/OpenMP/parallel_copyin_messages.cpp test/OpenMP/parallel_for_copyin_messages.cpp test/OpenMP/parallel_for_lastprivate_messages.cpp test/OpenMP/parallel_for_reduction_messages.cpp test/OpenMP/parallel_for_simd_copyin_messages.cpp test/OpenMP/parallel_for_simd_lastprivate_messages.cpp test/OpenMP/parallel_for_simd_reduction_messages.cpp test/OpenMP/parallel_reduction_messages.cpp test/OpenMP/parallel_sections_copyin_messages.cpp test/OpenMP/parallel_sections_lastprivate_messages.cpp test/OpenMP/parallel_sections_reduction_messages.cpp test/OpenMP/parallel_sections_shared_messages.cpp test/OpenMP/parallel_shared_messages.cpp test/OpenMP/sections_lastprivate_messages.cpp test/OpenMP/sections_reduction_messages.cpp test/OpenMP/simd_lastprivate_messages.cpp test/OpenMP/simd_reduction_messages.cpp test/OpenMP/single_copyprivate_messages.cpp test/OpenMP/target_map_messages.cpp test/OpenMP/task_shared_messages.cpp test/OpenMP/taskloop_firstprivate_messages.cpp test/OpenMP/taskloop_lastprivate_messages.cpp test/OpenMP/taskloop_simd_firstprivate_messages.cpp test/OpenMP/taskloop_simd_lastprivate_messages.cpp test/OpenMP/teams_reduction_messages.cpp test/OpenMP/teams_shared_messages.cpp test/Parser/cxx0x-ambig.cpp test/SemaCUDA/implicit-copy.cu test/SemaCUDA/implicit-member-target.cu test/SemaCXX/MicrosoftCompatibility.cpp test/SemaCXX/conditional-expr.cpp test/SemaCXX/conversion-function.cpp test/SemaCXX/copy-assignment.cpp test/SemaCXX/copy-initialization.cpp test/SemaCXX/coroutines.cpp test/SemaCXX/cxx0x-cursory-default-delete.cpp test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp test/SemaCXX/cxx98-compat-flags.cpp test/SemaCXX/cxx98-compat-pedantic.cpp test/SemaCXX/cxx98-compat.cpp test/SemaCXX/default-assignment-operator.cpp test/SemaCXX/lambda-expressions.cpp test/SemaCXX/overload-call-copycon.cpp test/SemaCXX/static-cast.cpp test/SemaCXX/type-traits.cpp test/SemaCXX/user-defined-conversions.cpp test/SemaCXX/warn-consumed-analysis.cpp test/SemaCXX/warn-non-idiomatic-copy-move.cpp test/SemaCXX/warn-unused-filescoped.cpp test/SemaObjCXX/property-synthesis-error.mm test/SemaTemplate/constructor-template.cpp test/SemaTemplate/instantiate-decl-init.cpp
Index: test/SemaTemplate/instantiate-decl-init.cpp =================================================================== --- test/SemaTemplate/instantiate-decl-init.cpp +++ test/SemaTemplate/instantiate-decl-init.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wno-non-idiomatic-copy-move -verify %s // expected-no-diagnostics // PR5426 - the non-dependent obj would be fully processed and wrapped in a Index: test/SemaTemplate/constructor-template.cpp =================================================================== --- test/SemaTemplate/constructor-template.cpp +++ test/SemaTemplate/constructor-template.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -Wno-non-idiomatic-copy-move -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wno-non-idiomatic-copy-move -verify -std=c++98 %s +// RUN: %clang_cc1 -fsyntax-only -Wno-non-idiomatic-copy-move -verify -std=c++11 %s struct X0 { // expected-note {{candidate constructor (the implicit copy constructor) not viable}} #if __cplusplus >= 201103L // C++11 or later @@ -9,7 +9,7 @@ X0(int); // expected-note{{candidate}} template<typename T> X0(T); // expected-note {{candidate}} template<typename T, typename U> X0(T*, U*); // expected-note {{candidate}} - + // PR4761 template<typename T> X0() : f0(T::foo) {} // expected-note {{candidate}} int f0; @@ -28,7 +28,7 @@ accept_X0(&f); X0 x0e(&i, &f); X0 x0f(&f, &i); - + X0 x0g(f, &i); // expected-error{{no matching constructor}} } @@ -41,9 +41,9 @@ template<typename T> struct Outer { typedef X1<T> A; - + A alloc; - + explicit Outer(const A& a) : alloc(a) { } }; @@ -66,7 +66,7 @@ X2 test(bool Cond, X2 x2) { if (Cond) return x2; // okay, uses copy constructor - + return X2(); // expected-error{{no matching constructor}} } Index: test/SemaObjCXX/property-synthesis-error.mm =================================================================== --- test/SemaObjCXX/property-synthesis-error.mm +++ test/SemaObjCXX/property-synthesis-error.mm @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class -Wno-non-idiomatic-copy-move %s // rdar: //8550657 @interface NSArray @end Index: test/SemaCXX/warn-unused-filescoped.cpp =================================================================== --- test/SemaCXX/warn-unused-filescoped.cpp +++ test/SemaCXX/warn-unused-filescoped.cpp @@ -55,7 +55,7 @@ void m2(); // expected-warning{{unused}} void m3(); S(const S&); - void operator=(const S&); + S& operator=(const S&); }; template <typename T> @@ -67,11 +67,11 @@ template <typename T> void tf() { } template <> void tf<int>() { } // expected-warning{{unused}} - + struct VS { virtual void vm() { } }; - + struct SVS : public VS { void vm() { } }; @@ -88,7 +88,7 @@ namespace { int x2; // expected-warning{{unused}} - + struct S2 { static int x; // expected-warning{{unused}} }; Index: test/SemaCXX/warn-non-idiomatic-copy-move.cpp =================================================================== --- test/SemaCXX/warn-non-idiomatic-copy-move.cpp +++ test/SemaCXX/warn-non-idiomatic-copy-move.cpp @@ -0,0 +1,129 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s + +struct A1 { + A1(A1&); // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} + A1& operator=(A1&); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} +}; + +struct A2 { + A2(volatile A2&); // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} + A2& operator=(volatile A2&); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} +}; + +struct A3 { + A3(const volatile A3&); // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} + A3& operator=(const volatile A3&); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} +}; + +struct A4 { + A4(const A4&); // ok + A4& operator=(const A4&); // ok +}; + +struct A5 { + A5(const A5&&); // expected-warning {{non-idiomatic move constructor declaration; consider 'T&&' instead}} + A5& operator=(const A5&&); // expected-warning {{non-idiomatic move assignment operator declaration; consider 'T&&' instead}} +}; + +struct A6 { + A6(volatile A6&&); // expected-warning {{non-idiomatic move constructor declaration; consider 'T&&' instead}} + A6& operator=(volatile A6&&); // expected-warning {{non-idiomatic move assignment operator declaration; consider 'T&&' instead}} +}; + +struct A7 { + A7(const volatile A7&&); // expected-warning {{non-idiomatic move constructor declaration; consider 'T&&' instead}} + A7& operator=(const volatile A7&&); // expected-warning {{non-idiomatic move assignment operator declaration; consider 'T&&' instead}} +}; + +struct A8 { + A8(A8&&); // ok + A8& operator=(A8&&); // ok +}; + +struct A9 { + A9& operator=(A9); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} +}; + +struct B { + B&& operator=(const B&); // expected-warning {{non-idiomatic copy assignment operator declaration; consider returning 'T&' instead}} + B&& operator=(B&&); // expected-warning {{non-idiomatic move assignment operator declaration; consider returning 'T&' instead}} +}; + +struct C { + C operator=(const C&); // expected-warning {{non-idiomatic copy assignment operator declaration; consider returning 'T&' instead}} + C operator=(C&&); // expected-warning {{non-idiomatic move assignment operator declaration; consider returning 'T&' instead}} +}; + +struct D { + C& operator=(const D&); // expected-warning {{non-idiomatic copy assignment operator declaration; consider returning 'T&' instead}} + C& operator=(D&&); // expected-warning {{non-idiomatic move assignment operator declaration; consider returning 'T&' instead}} +}; + +struct E { + E& operator=(const E&) &; // expected-warning {{non-idiomatic copy assignment operator declaration; consider removing ref-qualifiers instead}} + E& operator=(E&&) &; // expected-warning {{non-idiomatic move assignment operator declaration; consider removing ref-qualifiers instead}} +}; + +struct F { + F& operator=(F&) = default; // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} + F& operator=(const F&&) = delete; // expected-warning {{non-idiomatic move assignment operator declaration; consider 'T&&' instead}} +}; + +struct G { + // Do not diagnose if the declaration is invalid anyway. + auto operator=(const G&) = default; // expected-error {{must return 'G &'}} +}; + +struct H { + // Do not diagnose non-idiomatic copy/move operations in the presence of + // idiomatic ones. + H(H&); // ok + H(const H&); // ok + + H(const H&&); // ok + H(H&&); // ok + + H& operator=(H&) &; // ok + H& operator=(const H&); // ok + + H& operator=(const volatile H&&) &&; // ok + H& operator=(H&&); // ok +}; + +struct I { + // Do not diagnose things that are not copy or move operations, but are + // instead converting operations. + I(int); // ok + I(int&); // ok + I(int&&); // ok + I(H&); // ok + + I& operator=(int); // ok + I& operator=(int&); // ok + I& operator=(int&&); // ok + I& operator=(H&); // ok + I& operator=(H&&); // ok +}; + +struct K { + // Do not diagnose non-idiomatic operations in the presence of other non- + // idiomatic operations of the same type. + K(K&); // ok + K(volatile K&); // ok + + K(const K&&); // ok + K(volatile K&&); // ok + + K& operator=(const K&) &; // ok + K& operator=(K&); // ok + + K operator=(K&&); // ok + K& operator=(const K&&); // ok +}; + +struct L { + // Do not diagnose as non-idiomatic if the constructor uses default arguments; + // TODO: that should be diagnosed differently. + L(L&, int = 0); // ok + L(const L&&, int = 0); // ok +}; Index: test/SemaCXX/warn-consumed-analysis.cpp =================================================================== --- test/SemaCXX/warn-consumed-analysis.cpp +++ test/SemaCXX/warn-consumed-analysis.cpp @@ -14,37 +14,37 @@ template <typename T> class CONSUMABLE(unconsumed) ConsumableClass { T var; - + public: ConsumableClass(); ConsumableClass(nullptr_t p) RETURN_TYPESTATE(consumed); ConsumableClass(T val) RETURN_TYPESTATE(unconsumed); - ConsumableClass(ConsumableClass<T> &other); + ConsumableClass(const ConsumableClass<T> &other); ConsumableClass(ConsumableClass<T> &&other); - - ConsumableClass<T>& operator=(ConsumableClass<T> &other); + + ConsumableClass<T>& operator=(const ConsumableClass<T> &other); ConsumableClass<T>& operator=(ConsumableClass<T> &&other); ConsumableClass<T>& operator=(nullptr_t) SET_TYPESTATE(consumed); - + template <typename U> ConsumableClass<T>& operator=(ConsumableClass<U> &other); - + template <typename U> ConsumableClass<T>& operator=(ConsumableClass<U> &&other); - + void operator()(int a) SET_TYPESTATE(consumed); void operator*() const CALLABLE_WHEN("unconsumed"); void unconsumedCall() const CALLABLE_WHEN("unconsumed"); void callableWhenUnknown() const CALLABLE_WHEN("unconsumed", "unknown"); - + bool isValid() const TEST_TYPESTATE(unconsumed); operator bool() const TEST_TYPESTATE(unconsumed); bool operator!=(nullptr_t) const TEST_TYPESTATE(unconsumed); bool operator==(nullptr_t) const TEST_TYPESTATE(consumed); - + void constCall() const; void nonconstCall(); - + void consume() SET_TYPESTATE(consumed); void unconsume() SET_TYPESTATE(unconsumed); }; @@ -53,9 +53,9 @@ public: DestructorTester(); DestructorTester(int); - + void operator*() CALLABLE_WHEN("unconsumed"); - + ~DestructorTester() CALLABLE_WHEN("consumed"); }; @@ -94,14 +94,14 @@ var0 = ConsumableClass<int>(42); *var0; - + var0 = var1; *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - + if (var0.isValid()) { *var0; *var1; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} } @@ -109,13 +109,13 @@ void testDestruction() { DestructorTester D0(42), D1(42), D2; - + *D0; *D1; *D2; // expected-warning {{invalid invocation of method 'operator*' on object 'D2' while it is in the 'consumed' state}} - + D0.~DestructorTester(); // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}} - + return; // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}} \ expected-warning {{invalid invocation of method '~DestructorTester' on object 'D1' while it is in the 'unconsumed' state}} } @@ -127,12 +127,12 @@ void testSimpleRValueRefs() { ConsumableClass<int> var0; ConsumableClass<int> var1(42); - + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; - + var0 = static_cast<ConsumableClass<int>&&>(var1); - + *var0; *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } @@ -139,31 +139,31 @@ void testIfStmt() { ConsumableClass<int> var; - + if (var.isValid()) { *var; } else { *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } - + if (!var.isValid()) { *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } else { *var; } - + if (var) { // Empty } else { *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } - + if (var != nullptr) { // Empty } else { *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } - + if (var == nullptr) { *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } else { @@ -173,90 +173,90 @@ void testComplexConditionals0() { ConsumableClass<int> var0, var1, var2; - + if (var0 && var1) { *var0; *var1; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } - + if (var0 || var1) { *var0; *var1; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } - + if (var0 && !var1) { *var0; *var1; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } - + if (var0 || !var1) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; *var1; } - + if (!var0 && !var1) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; *var1; } - + if (!var0 || !var1) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; *var1; } - + if (!(var0 && var1)) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; *var1; } - + if (!(var0 || var1)) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; *var1; } - + if (var0 && var1 && var2) { *var0; *var1; *var2; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}} } - + #if 0 // FIXME: Get this test to pass. if (var0 || var1 || var2) { @@ -263,7 +263,7 @@ *var0; *var1; *var2; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} @@ -274,95 +274,95 @@ void testComplexConditionals1() { ConsumableClass<int> var0, var1, var2; - + // Coerce all variables into the unknown state. baf4(var0); baf4(var1); baf4(var2); - + if (var0 && var1) { *var0; *var1; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} } - + if (var0 || var1) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } - + if (var0 && !var1) { *var0; *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} } - + if (var0 || !var1) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; } - + if (!var0 && !var1) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} } - + if (!(var0 || var1)) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} } - + if (!var0 || !var1) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} - + } else { *var0; *var1; } - + if (!(var0 && var1)) { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} - + } else { *var0; *var1; } - + if (var0 && var1 && var2) { *var0; *var1; *var2; - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'unknown' state}} } - + #if 0 // FIXME: Get this test to pass. if (var0 || var1 || var2) { @@ -369,7 +369,7 @@ *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'unknown' state}} - + } else { *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} @@ -380,50 +380,50 @@ void testStateChangeInBranch() { ConsumableClass<int> var; - + // Make var enter the 'unknown' state. baf4(var); - + if (!var) { var = ConsumableClass<int>(42); } - + *var; } void testFunctionParam(ConsumableClass<int> param) { - + if (param.isValid()) { *param; } else { *param; } - + param = nullptr; *param; // expected-warning {{invocation of method 'operator*' on object 'param' while it is in the 'consumed' state}} } void testParamReturnTypestateCallee(bool cond, ConsumableClass<int> &Param RETURN_TYPESTATE(unconsumed)) { // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}} - + if (cond) { Param.consume(); return; // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}} } - + Param.consume(); } void testParamReturnTypestateCaller() { ConsumableClass<int> var; - + testParamReturnTypestateCallee(true, var); - + *var; } void testParamTypestateCallee(ConsumableClass<int> Param0 PARAM_TYPESTATE(consumed), ConsumableClass<int> &Param1 PARAM_TYPESTATE(consumed)) { - + *Param0; // expected-warning {{invalid invocation of method 'operator*' on object 'Param0' while it is in the 'consumed' state}} *Param1; // expected-warning {{invalid invocation of method 'operator*' on object 'Param1' while it is in the 'consumed' state}} } @@ -430,7 +430,7 @@ void testParamTypestateCaller() { ConsumableClass<int> Var0, Var1(42); - + testParamTypestateCallee(Var0, Var1); // expected-warning {{argument not in expected state; expected 'consumed', observed 'unconsumed'}} } @@ -471,34 +471,34 @@ void testCallingConventions() { ConsumableClass<int> var(42); - - baf0(var); + + baf0(var); *var; - - baf1(var); + + baf1(var); *var; - - baf2(&var); + + baf2(&var); *var; - - baf4(var); + + baf4(var); *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} - + var = ConsumableClass<int>(42); - baf5(&var); + baf5(&var); *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} - + var = ConsumableClass<int>(42); - baf6(static_cast<ConsumableClass<int>&&>(var)); + baf6(static_cast<ConsumableClass<int>&&>(var)); *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConstAndNonConstMemberFunctions() { ConsumableClass<int> var(42); - + var.constCall(); *var; - + var.nonconstCall(); *var; } @@ -513,10 +513,10 @@ void testReturnStates() { ConsumableClass<int> var; - + var = returnsUnconsumed(); *var; - + var = returnsConsumed(); *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } @@ -523,11 +523,11 @@ void testCallableWhen() { ConsumableClass<int> var(42); - + *var; - + baf4(var); - + var.callableWhenUnknown(); } @@ -534,15 +534,15 @@ void testMoveAsignmentish() { ConsumableClass<int> var0; ConsumableClass<long> var1(42); - + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; - + var0 = static_cast<ConsumableClass<long>&&>(var1); - + *var0; *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - + var1 = ConsumableClass<long>(42); var1 = nullptr; *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} @@ -550,60 +550,60 @@ void testConditionalMerge() { ConsumableClass<int> var; - + if (var.isValid()) { // Empty } - + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} - + if (var.isValid()) { // Empty } else { // Empty } - + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testSetTypestate() { ConsumableClass<int> var(42); - + *var; - + var.consume(); - + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} - + var.unconsume(); - + *var; } void testConsumes0() { ConsumableClass<int> var(nullptr); - + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConsumes1() { ConsumableClass<int> var(42); - + var.unconsumedCall(); var(6); - + var.unconsumedCall(); // expected-warning {{invalid invocation of method 'unconsumedCall' on object 'var' while it is in the 'consumed' state}} } void testUnreachableBlock() { ConsumableClass<int> var(42); - + if (var) { *var; } else { *var; } - + *var; } @@ -610,31 +610,31 @@ void testForLoop1() { ConsumableClass<int> var0, var1(42); - + for (int i = 0; i < 10; ++i) { // expected-warning {{state of variable 'var1' must match at the entry and exit of loop}} *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - + *var1; var1.consume(); *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } - + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} } void testWhileLoop1() { int i = 10; - + ConsumableClass<int> var0, var1(42); - + while (i-- > 0) { // expected-warning {{state of variable 'var1' must match at the entry and exit of loop}} *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - + *var1; var1.consume(); *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } - + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} } @@ -801,7 +801,7 @@ void testTemporariesWithConditionals1() { int a; - + Status s = doSomething(); if (cond()) a = 0; else a = 1; @@ -810,7 +810,7 @@ void testTemporariesWithConditionals2() { int a; - + Status s = doSomething(); s.ignore(); if (cond()) a = 0; Index: test/SemaCXX/user-defined-conversions.cpp =================================================================== --- test/SemaCXX/user-defined-conversions.cpp +++ test/SemaCXX/user-defined-conversions.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s struct X { operator bool(); }; @@ -39,7 +39,7 @@ // Test conversion followed by copy-construction struct FunkyDerived; -struct Base { +struct Base { Base(const FunkyDerived&); }; @@ -69,7 +69,8 @@ } struct X1 { - X1(X1&); // expected-note{{candidate constructor not viable: expects an l-value for 1st argument}} + X1(X1&); // expected-note{{candidate constructor not viable: expects an l-value for 1st argument}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; struct X2 { Index: test/SemaCXX/type-traits.cpp =================================================================== --- test/SemaCXX/type-traits.cpp +++ test/SemaCXX/type-traits.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft -Wno-non-idiomatic-copy-move %s #define T(b) (b) ? 1 : -1 #define F(b) (b) ? -1 : 1 @@ -40,17 +40,17 @@ struct HasCons { HasCons(int); }; struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); }; struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; -struct HasNoThrowMoveAssign { +struct HasNoThrowMoveAssign { HasNoThrowMoveAssign& operator=( const HasNoThrowMoveAssign&&) throw(); }; -struct HasNoExceptNoThrowMoveAssign { +struct HasNoExceptNoThrowMoveAssign { HasNoExceptNoThrowMoveAssign& operator=( - const HasNoExceptNoThrowMoveAssign&&) noexcept; + const HasNoExceptNoThrowMoveAssign&&) noexcept; }; -struct HasThrowMoveAssign { +struct HasThrowMoveAssign { HasThrowMoveAssign& operator=( const HasThrowMoveAssign&&) throw(POD); }; -struct HasNoExceptFalseMoveAssign { +struct HasNoExceptFalseMoveAssign { HasNoExceptFalseMoveAssign& operator=( const HasNoExceptFalseMoveAssign&&) noexcept(false); }; struct HasMoveCtor { HasMoveCtor(const HasMoveCtor&&); }; @@ -59,17 +59,17 @@ struct HasStaticMemberMoveCtor { static HasMoveCtor member; }; struct HasStaticMemberMoveAssign { static HasMoveAssign member; }; struct HasMemberThrowMoveAssign { HasThrowMoveAssign member; }; -struct HasMemberNoExceptFalseMoveAssign { +struct HasMemberNoExceptFalseMoveAssign { HasNoExceptFalseMoveAssign member; }; struct HasMemberNoThrowMoveAssign { HasNoThrowMoveAssign member; }; -struct HasMemberNoExceptNoThrowMoveAssign { +struct HasMemberNoExceptNoThrowMoveAssign { HasNoExceptNoThrowMoveAssign member; }; -struct HasDefaultTrivialCopyAssign { +struct HasDefaultTrivialCopyAssign { HasDefaultTrivialCopyAssign &operator=( - const HasDefaultTrivialCopyAssign&) = default; + const HasDefaultTrivialCopyAssign&) = default; }; -struct TrivialMoveButNotCopy { +struct TrivialMoveButNotCopy { TrivialMoveButNotCopy &operator=(TrivialMoveButNotCopy&&) = default; TrivialMoveButNotCopy &operator=(const TrivialMoveButNotCopy&); }; @@ -306,7 +306,7 @@ struct FinalClass final { }; -template<typename T> +template<typename T> struct PotentiallyFinal { }; template<typename T> @@ -1329,7 +1329,7 @@ { int arr[T(__has_trivial_move_constructor(HasCons))]; } { int arr[T(__has_trivial_move_constructor(HasStaticMemberMoveCtor))]; } { int arr[T(__has_trivial_move_constructor(AllDeleted))]; } - + { int arr[F(__has_trivial_move_constructor(HasVirt))]; } { int arr[F(__has_trivial_move_constructor(DerivesVirt))]; } { int arr[F(__has_trivial_move_constructor(HasMoveCtor))]; } @@ -1762,7 +1762,7 @@ }; template<typename T> -struct X0 { +struct X0 { template<typename U> X0(const X0<U>&); }; Index: test/SemaCXX/static-cast.cpp =================================================================== --- test/SemaCXX/static-cast.cpp +++ test/SemaCXX/static-cast.cpp @@ -157,9 +157,9 @@ struct X1 { X1(); - X1(X1&); + X1(const X1&); X1(const X0&); - + operator X0() const; }; @@ -178,11 +178,11 @@ struct X4 { typedef const X3 X3_typedef; - + void f() const { (void)static_cast<X3_typedef*>(x2); } - + const X2 *x2; }; @@ -190,7 +190,7 @@ void PR5897() { (void)static_cast<const int(*)[1]>((const void*)0); } namespace PR6072 { - struct A { }; + struct A { }; struct B : A { void f(int); void f(); }; // expected-note 2{{candidate function}} struct C : B { }; struct D { }; Index: test/SemaCXX/overload-call-copycon.cpp =================================================================== --- test/SemaCXX/overload-call-copycon.cpp +++ test/SemaCXX/overload-call-copycon.cpp @@ -20,7 +20,8 @@ class A { public: A(A&); // expected-note{{would lose const qualifier}} \ - // expected-note{{no known conversion}} + // expected-note{{no known conversion}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; class B : public A { }; // expected-note{{would lose const qualifier}} \ Index: test/SemaCXX/MicrosoftCompatibility.cpp =================================================================== --- test/SemaCXX/MicrosoftCompatibility.cpp +++ test/SemaCXX/MicrosoftCompatibility.cpp @@ -77,7 +77,7 @@ } } - + void exception_jump() { goto l2; // expected-error {{cannot jump}} try { // expected-note {{jump bypasses initialization of try block}} @@ -93,13 +93,13 @@ a0: return 0; } - + } namespace PR11826 { struct pair { pair(int v) { } - void operator=(pair&& rhs) { } + pair& operator=(pair&& rhs) { return *this; } }; void f() { pair p0(3); @@ -122,12 +122,12 @@ namespace ms_using_declaration_bug { class A { -public: - int f(); +public: + int f(); }; class B : public A { -private: +private: using A::f; void g() { f(); // no diagnostic @@ -134,8 +134,8 @@ } }; -class C : public B { -private: +class C : public B { +private: using B::f; // expected-warning {{using declaration referring to inaccessible member 'ms_using_declaration_bug::B::f' (which refers to accessible member 'ms_using_declaration_bug::A::f') is a Microsoft compatibility extension}} }; Index: test/SemaCXX/lambda-expressions.cpp =================================================================== --- test/SemaCXX/lambda-expressions.cpp +++ test/SemaCXX/lambda-expressions.cpp @@ -75,7 +75,8 @@ (void) ^{ return []() { return f[2]; }; }; // expected-error {{variable 'f' cannot be implicitly captured in a lambda with no capture-default specified}} \ // expected-note{{lambda expression begins here}} - struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}} + struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} G g; [=]() { const G* gg = &g; return gg->a; }; [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'G'}} @@ -269,16 +270,16 @@ template<class T> struct L { T t{}; - T t2 = ([](int a) { return [](int b) { return b; };})(t)(t); + T t2 = ([](int a) { return [](int b) { return b; };})(t)(t); }; - L<int> l; - + L<int> l; + namespace non_template { struct L { int t = 0; - int t2 = ([](int a) { return [](int b) { return b; };})(t)(t); + int t2 = ([](int a) { return [](int b) { return b; };})(t)(t); }; - L l; + L l; } } Index: test/SemaCXX/default-assignment-operator.cpp =================================================================== --- test/SemaCXX/default-assignment-operator.cpp +++ test/SemaCXX/default-assignment-operator.cpp @@ -8,18 +8,18 @@ class X : Base { // // expected-error {{cannot define the implicit copy assignment operator for 'X', because non-static const member 'cint' cannot use copy assignment operator}} \ // expected-note{{assignment operator for 'Base' first required here}} -public: +public: X(); const int cint; // expected-note {{declared here}} -}; +}; -struct Y : X { +struct Y : X { Y(); Y& operator=(const Y&); Y& operator=(volatile Y&); Y& operator=(const volatile Y&); Y& operator=(Y&); -}; +}; class Z : Y {}; @@ -46,7 +46,7 @@ class V { public: V(); - V &operator = (V &b); + V &operator = (V &b); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} }; class W : V {}; @@ -61,7 +61,7 @@ class B1 { public: B1(); - B1 &operator = (B1 b); + B1 &operator = (B1 b); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} }; class D1 : B1 {}; @@ -77,7 +77,7 @@ public: const int a; // expected-note{{declared here}} - E1() : a(0) {} + E1() : a(0) {} }; @@ -106,7 +106,7 @@ } namespace MultiplePaths { - struct X0 { + struct X0 { X0 &operator=(const X0&); }; Index: test/SemaCXX/cxx98-compat.cpp =================================================================== --- test/SemaCXX/cxx98-compat.cpp +++ test/SemaCXX/cxx98-compat.cpp @@ -330,7 +330,7 @@ }; struct b { - void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-provided copy assignment operator}} + b& operator=(const b &it) { return *this; } // expected-note {{because type 'AssignOpUnion::b' has a user-provided copy assignment operator}} }; union test1 { Index: test/SemaCXX/cxx98-compat-pedantic.cpp =================================================================== --- test/SemaCXX/cxx98-compat-pedantic.cpp +++ test/SemaCXX/cxx98-compat-pedantic.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat-pedantic -verify %s -DCXX1Y2 -// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat -Werror %s -DCXX1Y2 +// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat -Werror -Wno-non-idiomatic-copy-move %s -DCXX1Y2 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Werror %s -// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s -DCXX98 +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Werror -Wno-non-idiomatic-copy-move %s +// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror -Wno-non-idiomatic-copy-move %s -DCXX98 // RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat-pedantic -verify %s -Wno-c++98-c++11-compat-pedantic -DCXX1Y2 @@ -60,7 +60,8 @@ }; struct NoViable { NoViable(); - NoViable(NoViable&); // expected-note {{not viable}} + NoViable(NoViable&); // expected-note {{not viable}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; struct Ambiguous { Ambiguous(); Index: test/SemaCXX/cxx98-compat-flags.cpp =================================================================== --- test/SemaCXX/cxx98-compat-flags.cpp +++ test/SemaCXX/cxx98-compat-flags.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Werror %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Wno-non-idiomatic-copy-move -Werror %s template<typename T> int TemplateFn(T) { return 0; } void LocalTemplateArg() { @@ -17,7 +17,8 @@ }; struct NoViable { NoViable(); - NoViable(NoViable&); // expected-note {{not viable}} + NoViable(NoViable&); // expected-note {{not viable}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; struct Ambiguous { Ambiguous(); Index: test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp =================================================================== --- test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -175,7 +175,7 @@ template<typename T> X(std::initializer_list<int>, T); }; - + X x({}, 17); } @@ -216,7 +216,7 @@ struct X { X(int i) {} X(const X& x) = delete; // expected-note {{here}} - void operator=(const X& x) = delete; + X& operator=(const X& x) = delete; }; std::initializer_list<X> x{1}; // expected-error {{invokes deleted constructor}} Index: test/SemaCXX/cxx0x-cursory-default-delete.cpp =================================================================== --- test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-non-idiomatic-copy-move -verify %s struct non_copiable { non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}} Index: test/SemaCXX/coroutines.cpp =================================================================== --- test/SemaCXX/coroutines.cpp +++ test/SemaCXX/coroutines.cpp @@ -135,7 +135,7 @@ co_return 0; // expected-error {{'co_return' cannot be used in a destructor}} } // FIXME: The spec says this is ill-formed. - void operator=(CtorDtor&) { + void operator=(CtorDtor&) { // expected-warning {{non-idiomatic copy assignment operator declaration; consider returning 'T&' instead}} co_yield 0; } }; Index: test/SemaCXX/copy-initialization.cpp =================================================================== --- test/SemaCXX/copy-initialization.cpp +++ test/SemaCXX/copy-initialization.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s @@ -31,7 +31,8 @@ namespace PR6757 { struct Foo { Foo(); - Foo(Foo&); // expected-note{{candidate constructor not viable}} + Foo(Foo&); // expected-note{{candidate constructor not viable}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; struct Bar { Index: test/SemaCXX/copy-assignment.cpp =================================================================== --- test/SemaCXX/copy-assignment.cpp +++ test/SemaCXX/copy-assignment.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s struct A { }; @@ -11,7 +11,8 @@ }; struct B { - B& operator=(B&); // expected-note 4 {{candidate function}} + B& operator=(B&); // expected-note 4 {{candidate function}} \ + // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} }; struct ConvertibleToB { Index: test/SemaCXX/conversion-function.cpp =================================================================== --- test/SemaCXX/conversion-function.cpp +++ test/SemaCXX/conversion-function.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -Wbind-to-temporary-copy -verify %s -class X { +// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -Wbind-to-temporary-copy -Wno-non-idiomatic-copy-move -verify %s +class X { public: operator bool(); operator int() const; @@ -28,11 +28,11 @@ // expected-error{{conversion function cannot have any parameters}} operator bool(int a = 4, int b = 6) const; // expected-error{{conversion function cannot have any parameters}} - - + + operator float(...) const; // expected-error{{conversion function cannot be variadic}} - - + + operator func_type(); // expected-error{{conversion function cannot convert to a function type}} operator array_type(); // expected-error{{conversion function cannot convert to an array type}} }; @@ -41,10 +41,10 @@ typedef int INT; typedef INT* INT_PTR; -class Z { +class Z { operator int(); // expected-note {{previous declaration is here}} operator int**(); // expected-note {{previous declaration is here}} - + operator INT(); // expected-error{{conversion function cannot be redeclared}} operator INT_PTR*(); // expected-error{{conversion function cannot be redeclared}} }; @@ -82,12 +82,12 @@ } // Test. Conversion in base class is visible in derived class. -class XB { +class XB { public: operator int(); // expected-note {{candidate function}} }; -class Yb : public XB { +class Yb : public XB { public: operator char(); // expected-note {{candidate function}} }; @@ -103,11 +103,11 @@ class AutoPtr { AutoPtr(AutoPtr &); // expected-note{{declared private here}} - + public: AutoPtr(); AutoPtr(AutoPtrRef); - + operator AutoPtrRef(); }; @@ -115,11 +115,11 @@ AutoPtr test_auto_ptr(bool Cond) { AutoPtr p1( make_auto_ptr() ); - + AutoPtr p; if (Cond) return p; // expected-error{{calling a private constructor}} - + return AutoPtr(); } @@ -159,7 +159,7 @@ const A<float, int> &caf2 = E(); } - // Check + // Check template<typename T> struct E2 { operator T @@ -180,7 +180,7 @@ } namespace smart_ptr { - class Y { + class Y { class YRef { }; Y(Y&); @@ -210,7 +210,7 @@ }; struct Other { - Other(const Other &); + Other(const Other &); Other(); }; @@ -248,7 +248,7 @@ struct Y { Y(X); }; - + Y f2(foo()); } @@ -298,7 +298,7 @@ struct Derived2 : Base { }; - struct SuperDerived : Derived1, Derived2 { + struct SuperDerived : Derived1, Derived2 { using Derived1::operator int; }; @@ -318,7 +318,7 @@ operator int(); }; - struct Derived23 : Base2, Base3 { + struct Derived23 : Base2, Base3 { using Base2::operator int; }; @@ -363,7 +363,7 @@ { template<class Container> operator Container() - { + { Container ar; T* i; ar[0]=*i; Index: test/SemaCXX/conditional-expr.cpp =================================================================== --- test/SemaCXX/conditional-expr.cpp +++ test/SemaCXX/conditional-expr.cpp @@ -8,9 +8,9 @@ struct B; struct A { - A(); + A(); A(const B&); // expected-note 2 {{candidate constructor}} -}; +}; struct B { operator A() const; }; // expected-note 2 {{candidate function}} struct I { operator int(); }; struct J { operator I(); }; @@ -197,8 +197,8 @@ (void)&(i1 ? flds.b1 : flds.i1); // expected-error {{address of bit-field requested}} (void)&(i1 ? flds.i1 : flds.b1); // expected-error {{address of bit-field requested}} - + unsigned long test0 = 5; test0 = test0 ? (long) test0 : test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}} test0 = test0 ? (int) test0 : test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}} @@ -263,7 +263,8 @@ struct Foo3 { Foo3(); - Foo3(Foo3&); // expected-note{{would lose const qualifier}} + Foo3(Foo3&); // expected-note{{would lose const qualifier}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; struct Bar { @@ -297,8 +298,9 @@ } namespace rdar7998817 { - class X { - X(X&); // expected-note{{declared private here}} + class X { + X(X&); // expected-note{{declared private here}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} struct ref { }; @@ -305,7 +307,7 @@ public: X(); X(ref); - + operator ref(); }; Index: test/SemaCUDA/implicit-member-target.cu =================================================================== --- test/SemaCUDA/implicit-member-target.cu +++ test/SemaCUDA/implicit-member-target.cu @@ -98,7 +98,7 @@ struct A5_copy_ctor_constness { __host__ A5_copy_ctor_constness() {} - __host__ A5_copy_ctor_constness(A5_copy_ctor_constness&) {} + __host__ A5_copy_ctor_constness(A5_copy_ctor_constness&) {} // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; struct B5_copy_ctor_constness : A5_copy_ctor_constness { Index: test/SemaCUDA/implicit-copy.cu =================================================================== --- test/SemaCUDA/implicit-copy.cu +++ test/SemaCUDA/implicit-copy.cu @@ -2,10 +2,10 @@ // RUN: %clang_cc1 -std=gnu++11 -triple nvptx64-unknown-unknown -fcuda-is-device -fsyntax-only -verify %s struct CopyableH { - const CopyableH& operator=(const CopyableH& x) { return *this; } + const CopyableH& operator=(const CopyableH& x) { return *this; } // expected-warning {{non-idiomatic copy assignment operator declaration; consider returning 'T&' instead}} }; struct CopyableD { - __attribute__((device)) const CopyableD& operator=(const CopyableD x) { return *this; } + __attribute__((device)) const CopyableD& operator=(const CopyableD x) { return *this; } // expected-warning {{non-idiomatic copy assignment operator declaration; consider returning 'T&' instead}} }; struct SimpleH { Index: test/Parser/cxx0x-ambig.cpp =================================================================== --- test/Parser/cxx0x-ambig.cpp +++ test/Parser/cxx0x-ambig.cpp @@ -38,7 +38,7 @@ constexpr T() {} constexpr T(int) {} constexpr T(T, T, T, T) {} - constexpr T operator=(T) const { return *this; } + constexpr T operator=(T) const { return *this; } // expected-warning {{non-idiomatic copy assignment operator declaration; consider returning 'T&' instead}} constexpr operator int() const { return 4; } }; constexpr T a, b, c, d; Index: test/OpenMP/teams_shared_messages.cpp =================================================================== --- test/OpenMP/teams_shared_messages.cpp +++ test/OpenMP/teams_shared_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/teams_reduction_messages.cpp =================================================================== --- test/OpenMP/teams_reduction_messages.cpp +++ test/OpenMP/teams_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 -o - %s void foo() { } Index: test/OpenMP/taskloop_simd_lastprivate_messages.cpp =================================================================== --- test/OpenMP/taskloop_simd_lastprivate_messages.cpp +++ test/OpenMP/taskloop_simd_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/taskloop_simd_firstprivate_messages.cpp =================================================================== --- test/OpenMP/taskloop_simd_firstprivate_messages.cpp +++ test/OpenMP/taskloop_simd_firstprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/taskloop_lastprivate_messages.cpp =================================================================== --- test/OpenMP/taskloop_lastprivate_messages.cpp +++ test/OpenMP/taskloop_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/taskloop_firstprivate_messages.cpp =================================================================== --- test/OpenMP/taskloop_firstprivate_messages.cpp +++ test/OpenMP/taskloop_firstprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/task_shared_messages.cpp =================================================================== --- test/OpenMP/task_shared_messages.cpp +++ test/OpenMP/task_shared_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 %s void foo() { } Index: test/OpenMP/target_map_messages.cpp =================================================================== --- test/OpenMP/target_map_messages.cpp +++ test/OpenMP/target_map_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 %s void foo() { } @@ -97,7 +97,7 @@ #pragma omp target map(to, x) foo(); #pragma omp target map(to x) // expected-error {{expected ',' or ')' in 'map' clause}} -#pragma omp target map(tofrom: argc > 0 ? x : y) // expected-error 2 {{expected variable name, array element or array section}} +#pragma omp target map(tofrom: argc > 0 ? x : y) // expected-error 2 {{expected variable name, array element or array section}} #pragma omp target map(argc) #pragma omp target map(S1) // expected-error {{'S1' does not refer to a value}} #pragma omp target map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}} Index: test/OpenMP/single_copyprivate_messages.cpp =================================================================== --- test/OpenMP/single_copyprivate_messages.cpp +++ test/OpenMP/single_copyprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/simd_reduction_messages.cpp =================================================================== --- test/OpenMP/simd_reduction_messages.cpp +++ test/OpenMP/simd_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 %s void foo() { } Index: test/OpenMP/simd_lastprivate_messages.cpp =================================================================== --- test/OpenMP/simd_lastprivate_messages.cpp +++ test/OpenMP/simd_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/sections_reduction_messages.cpp =================================================================== --- test/OpenMP/sections_reduction_messages.cpp +++ test/OpenMP/sections_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 -ferror-limit 150 -o - %s void foo() { } Index: test/OpenMP/sections_lastprivate_messages.cpp =================================================================== --- test/OpenMP/sections_lastprivate_messages.cpp +++ test/OpenMP/sections_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/parallel_shared_messages.cpp =================================================================== --- test/OpenMP/parallel_shared_messages.cpp +++ test/OpenMP/parallel_shared_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 %s void foo() { } Index: test/OpenMP/parallel_sections_shared_messages.cpp =================================================================== --- test/OpenMP/parallel_sections_shared_messages.cpp +++ test/OpenMP/parallel_sections_shared_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 %s void foo() { } Index: test/OpenMP/parallel_sections_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_sections_reduction_messages.cpp +++ test/OpenMP/parallel_sections_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 100 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 -ferror-limit 100 -o - %s void foo() { } Index: test/OpenMP/parallel_sections_lastprivate_messages.cpp =================================================================== --- test/OpenMP/parallel_sections_lastprivate_messages.cpp +++ test/OpenMP/parallel_sections_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/parallel_sections_copyin_messages.cpp =================================================================== --- test/OpenMP/parallel_sections_copyin_messages.cpp +++ test/OpenMP/parallel_sections_copyin_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 -o - %s void foo() { } Index: test/OpenMP/parallel_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_reduction_messages.cpp +++ test/OpenMP/parallel_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 100 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 -ferror-limit 100 -o - %s void foo() { } Index: test/OpenMP/parallel_for_simd_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_for_simd_reduction_messages.cpp +++ test/OpenMP/parallel_for_simd_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 -o - %s void foo() { } Index: test/OpenMP/parallel_for_simd_lastprivate_messages.cpp =================================================================== --- test/OpenMP/parallel_for_simd_lastprivate_messages.cpp +++ test/OpenMP/parallel_for_simd_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/parallel_for_simd_copyin_messages.cpp =================================================================== --- test/OpenMP/parallel_for_simd_copyin_messages.cpp +++ test/OpenMP/parallel_for_simd_copyin_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -o - %s void foo() { } Index: test/OpenMP/parallel_for_reduction_messages.cpp =================================================================== --- test/OpenMP/parallel_for_reduction_messages.cpp +++ test/OpenMP/parallel_for_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 100 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 -ferror-limit 100 -o - %s void foo() { } Index: test/OpenMP/parallel_for_lastprivate_messages.cpp =================================================================== --- test/OpenMP/parallel_for_lastprivate_messages.cpp +++ test/OpenMP/parallel_for_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/parallel_for_copyin_messages.cpp =================================================================== --- test/OpenMP/parallel_for_copyin_messages.cpp +++ test/OpenMP/parallel_for_copyin_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 -o - %s void foo() { } Index: test/OpenMP/parallel_copyin_messages.cpp =================================================================== --- test/OpenMP/parallel_copyin_messages.cpp +++ test/OpenMP/parallel_copyin_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 100 -o - %s void foo() { } Index: test/OpenMP/for_simd_reduction_messages.cpp =================================================================== --- test/OpenMP/for_simd_reduction_messages.cpp +++ test/OpenMP/for_simd_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 %s void foo() { } Index: test/OpenMP/for_simd_lastprivate_messages.cpp =================================================================== --- test/OpenMP/for_simd_lastprivate_messages.cpp +++ test/OpenMP/for_simd_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/OpenMP/for_reduction_messages.cpp =================================================================== --- test/OpenMP/for_reduction_messages.cpp +++ test/OpenMP/for_reduction_messages.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++98 -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp -std=c++11 -ferror-limit 150 -o - %s void foo() { } Index: test/OpenMP/for_lastprivate_messages.cpp =================================================================== --- test/OpenMP/for_lastprivate_messages.cpp +++ test/OpenMP/for_lastprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -fopenmp -Wno-non-idiomatic-copy-move %s void foo() { } Index: test/OpenMP/for_firstprivate_messages.cpp =================================================================== --- test/OpenMP/for_firstprivate_messages.cpp +++ test/OpenMP/for_firstprivate_messages.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp %s +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move -fopenmp %s void foo() { } Index: test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp =================================================================== --- test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp +++ test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-non-idiomatic-copy-move %s // expected-no-diagnostics #if !__has_feature(cxx_access_control_sfinae) Index: test/CXX/stmt.stmt/stmt.dcl/p3.cpp =================================================================== --- test/CXX/stmt.stmt/stmt.dcl/p3.cpp +++ test/CXX/stmt.stmt/stmt.dcl/p3.cpp @@ -36,7 +36,7 @@ } struct Z { - Z operator=(const Z&); + Z& operator=(const Z&); }; void test_Z() { Index: test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp =================================================================== --- test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp +++ test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp @@ -38,13 +38,13 @@ { Y y2; // expected-note{{jump bypasses variable with a non-trivial destructor}} inner: - f(); + f(); } return; } struct Z { - Z operator=(const Z&); + Z& operator=(const Z&); }; void test_Z() { Index: test/CXX/special/class.copy/p9.cpp =================================================================== --- test/CXX/special/class.copy/p9.cpp +++ test/CXX/special/class.copy/p9.cpp @@ -7,10 +7,10 @@ struct NonConstCopy { NonConstCopy(); - NonConstCopy(NonConstCopy&); + NonConstCopy(NonConstCopy&); // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; -struct VirtualInheritsNonConstCopy : virtual NonConstCopy { +struct VirtualInheritsNonConstCopy : virtual NonConstCopy { VirtualInheritsNonConstCopy(); VirtualInheritsNonConstCopy(const VirtualInheritsNonConstCopy&); }; Index: test/CXX/special/class.copy/p8-cxx11.cpp =================================================================== --- test/CXX/special/class.copy/p8-cxx11.cpp +++ test/CXX/special/class.copy/p8-cxx11.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 %s -verify +// RUN: %clang_cc1 -std=c++11 %s -verify -Wno-non-idiomatic-copy-move // expected-no-diagnostics // C++98 [class.copy]p5 / C++11 [class.copy]p8. Index: test/CXX/special/class.copy/p25-0x.cpp =================================================================== --- test/CXX/special/class.copy/p25-0x.cpp +++ test/CXX/special/class.copy/p25-0x.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -verify %s +// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-non-idiomatic-copy-move // expected-no-diagnostics Index: test/CXX/special/class.copy/p23-cxx11.cpp =================================================================== --- test/CXX/special/class.copy/p23-cxx11.cpp +++ test/CXX/special/class.copy/p23-cxx11.cpp @@ -50,7 +50,7 @@ InaccessibleMoveAssign &operator=(InaccessibleMoveAssign &&); }; class NonConstCopyAssign { - NonConstCopyAssign &operator=(NonConstCopyAssign &); + NonConstCopyAssign &operator=(NonConstCopyAssign &); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} }; // A defaulted copy/move assignment operator for class X is defined as deleted Index: test/CXX/special/class.copy/p20.cpp =================================================================== --- test/CXX/special/class.copy/p20.cpp +++ test/CXX/special/class.copy/p20.cpp @@ -7,10 +7,10 @@ struct NonConstCopy { NonConstCopy(); - NonConstCopy &operator=(NonConstCopy&); + NonConstCopy &operator=(NonConstCopy&); // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} }; -struct VirtualInheritsNonConstCopy : virtual NonConstCopy { +struct VirtualInheritsNonConstCopy : virtual NonConstCopy { VirtualInheritsNonConstCopy(); VirtualInheritsNonConstCopy &operator=(const VirtualInheritsNonConstCopy&); }; @@ -29,7 +29,7 @@ NonConstCopy ncc_array[2][3]; }; -struct ImplicitNonConstCopy4 : VirtualInheritsNonConstCopy { +struct ImplicitNonConstCopy4 : VirtualInheritsNonConstCopy { ImplicitNonConstCopy4(); }; Index: test/CXX/special/class.copy/p18-cxx11.cpp =================================================================== --- test/CXX/special/class.copy/p18-cxx11.cpp +++ test/CXX/special/class.copy/p18-cxx11.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 %s -verify +// RUN: %clang_cc1 -std=c++11 %s -verify -Wno-non-idiomatic-copy-move // expected-no-diagnostics // C++98 [class.copy]p10 / C++11 [class.copy]p18. Index: test/CXX/special/class.copy/p12-0x.cpp =================================================================== --- test/CXX/special/class.copy/p12-0x.cpp +++ test/CXX/special/class.copy/p12-0x.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -verify %s +// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-non-idiomatic-copy-move // expected-no-diagnostics Index: test/CXX/special/class.copy/p11.0x.copy.cpp =================================================================== --- test/CXX/special/class.copy/p11.0x.copy.cpp +++ test/CXX/special/class.copy/p11.0x.copy.cpp @@ -49,7 +49,7 @@ HasAccess HAb(HAa); struct NonConst { - NonConst(NonConst&); + NonConst(NonConst&); // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; struct Ambiguity { Ambiguity(const Ambiguity&); Index: test/CXX/special/class.copy/implicit-move.cpp =================================================================== --- test/CXX/special/class.copy/implicit-move.cpp +++ test/CXX/special/class.copy/implicit-move.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -Wno-non-idiomatic-copy-move %s // Tests for implicit (non-)declaration of move constructor and // assignment: p9, p11, p20, p23. @@ -142,16 +142,16 @@ static_assert(!noexcept(cntco = ContainsNonTrivialCopyOnly()), ""); ContainsConst cc; - cc = ContainsConst(); // expected-error {{no viable}} + cc = ContainsConst(); // expected-error {{no viable}} ContainsRef cr; - cr = ContainsRef(); // expected-error {{no viable}} + cr = ContainsRef(); // expected-error {{no viable}} DirectVirtualBase dvb; - dvb = DirectVirtualBase(); // expected-error {{no viable}} + dvb = DirectVirtualBase(); // expected-error {{no viable}} IndirectVirtualBase ivb; - ivb = IndirectVirtualBase(); // expected-error {{no viable}} + ivb = IndirectVirtualBase(); // expected-error {{no viable}} } struct ContainsRValueRef { Index: test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp =================================================================== --- test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp +++ test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify +// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -Wno-non-idiomatic-copy-move // expected-no-diagnostics struct DirectInitOnly { Index: test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp =================================================================== --- test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp +++ test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp @@ -10,13 +10,14 @@ class NonConstCopy { public: - NonConstCopy(NonConstCopy&); // expected-note{{would lose const}} + NonConstCopy(NonConstCopy&); // expected-note{{would lose const}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; void capture_by_copy(NonCopyable nc, NonCopyable &ncr, const NonConstCopy nco) { (void)[nc] { }; // expected-error{{capture of variable 'nc' as type 'NonCopyable' calls private copy constructor}} (void)[=] { - ncr.foo(); // expected-error{{capture of variable 'ncr' as type 'NonCopyable' calls private copy constructor}} + ncr.foo(); // expected-error{{capture of variable 'ncr' as type 'NonCopyable' calls private copy constructor}} }(); [nco] {}(); // expected-error{{no matching constructor for initialization of 'const NonConstCopy'}} Index: test/CXX/drs/dr5xx.cpp =================================================================== --- test/CXX/drs/dr5xx.cpp +++ test/CXX/drs/dr5xx.cpp @@ -157,7 +157,7 @@ template<typename T> void b3(Base<T> *); void test(int n, const int cn, int **p, int *S::*pm) { - int *a[3], *S::*am[3]; + int *a[3], *S::*am[3]; const Derived cd = Derived(); Derived d[3]; @@ -742,10 +742,12 @@ }; #if __cplusplus >= 201103L struct C { - C &operator=(const C&) &; // expected-note {{not viable}} expected-note {{nearly matches}} expected-note {{here}} + C &operator=(const C&) &; // expected-note {{not viable}} expected-note {{nearly matches}} expected-note {{here}} \ + // expected-warning {{non-idiomatic copy assignment operator declaration; consider removing ref-qualifiers instead}} }; struct D { - D &operator=(const D&) &&; // expected-note {{not viable}} expected-note {{nearly matches}} expected-note {{here}} + D &operator=(const D&) &&; // expected-note {{not viable}} expected-note {{nearly matches}} expected-note {{here}} \ + // expected-warning {{non-idiomatic copy assignment operator declaration; consider removing ref-qualifiers instead}} }; void test(C c, D d) { c = c; Index: test/CXX/drs/dr3xx.cpp =================================================================== --- test/CXX/drs/dr3xx.cpp +++ test/CXX/drs/dr3xx.cpp @@ -357,7 +357,8 @@ namespace dr331 { // dr331: yes struct A { - A(volatile A&); // expected-note {{candidate}} + A(volatile A&); // expected-note {{candidate}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} } const a, b(a); // expected-error {{no matching constructor}} } @@ -1010,7 +1011,7 @@ } namespace dr385 { // dr385: yes - struct A { protected: void f(); }; + struct A { protected: void f(); }; struct B : A { using A::f; }; struct C : A { void g(B b) { b.f(); } }; void h(B b) { b.f(); } Index: test/CXX/drs/dr1xx.cpp =================================================================== --- test/CXX/drs/dr1xx.cpp +++ test/CXX/drs/dr1xx.cpp @@ -826,7 +826,8 @@ namespace dr177 { // dr177: yes struct B {}; struct A { - A(A &); // expected-note {{not viable: expects an l-value}} + A(A &); // expected-note {{not viable: expects an l-value}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} A(const B &); }; B b; Index: test/CXX/drs/dr0xx.cpp =================================================================== --- test/CXX/drs/dr0xx.cpp +++ test/CXX/drs/dr0xx.cpp @@ -70,7 +70,7 @@ }; const volatile B b = a; - struct C { C(C&); }; + struct C { C(C&); }; // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} struct D : C {}; struct E { operator D&(); } e; const C c = e; @@ -901,7 +901,8 @@ struct A { operator B() const; }; struct C {}; struct B { - B(B&); // expected-note {{candidate}} + B(B&); // expected-note {{candidate}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} B(C); operator C() const; }; Index: test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp =================================================================== --- test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp +++ test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-non-idiomatic-copy-move -std=c++11 %s // FIXME: test with non-std qualifiers Index: test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp =================================================================== --- test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp +++ test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp @@ -21,7 +21,7 @@ X3(); private: - X3(X3&); + X3(X3&); // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; template<typename T> Index: test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp =================================================================== --- test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp +++ test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp @@ -22,7 +22,8 @@ X3(); private: - X3(X3&); // expected-note{{candidate constructor not viable: expects an l-value for 1st argument}} + X3(X3&); // expected-note{{candidate constructor not viable: expects an l-value for 1st argument}} \ + // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; // Check for instantiation of default arguments @@ -38,7 +39,7 @@ struct X4 { X4(); X4(const X4&, T = get_value_badly<T>()); // expected-note{{in instantiation of}} -}; +}; // Check for "dangerous" default arguments that could cause recursion. struct X5 { Index: test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp =================================================================== --- test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp +++ test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify %s -std=c++11 +// RUN: %clang_cc1 -verify -Wno-non-idiomatic-copy-move %s -std=c++11 // A function that is explicitly defaulted shall struct A { Index: test/CXX/class/p6-0x.cpp =================================================================== --- test/CXX/class/p6-0x.cpp +++ test/CXX/class/p6-0x.cpp @@ -4,8 +4,8 @@ class Trivial { int n; void f(); }; class NonTrivial1 { NonTrivial1(const NonTrivial1 &); }; class NonTrivial2 { NonTrivial2(NonTrivial2 &&); }; -class NonTrivial3 { NonTrivial3 operator=(const NonTrivial3 &); }; -class NonTrivial4 { NonTrivial4 operator=(NonTrivial4 &&); }; +class NonTrivial3 { NonTrivial3& operator=(const NonTrivial3 &); }; +class NonTrivial4 { NonTrivial4& operator=(NonTrivial4 &&); }; class NonTrivial5 { ~NonTrivial5(); }; static_assert(__is_trivial(Trivial), "Trivial is not trivial"); Index: test/CXX/class/class.union/p1.cpp =================================================================== --- test/CXX/class/class.union/p1.cpp +++ test/CXX/class/class.union/p1.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s void abort() __attribute__((noreturn)); @@ -24,11 +24,11 @@ }; class CopyCtor { // expected-note 2{{because no constructor can be used to copy an object of type 'const CopyCtor'}} - CopyCtor(CopyCtor &cc) { abort(); } + CopyCtor(CopyCtor &cc) { abort(); } // expected-warning {{non-idiomatic copy constructor declaration; consider 'const T&' instead}} }; class CopyAssign { // expected-note 2 {{because no assignment operator can be used to copy an object of type 'const CopyAssign'}} - CopyAssign& operator=(CopyAssign& CA) { abort(); } + CopyAssign& operator=(CopyAssign& CA) { abort(); } // expected-warning {{non-idiomatic copy assignment operator declaration; consider 'const T&' instead}} }; class Dtor { Index: test/CXX/class.access/p4.cpp =================================================================== --- test/CXX/class.access/p4.cpp +++ test/CXX/class.access/p4.cpp @@ -95,11 +95,11 @@ A a; // expected-error {{calling a private constructor}} A A::foo; // okay - + class B : A { }; // expected-error {{base class 'test2::A' has private default constructor}} B b; // expected-note{{implicit default constructor}} - - class C : virtual A { + + class C : virtual A { public: C(); }; @@ -149,7 +149,7 @@ virtual Base<1>, // expected-error 2 {{base class 'Base<1>' has private destructor}} Base2, // expected-error 2 {{base class 'test3::Base2' has private destructor}} virtual Base3 - {}; + {}; Derived3 d3; // expected-note {{implicit default constructor}}\ // expected-note{{implicit destructor}}} } @@ -201,12 +201,12 @@ // Implicit copy assignment operator uses. namespace test5 { class A { - void operator=(const A &); // expected-note 2 {{implicitly declared private here}} + A& operator=(const A &); // expected-note 2 {{implicitly declared private here}} }; class Test1 { A a; }; // expected-error {{private member}} void test1() { - Test1 a; + Test1 a; a = Test1(); // expected-note{{implicit copy}} } @@ -247,7 +247,7 @@ }; } -// Ignored operator new and delete overloads are not +// Ignored operator new and delete overloads are not namespace test8 { typedef __typeof__(sizeof(int)) size_t; @@ -355,11 +355,11 @@ class X { ~X(); // expected-note {{declared private here}} }; - + struct Y1 { operator X(); }; - + void g() { const X &xr = Y1(); // expected-error{{temporary of type 'test14::X' has private destructor}} } @@ -393,7 +393,7 @@ }; template class A<int>; - template class A<long>; // expected-note 4 {{in instantiation}} + template class A<long>; // expected-note 4 {{in instantiation}} template <class T> class B : public A<T> { // TODO: These first two accesses can be detected as ill-formed at @@ -454,7 +454,7 @@ // PR8325 namespace test19 { class A { ~A(); }; - // The destructor is not implicitly referenced here. Contrast to test16, + // The destructor is not implicitly referenced here. Contrast to test16, // testing PR7281, earlier in this file. void b(A* x) { throw x; } } Index: test/CXX/basic/basic.types/p10.cpp =================================================================== --- test/CXX/basic/basic.types/p10.cpp +++ test/CXX/basic/basic.types/p10.cpp @@ -20,7 +20,7 @@ struct BeingDefined; extern BeingDefined beingdefined; -struct BeingDefined { +struct BeingDefined { static constexpr BeingDefined& t = beingdefined; }; @@ -75,7 +75,7 @@ template<typename T> constexpr CtorTemplate(T); }; struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}} - constexpr CopyCtorOnly(CopyCtorOnly&); + constexpr CopyCtorOnly(const CopyCtorOnly&); }; constexpr int f(CopyCtorOnly) { return 0; } // expected-error {{'CopyCtorOnly' is not a literal type}} struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}} Index: test/CodeGenCXX/copy-assign-synthesis-3.cpp =================================================================== --- test/CodeGenCXX/copy-assign-synthesis-3.cpp +++ test/CodeGenCXX/copy-assign-synthesis-3.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm-only -verify %s +// RUN: %clang_cc1 -emit-llvm-only -verify -Wno-non-idiomatic-copy-move %s // expected-no-diagnostics struct A { Index: test/Analysis/operator-calls.cpp =================================================================== --- test/Analysis/operator-calls.cpp +++ test/Analysis/operator-calls.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s +// RUN: %clang_cc1 -std=c++11 -Wno-non-idiomatic-copy-move -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s void clang_analyzer_eval(bool); struct X0 { }; Index: test/Analysis/NewDelete-checker-test.cpp =================================================================== --- test/Analysis/NewDelete-checker-test.cpp +++ test/Analysis/NewDelete-checker-test.cpp @@ -71,7 +71,7 @@ //----- Other cases void testNewMemoryIsInHeap() { int *p = new int; - if (global != p) // condition is always true as 'p' wraps a heap region that + if (global != p) // condition is always true as 'p' wraps a heap region that // is different from a region wrapped by 'global' global = p; // pointer escapes } @@ -278,7 +278,7 @@ explicit shared_ptr(T *p) : p(p), control(new control_block) { control->retain(); } - shared_ptr(shared_ptr &other) : p(other.p), control(other.control) { + shared_ptr(const shared_ptr &other) : p(other.p), control(other.control) { if (control) control->retain(); } Index: test/Analysis/inlining/path-notes.cpp =================================================================== --- test/Analysis/inlining/path-notes.cpp +++ test/Analysis/inlining/path-notes.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify -Wno-tautological-undefined-compare %s -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist -Wno-tautological-undefined-compare +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify -Wno-non-idiomatic-copy-move -Wno-tautological-undefined-compare %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist -Wno-non-idiomatic-copy-move -Wno-tautological-undefined-compare // RUN: FileCheck --input-file=%t.plist %s class Foo { Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -4899,6 +4899,67 @@ } } +static void DiagnoseNonIdiomaticConstructor(Sema &S, + const CXXConstructorDecl *Ctor, + bool Move) { + // This is already known to be a copy or move constructor, so there is at + // least one parameter of a sensible class type. Check the qualifiers on that + // type to determine if they are idiomatic or not. + QualType ParamType = Ctor->getParamDecl(0)->getType(); + assert(ParamType->isReferenceType() && + "Copy or move ctor with non-reference type"); + QualType RefType = + S.Context.getCanonicalType(ParamType.getNonReferenceType()); + + if (RefType.isVolatileQualified() || + ((!Move && !RefType.isConstQualified()) || + (Move && RefType.isConstQualified()))) + S.Diag(Ctor->getParamDecl(0)->getLocation(), + diag::warn_non_idiomatic_copy_move_ctor) << Move; +} + +static void DiagnoseNonIdiomaticAssignment(Sema &S, + const CXXMethodDecl *Assign, + bool Move) { + // Check that there are no ref-qualifiers. + if (Assign->getRefQualifier() != RQ_None) { + S.Diag(Assign->getLocation(), diag::warn_non_idiomatic_copy_move_assign) + << Move << /*ref-qualifier*/ 2; + return; + } + + // Check that the return type is an lvalue reference type that is an + // unqualified reference to the class type. + QualType ClassType = S.Context.getTagDeclType(Assign->getParent()); + QualType ReturnType = Assign->getReturnType(); + if (!ReturnType->isLValueReferenceType() || + ReturnType.getNonReferenceType().hasQualifiers() || + S.Context.getCanonicalType(ReturnType).getNonReferenceType() != + ClassType) { + S.Diag(Assign->getReturnTypeSourceRange().getBegin(), + diag::warn_non_idiomatic_copy_move_assign) << Move << /*return*/ 0; + return; + } + + // This is already known to be a copy or move assignment operator, so there + // is at least one parameter of a sensible class type. Check that it is an + // idiomatic parameter type. For a move assignment, if the non-reference type + // has any qualifiers, it is not idiomatic. For a copy assignment, if the type + // is not a reference type, or if it is a reference type that is not solely + // const-qualified, it is not idiomatic. + QualType ParamType = + S.Context.getCanonicalType(Assign->getParamDecl(0)->getType()); + QualType ParamNonRefType = ParamType.getNonReferenceType(); + if ((Move && ParamNonRefType.hasQualifiers()) || + (!Move && (!ParamType->isReferenceType() || + ParamNonRefType.isVolatileQualified() || + !ParamNonRefType.isConstQualified()))) { + S.Diag(Assign->getParamDecl(0)->getLocation(), + diag::warn_non_idiomatic_copy_move_assign) << Move << /*param*/ 1; + return; + } +} + /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -5038,6 +5099,62 @@ DeclareInheritingConstructors(Record); checkClassLevelDLLAttribute(Record); + + // Diagnose non-idiomatic copy/move constructors. Do not diagnose an operation + // in the presence of an idiomatic variant or multiple non-idiomatic variants. + if (Record->hasUserDeclaredCopyConstructor() || + Record->hasUserDeclaredMoveConstructor()) { + SmallVector<const CXXConstructorDecl *, 1> CopyCtors, MoveCtors; + for (const auto *Ctor : Record->ctors()) { + // If the constructor has default arguments or has been flagged as being + // invalid, skip it. + if (Ctor->isInvalidDecl() || Ctor->getNumParams() != 1) + continue; + if (Ctor->isCopyConstructor()) + CopyCtors.push_back(Ctor); + else if (Ctor->isMoveConstructor()) + MoveCtors.push_back(Ctor); + } + + // If there are multiple copy/move constructors (considered separately), + // then no diagnostics should be triggered even if some of the constructors + // are non-idiomatic. If there is only one such constructor, and it is non- + // idiomatic, then diagnose. + if (CopyCtors.size() == 1) + DiagnoseNonIdiomaticConstructor(*this, CopyCtors.front(), false); + if (MoveCtors.size() == 1) + DiagnoseNonIdiomaticConstructor(*this, MoveCtors.front(), true); + } + + // Diagnose non-idiomatic copy/move assignment operators. Do not diagnose an + // operation in the presence of an idiomatic variant or multiple non-idiomatic + // variants. + if (Record->hasUserDeclaredCopyAssignment() || + Record->hasUserDeclaredMoveAssignment()) { + SmallVector<const CXXMethodDecl *, 1> CopyAssigns, MoveAssigns; + // If the assignment operator has been flagged as being invalid, skip it. + for (const auto *M : Record->methods()) { + if (M->isInvalidDecl()) + continue; + if (M->isCopyAssignmentOperator()) + CopyAssigns.push_back(M); + else if (M->isMoveAssignmentOperator()) + MoveAssigns.push_back(M); + } + + // If there are multiple copy/move assignment operators (considered + // separately), then no diagnostics should be triggered even if some of the + // operators are non-idiomatic. If there is only one such operator, and it + // is non-idiomatic, then diagnose. + if (CopyAssigns.size() == 1) + DiagnoseNonIdiomaticAssignment(*this, CopyAssigns.front(), false); + if (MoveAssigns.size() == 1) + DiagnoseNonIdiomaticAssignment(*this, MoveAssigns.front(), true); + } + + if (Record->hasUserDeclaredCopyAssignment() || + Record->hasUserDeclaredMoveAssignment()) { + } } /// Look up the special member function that would be called by a special Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4166,6 +4166,15 @@ "%select{copy|move}0 assignment operator of %1 is implicitly deleted " "because field %2 is of %select{reference|const-qualified}4 type %3">; +def warn_non_idiomatic_copy_move_ctor : Warning< + "non-idiomatic %select{copy|move}0 constructor declaration; consider " + "%select{'const T&'|'T&&'}0 instead">, + InGroup<NonIdiomaticCopyMove>; +def warn_non_idiomatic_copy_move_assign : Warning< + "non-idiomatic %select{copy|move}0 assignment operator declaration; consider " + "%select{returning 'T&'|'%select{const T&|T&&}0'|removing ref-qualifiers}1 " + "instead">, InGroup<NonIdiomaticCopyMove>; + // These should be errors. def warn_undefined_internal : Warning< "%select{function|variable}0 %q1 has internal linkage but is not defined">, Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -495,6 +495,7 @@ def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">; def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">; def Fallback : DiagGroup<"fallback">; +def NonIdiomaticCopyMove : DiagGroup<"non-idiomatic-copy-move">; // This covers both the deprecated case (in C++98) // and the extension case (in C++11 onwards).
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits