1 // RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -verify %s
2 // RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
3 // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -ast-dump | FileCheck %s --check-prefix=CHECK-AST
4 
5 // definitions for std::move
6 namespace std {
7 inline namespace foo {
8 template <class T> struct remove_reference { typedef T type; };
9 template <class T> struct remove_reference<T&> { typedef T type; };
10 template <class T> struct remove_reference<T&&> { typedef T type; };
11 
12 template <class T> typename remove_reference<T>::type &&move(T &&t);
13 }
14 }
15 
16 // test1 and test2 should not warn until after implementation of DR1579.
17 struct A {};
18 struct B : public A {};
19 
test1(B b1)20 A test1(B b1) {
21   B b2;
22   return b1;
23   return b2;
24   return std::move(b1);
25   return std::move(b2);
26 }
27 
28 struct C {
CC29   C() {}
CC30   C(A) {}
31 };
32 
test2(A a1,B b1)33 C test2(A a1, B b1) {
34   A a2;
35   B b2;
36 
37   return a1;
38   return a2;
39   return b1;
40   return b2;
41 
42   return std::move(a1);
43   return std::move(a2);
44   return std::move(b1);
45   return std::move(b2);
46 }
47 
48 // Copy of tests above with types changed to reference types.
test3(B & b1)49 A test3(B& b1) {
50   B& b2 = b1;
51   return b1;
52   return b2;
53   return std::move(b1);
54   return std::move(b2);
55 }
56 
test4(A & a1,B & b1)57 C test4(A& a1, B& b1) {
58   A& a2 = a1;
59   B& b2 = b1;
60 
61   return a1;
62   return a2;
63   return b1;
64   return b2;
65 
66   return std::move(a1);
67   return std::move(a2);
68   return std::move(b1);
69   return std::move(b2);
70 }
71 
72 // PR23819, case 2
73 struct D {};
test5(D d)74 D test5(D d) {
75   return d;
76   // Verify the implicit move from the AST dump
77   // CHECK-AST: ReturnStmt{{.*}}line:[[@LINE-2]]
78   // CHECK-AST-NEXT: CXXConstructExpr{{.*}}struct D{{.*}}void (struct D &&)
79   // CHECK-AST-NEXT: ImplicitCastExpr
80   // CHECK-AST-NEXT: DeclRefExpr{{.*}}ParmVar{{.*}}'d'
81 
82   return std::move(d);
83   // expected-warning@-1{{redundant move in return statement}}
84   // expected-note@-2{{remove std::move call here}}
85   // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
86   // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:21-[[@LINE-4]]:22}:""
87 }
88 
89 namespace templates {
90   struct A {};
91   struct B { B(A); };
92 
93   // Warn once here since the type is not dependent.
94   template <typename T>
test1(A a)95   A test1(A a) {
96     return std::move(a);
97     // expected-warning@-1{{redundant move in return statement}}
98     // expected-note@-2{{remove std::move call here}}
99     // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:22}:""
100     // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
101   }
run_test1()102   void run_test1() {
103     test1<A>(A());
104     test1<B>(A());
105   }
106 
107   // T1 and T2 may not be the same, the warning may not always apply.
108   template <typename T1, typename T2>
test2(T2 t)109   T1 test2(T2 t) {
110     return std::move(t);
111   }
run_test2()112   void run_test2() {
113     test2<A, A>(A());
114     test2<B, A>(A());
115   }
116 }
117