1 // RUN: %check_clang_tidy %s bugprone-return-const-ref-from-parameter %t -- -- -fno-delayed-template-parsing
2 
3 using T = int;
4 using TConst = int const;
5 using TConstRef = int const&;
6 
7 template <typename T>
8 struct Wrapper { Wrapper(T); };
9 
10 template <typename T>
11 struct Identity { using type = T; };
12 
13 template <typename T>
14 struct ConstRef { using type = const T&; };
15 
16 namespace invalid {
17 
18 int const &f1(int const &a) { return a; }
19 // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: returning a constant reference parameter
20 
21 int const &f2(T const &a) { return a; }
22 // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: returning a constant reference parameter
23 
24 int const &f3(TConstRef a) { return a; }
25 // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: returning a constant reference parameter
26 
27 int const &f4(TConst &a) { return a; }
28 // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter
29 
30 int const &f5(TConst &a) { return true ? a : a; }
31 // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: returning a constant reference parameter
32 // CHECK-MESSAGES: :[[@LINE-2]]:46: warning: returning a constant reference parameter
33 
34 template <typename T>
35 const T& tf1(const T &a) { return a; }
36 // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter
37 
38 template <typename T>
39 const T& itf1(const T &a) { return a; }
40 // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: returning a constant reference parameter
41 
42 template <typename T>
43 typename ConstRef<T>::type itf2(const T &a) { return a; }
44 // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter
45 
46 template <typename T>
47 typename ConstRef<T>::type itf3(typename ConstRef<T>::type a) { return a; }
48 // CHECK-MESSAGES: :[[@LINE-1]]:72: warning: returning a constant reference parameter
49 
50 template <typename T>
51 const T& itf4(typename ConstRef<T>::type a) { return a; }
52 // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter
53 
54 template <typename T>
55 const T& itf5(const T &a) { return true ? a : a; }
56 // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: returning a constant reference parameter
57 // CHECK-MESSAGES: :[[@LINE-2]]:47: warning: returning a constant reference parameter
58 
59 void instantiate(const int &param, const float &paramf, int &mut_param, float &mut_paramf) {
60         itf1(0);
61         itf1(param);
62         itf1(paramf);
63         itf2(0);
64         itf2(param);
65         itf2(paramf);
66         itf3<int>(0);
67         itf3<int>(param);
68         itf3<float>(paramf);
69         itf4<int>(0);
70         itf4<int>(param);
71         itf4<float>(paramf);
72 }
73 
74 struct C {
75     const C& foo(const C&c) { return c; }
76 // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: returning a constant reference parameter
77 };
78 
79 const auto Lf1 = [](const T& t) -> const T& { return t; };
80 // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter
81 
82 } // namespace invalid
83 
84 namespace false_negative_because_dependent_and_not_instantiated {
85 template <typename T>
86 typename ConstRef<T>::type tf2(const T &a) { return a; }
87 
88 template <typename T>
89 typename ConstRef<T>::type tf3(typename ConstRef<T>::type a) { return a; }
90 
91 template <typename T>
92 const T& tf4(typename ConstRef<T>::type a) { return a; }
93 } // false_negative_because_dependent_and_not_instantiated
94 
95 namespace valid {
96 
97 int const &f1(int &a) { return a; }
98 
99 int const &f2(int &&a) { return a; }
100 
101 int f1(int const &a) { return a; }
102 
103 template <typename T>
104 T tf1(T a) { return a; }
105 
106 template <typename T>
107 T tf2(const T a) { return a; }
108 
109 template <typename T>
110 T tf3(const T &a) { return a; }
111 
112 template <typename T>
113 Identity<T>::type tf4(const T &a) { return a; }
114 
115 template <typename T>
116 T itf1(T a) { return a; }
117 
118 template <typename T>
119 T itf2(const T a) { return a; }
120 
121 template <typename T>
122 T itf3(const T &a) { return a; }
123 
124 template <typename T>
125 Wrapper<T> itf4(const T& a) { return a; }
126 
127 template <typename T>
128 const T& itf5(T& a) { return a; }
129 
130 template <typename T>
131 T itf6(T& a) { return a; }
132 
133 void instantiate(const int &param, const float &paramf, int &mut_param, float &mut_paramf) {
134         itf1(0);
135         itf1(param);
136         itf1(paramf);
137         itf2(0);
138         itf2(param);
139         itf2(paramf);
140         itf3(0);
141         itf3(param);
142         itf3(paramf);
143         itf2(0);
144         itf2(param);
145         itf2(paramf);
146         itf3(0);
147         itf3(param);
148         itf3(paramf);
149         itf4(param);
150         itf4(paramf);
151         itf5(mut_param);
152         itf5(mut_paramf);
153         itf6(mut_param);
154         itf6(mut_paramf);
155 }
156 
157 template<class T>
158 void f(const T& t) {
159     const auto get = [&t] -> const T& { return t; };
160     return T{};
161 }
162 
163 const auto Lf1 = [](T& t) -> const T& { return t; };
164 
165 } // namespace valid
166 
167 namespace overload {
168 
169 int const &overload_base(int const &a) { return a; }
170 int const &overload_base(int &&a);
171 
172 int const &overload_ret_type(int const &a) { return a; }
173 void overload_ret_type(int &&a);
174 
175 int const &overload_params1(int p1, int const &a) { return a; }
176 int const & overload_params1(int p1, int &&a);
177 
178 int const &overload_params2(int p1, int const &a, int p2) { return a; }
179 int const &overload_params2(int p1, int &&a, int p2);
180 
181 int const &overload_params3(T p1, int const &a, int p2) { return a; }
182 int const &overload_params3(int p1, int &&a, T p2);
183 
184 int const &overload_params_const(int p1, int const &a, int const p2) { return a; }
185 int const &overload_params_const(int const p1, int &&a, int p2);
186 
187 int const &overload_params_difference1(int p1, int const &a, int p2) { return a; }
188 // CHECK-MESSAGES: :[[@LINE-1]]:79: warning: returning a constant reference parameter
189 int const &overload_params_difference1(long p1, int &&a, int p2);
190 
191 int const &overload_params_difference2(int p1, int const &a, int p2) { return a; }
192 // CHECK-MESSAGES: :[[@LINE-1]]:79: warning: returning a constant reference parameter
193 int const &overload_params_difference2(int p1, int &&a, long p2);
194 
195 int const &overload_params_difference3(int p1, int const &a, int p2) { return a; }
196 // CHECK-MESSAGES: :[[@LINE-1]]:79: warning: returning a constant reference parameter
197 int const &overload_params_difference3(int p1, long &&a, int p2);
198 
199 } // namespace overload
200 
201 namespace gh117696 {
202 namespace use_lifetime_bound_attr {
203 int const &f(int const &a [[clang::lifetimebound]]) { return a; }
204 } // namespace use_lifetime_bound_attr
205 } // namespace gh117696
206 
207 
208 namespace lambda {
209 using T = const int &;
210 using K = const float &;
211 T inner_valid_lambda(T a) {
212   [&]() -> T { return a; };
213   return a;
214   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: returning a constant reference parameter
215 }
216 T inner_invalid_lambda(T a) {
217   [&](T a) -> T { return a; };
218   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: returning a constant reference parameter
219   return a;
220   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: returning a constant reference parameter
221 }
222 T inner_invalid_lambda2(T a) {
223   [&](K a) -> K { return a; };
224   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: returning a constant reference parameter
225   return a;
226   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: returning a constant reference parameter
227 }
228 } // namespace lambda
229