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 |
|
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 {
|
29 | C() {}
|
30 | C(A) {}
|
31 | };
|
32 |
|
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.
|
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 |
|
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 {};
|
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{{.*}}D{{.*}}void (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>
|
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 | }
|
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>
|
109 | T1 test2(T2 t) {
|
110 | return std::move(t);
|
111 | }
|
112 | void run_test2() {
|
113 | test2<A, A>(A());
|
114 | test2<B, A>(A());
|
115 | }
|
116 | }
|
117 | |