1 | // RUN: %check_clang_tidy -std=c++17-or-later %s cert-dcl58-cpp %t -- -- -I %clang_tidy_headers |
2 | |
3 | #include "system-header-simulation.h" |
4 | |
5 | namespace A { |
6 | namespace B { |
7 | int b; |
8 | } |
9 | } |
10 | |
11 | namespace A { |
12 | namespace B { |
13 | int c; |
14 | } |
15 | } |
16 | |
17 | namespace posix { |
18 | // CHECK-MESSAGES: :[[@LINE+2]]:11: warning: modification of 'posix' namespace can result in undefined behavior [cert-dcl58-cpp] |
19 | // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here |
20 | namespace foo { |
21 | int foobar; |
22 | } |
23 | } |
24 | |
25 | namespace std { |
26 | // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: modification of 'std' namespace |
27 | // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here |
28 | int stdInt; |
29 | // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: modification of 'std' namespace |
30 | // CHECK-MESSAGES: :[[@LINE-5]]:11: note: 'std' namespace opened here |
31 | int stdInt1; |
32 | } |
33 | |
34 | namespace foobar { |
35 | namespace std { |
36 | int bar; |
37 | } |
38 | } |
39 | |
40 | namespace posix { |
41 | // CHECK-MESSAGES: :[[@LINE+2]]:11: warning: modification of 'posix' namespace |
42 | // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here |
43 | namespace std { |
44 | } |
45 | } // namespace posix |
46 | |
47 | namespace posix::a { |
48 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: modification of 'posix' namespace |
49 | // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here |
50 | } |
51 | |
52 | namespace std { |
53 | // no-warning: empty |
54 | } // namespace std |
55 | |
56 | namespace std { |
57 | // Warn for non-NamedDecls as well. |
58 | // CHECK-MESSAGES: :[[@LINE+2]]:1: warning: modification of 'std' namespace |
59 | // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here |
60 | static_assert(1 == 1, "non-NamedDecl" ); |
61 | } // namespace std |
62 | |
63 | enum class MyError { |
64 | ErrorA, |
65 | ErrorB |
66 | }; |
67 | |
68 | namespace std { |
69 | // no-warning: Class template specialized by a program-defined type. |
70 | template <> |
71 | struct is_error_code_enum<MyError> : std::true_type {}; |
72 | |
73 | // no-warning: Function template specialized by a program-defined type. |
74 | template<> |
75 | void swap<MyError>(MyError &a, MyError &b); |
76 | } |
77 | |
78 | using ConstBoolPtr = const bool *; |
79 | |
80 | namespace std { |
81 | // class template, builtin type |
82 | // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace |
83 | // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here |
84 | template <> |
85 | struct is_error_code_enum<bool> : std::true_type {}; |
86 | // function template, builtin type |
87 | // CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace |
88 | // CHECK-MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here |
89 | template <> |
90 | void swap<bool>(bool &, bool &); |
91 | // CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace |
92 | // CHECK-MESSAGES: :[[@LINE-12]]:11: note: 'std' namespace opened here |
93 | template <> |
94 | void swap<ConstBoolPtr>(ConstBoolPtr &, ConstBoolPtr &); |
95 | } // namespace std |
96 | |
97 | namespace std { |
98 | // class template, std type |
99 | // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace |
100 | // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here |
101 | template <> |
102 | struct is_error_code_enum<std::io_errc> : std::true_type {}; |
103 | // function template, std type |
104 | // CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace |
105 | // CHECK-MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here |
106 | template <> |
107 | void swap<std::io_errc>(std::io_errc &, std::io_errc &); |
108 | } // namespace std |
109 | |
110 | // parameter pack, has program-defined type |
111 | namespace std { |
112 | // no-warning: there is one program-defined type. |
113 | template <> |
114 | class tuple<int, MyError, std::io_errc> {}; |
115 | } // namespace std |
116 | |
117 | // parameter pack, only builtin or std type |
118 | namespace std { |
119 | // Forbid variadic specializations over only `std::` or builtin types. |
120 | // CHECK-MESSAGES: :[[@LINE+3]]:7: warning: modification of 'std' namespace |
121 | // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here |
122 | template <> |
123 | class tuple<int, const std::io_errc, float> {}; |
124 | } // namespace std |
125 | |
126 | namespace std { |
127 | // Test nested standard declarations. |
128 | // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace |
129 | // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here |
130 | template <> |
131 | struct is_error_code_enum<std::Outer::Inner> : std::true_type {}; |
132 | } // namespace std |
133 | |
134 | namespace std { |
135 | // Test nested namespace. |
136 | // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace |
137 | // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here |
138 | template <> |
139 | struct is_error_code_enum<std::detail::X> : std::true_type {}; |
140 | } // namespace std |
141 | |
142 | // Test member function template specializations. |
143 | namespace std { |
144 | // CHECK-MESSAGES: :[[@LINE+3]]:18: warning: modification of 'std' namespace |
145 | // CHECK_MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here |
146 | template <> |
147 | bool less<void>::operator()<int &&, float &&>(int &&, float &&) const { |
148 | return true; |
149 | } |
150 | // CHECK-MESSAGES: :[[@LINE+3]]:18: warning: modification of 'std' namespace |
151 | // CHECK_MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here |
152 | template <> |
153 | bool less<void>::operator()<MyError &&, MyError &&>(MyError &&, MyError &&) const { |
154 | return true; |
155 | } |
156 | } // namespace std |
157 | |
158 | // Test member class template specializations. |
159 | namespace std { |
160 | // CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace |
161 | // CHECK_MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here |
162 | template <> |
163 | struct less<void>::X<bool> {}; |
164 | // CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace |
165 | // CHECK_MESSAGES: :[[@LINE-6]]:11: note: 'std' namespace opened here |
166 | template <> |
167 | struct less<void>::X<MyError> {}; |
168 | // CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace |
169 | // CHECK_MESSAGES: :[[@LINE-10]]:11: note: 'std' namespace opened here |
170 | template <typename T> |
171 | struct less<void>::X<MyError, T> {}; |
172 | } // namespace std |
173 | |
174 | // We did not open the 'std' namespace, but still specialized the member |
175 | // function of 'std::less'. |
176 | // CHECK-MESSAGES: :[[@LINE+3]]:23: warning: modification of 'std' namespace |
177 | // no-note: There is no opening of 'std' namespace, hence no note emitted. |
178 | template <> |
179 | bool std::less<void>::operator()<int &&, int &&>(int &&, int &&) const { |
180 | return true; |
181 | } |
182 | |
183 | namespace SpaceA { |
184 | namespace SpaceB { |
185 | class MapKey { |
186 | int Type = 0; |
187 | |
188 | public: |
189 | MapKey() = default; |
190 | int getType() const { return Type; } |
191 | }; |
192 | } // namespace SpaceB |
193 | } // namespace SpaceA |
194 | |
195 | // no-warning: Specializing for 'std::hash' for a program-defined type. |
196 | template <> |
197 | struct std::hash<::SpaceA::SpaceB::MapKey> { |
198 | // no-warning |
199 | unsigned long operator()(const ::SpaceA::SpaceB::MapKey &K) const { |
200 | return K.getType(); |
201 | } |
202 | // no-warning |
203 | bool operator()(const ::SpaceA::SpaceB::MapKey &K1, |
204 | const ::SpaceA::SpaceB::MapKey &K2) const { |
205 | return K1.getType() < K2.getType(); |
206 | } |
207 | }; |
208 | |
209 | using myint = int; |
210 | |
211 | // The type alias declaration is the same as typedef, does not introduce a |
212 | // program-defined type. |
213 | // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: modification of 'std' namespace |
214 | template <> |
215 | struct std::hash<myint> { |
216 | // no-warning: The warning was already reported for the struct itself. |
217 | unsigned long operator()(const myint &K) const { |
218 | return K; |
219 | } |
220 | // no-warning: The warning was already reported for the struct itself. |
221 | bool operator()(const myint &K1, |
222 | const myint &K2) const { |
223 | return K1 < K2; |
224 | } |
225 | }; |
226 | |
227 | // CHECK-MESSAGES: :[[@LINE+2]]:15: warning: modification of 'std' namespace |
228 | template <> |
229 | struct ::std::hash<long> { |
230 | unsigned long operator()(const long &K) const { |
231 | return K; |
232 | } |
233 | }; |
234 | |
235 | namespace ranges { |
236 | namespace detail { |
237 | struct diffmax_t {}; |
238 | using LongT = long; |
239 | } // namespace detail |
240 | } // namespace ranges |
241 | |
242 | namespace std { |
243 | // no-warning: specialization with an user-defined type |
244 | template <> |
245 | struct numeric_limits<::ranges::detail::diffmax_t> { |
246 | static constexpr bool is_signed = true; |
247 | static constexpr bool is_integer = true; |
248 | static constexpr ::ranges::detail::diffmax_t max() noexcept { |
249 | return {}; |
250 | } |
251 | }; |
252 | inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_signed; |
253 | inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_integer; |
254 | } // namespace std |
255 | |
256 | namespace std { |
257 | // specialization with type alias to non-program-defined-type |
258 | // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace |
259 | // CHECK_MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here |
260 | template <> |
261 | struct numeric_limits<::ranges::detail::LongT> { |
262 | static constexpr bool is_signed = true; |
263 | static constexpr bool is_integer = true; |
264 | static constexpr ::ranges::detail::LongT max() noexcept { |
265 | return 1; |
266 | } |
267 | }; |
268 | inline constexpr bool numeric_limits<::ranges::detail::LongT>::is_signed; |
269 | inline constexpr bool numeric_limits<::ranges::detail::LongT>::is_integer; |
270 | } // namespace std |
271 | |
272 | namespace no_crash { |
273 | struct A |
274 | { |
275 | friend struct B; |
276 | }; |
277 | |
278 | struct B; |
279 | |
280 | template<typename> struct T {}; |
281 | |
282 | T<B> b; |
283 | } |
284 | |