]>
Commit | Line | Data |
---|---|---|
dc9dc135 | 1 | // Validate AST before lowering it to HIR. |
3157f602 XL |
2 | // |
3 | // This pass is supposed to catch things that fit into AST data structures, | |
4 | // but not permitted by the language. It runs after expansion when AST is frozen, | |
5 | // so it can check for erroneous constructions produced by syntax extensions. | |
6 | // This pass is supposed to perform only simple checks not requiring name resolution | |
7 | // or type checking or some other kind of complex analysis. | |
8 | ||
ba9703b0 | 9 | use itertools::{Either, Itertools}; |
ba9703b0 | 10 | use rustc_ast::ptr::P; |
74b04a01 XL |
11 | use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; |
12 | use rustc_ast::walk_list; | |
3dfed10e | 13 | use rustc_ast::*; |
74b04a01 | 14 | use rustc_ast_pretty::pprust; |
9fa01778 | 15 | use rustc_data_structures::fx::FxHashMap; |
ba9703b0 | 16 | use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; |
60c5eb7d | 17 | use rustc_parse::validate_attr; |
94222f64 | 18 | use rustc_session::lint::builtin::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY}; |
5869c6ff | 19 | use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; |
dfeec247 | 20 | use rustc_session::Session; |
94222f64 | 21 | use rustc_span::source_map::Spanned; |
f9f354fc | 22 | use rustc_span::symbol::{kw, sym, Ident}; |
dfeec247 | 23 | use rustc_span::Span; |
94222f64 | 24 | use rustc_target::spec::abi; |
dfeec247 | 25 | use std::mem; |
f9f354fc | 26 | use std::ops::DerefMut; |
74b04a01 XL |
27 | |
28 | const MORE_EXTERN: &str = | |
29 | "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; | |
30 | ||
31 | /// Is `self` allowed semantically as the first parameter in an `FnDecl`? | |
32 | enum SelfSemantic { | |
33 | Yes, | |
34 | No, | |
35 | } | |
dfeec247 | 36 | |
3157f602 XL |
37 | struct AstValidator<'a> { |
38 | session: &'a Session, | |
74b04a01 XL |
39 | |
40 | /// The span of the `extern` in an `extern { ... }` block, if any. | |
41 | extern_mod: Option<&'a Item>, | |
42 | ||
43 | /// Are we inside a trait impl? | |
44 | in_trait_impl: bool, | |
45 | ||
94222f64 XL |
46 | in_const_trait_impl: bool, |
47 | ||
9fa01778 | 48 | has_proc_macro_decls: bool, |
9fa01778 | 49 | |
48663c56 XL |
50 | /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`. |
51 | /// Nested `impl Trait` _is_ allowed in associated type position, | |
dc9dc135 | 52 | /// e.g., `impl Iterator<Item = impl Debug>`. |
60c5eb7d | 53 | outer_impl_trait: Option<Span>, |
9fa01778 | 54 | |
94222f64 | 55 | is_tilde_const_allowed: bool, |
dfeec247 | 56 | |
48663c56 XL |
57 | /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` |
58 | /// or `Foo::Bar<impl Trait>` | |
9fa01778 XL |
59 | is_impl_trait_banned: bool, |
60 | ||
dc9dc135 XL |
61 | /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in |
62 | /// certain positions. | |
63 | is_assoc_ty_bound_banned: bool, | |
64 | ||
94222f64 XL |
65 | /// Used to allow `let` expressions in certain syntactic locations. |
66 | is_let_allowed: bool, | |
67 | ||
dfeec247 | 68 | lint_buffer: &'a mut LintBuffer, |
3157f602 XL |
69 | } |
70 | ||
71 | impl<'a> AstValidator<'a> { | |
94222f64 XL |
72 | fn with_in_trait_impl( |
73 | &mut self, | |
74 | is_in: bool, | |
75 | constness: Option<Const>, | |
76 | f: impl FnOnce(&mut Self), | |
77 | ) { | |
74b04a01 | 78 | let old = mem::replace(&mut self.in_trait_impl, is_in); |
94222f64 XL |
79 | let old_const = |
80 | mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_)))); | |
74b04a01 XL |
81 | f(self); |
82 | self.in_trait_impl = old; | |
94222f64 | 83 | self.in_const_trait_impl = old_const; |
74b04a01 XL |
84 | } |
85 | ||
9fa01778 XL |
86 | fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { |
87 | let old = mem::replace(&mut self.is_impl_trait_banned, true); | |
88 | f(self); | |
89 | self.is_impl_trait_banned = old; | |
90 | } | |
91 | ||
94222f64 XL |
92 | fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) { |
93 | let old = mem::replace(&mut self.is_tilde_const_allowed, true); | |
94 | f(self); | |
95 | self.is_tilde_const_allowed = old; | |
96 | } | |
97 | ||
98 | fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) { | |
99 | let old = mem::replace(&mut self.is_tilde_const_allowed, false); | |
100 | f(self); | |
101 | self.is_tilde_const_allowed = old; | |
102 | } | |
103 | ||
104 | fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) { | |
105 | let old = mem::replace(&mut self.is_let_allowed, allowed); | |
106 | f(self, old); | |
107 | self.is_let_allowed = old; | |
108 | } | |
109 | ||
110 | /// Emits an error banning the `let` expression provided in the given location. | |
111 | fn ban_let_expr(&self, expr: &'a Expr) { | |
112 | let sess = &self.session; | |
113 | if sess.opts.unstable_features.is_nightly_build() { | |
114 | sess.struct_span_err(expr.span, "`let` expressions are not supported here") | |
115 | .note("only supported directly in conditions of `if`- and `while`-expressions") | |
116 | .note("as well as when nested within `&&` and parenthesis in those conditions") | |
117 | .emit(); | |
118 | } else { | |
119 | sess.struct_span_err(expr.span, "expected expression, found statement (`let`)") | |
120 | .note("variable declaration using `let` is a statement") | |
121 | .emit(); | |
122 | } | |
123 | } | |
124 | ||
dc9dc135 XL |
125 | fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) { |
126 | let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true); | |
127 | f(self); | |
128 | self.is_assoc_ty_bound_banned = old; | |
129 | } | |
130 | ||
60c5eb7d | 131 | fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { |
9fa01778 | 132 | let old = mem::replace(&mut self.outer_impl_trait, outer); |
dfeec247 | 133 | if outer.is_some() { |
94222f64 | 134 | self.with_banned_tilde_const(f); |
dfeec247 | 135 | } else { |
94222f64 | 136 | f(self); |
dfeec247 | 137 | } |
9fa01778 XL |
138 | self.outer_impl_trait = old; |
139 | } | |
140 | ||
dc9dc135 XL |
141 | fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { |
142 | match constraint.kind { | |
60c5eb7d | 143 | AssocTyConstraintKind::Equality { .. } => {} |
dc9dc135 XL |
144 | AssocTyConstraintKind::Bound { .. } => { |
145 | if self.is_assoc_ty_bound_banned { | |
dfeec247 XL |
146 | self.err_handler().span_err( |
147 | constraint.span, | |
148 | "associated type bounds are not allowed within structs, enums, or unions", | |
dc9dc135 XL |
149 | ); |
150 | } | |
151 | } | |
9fa01778 | 152 | } |
dc9dc135 | 153 | self.visit_assoc_ty_constraint(constraint); |
9fa01778 XL |
154 | } |
155 | ||
dc9dc135 | 156 | // Mirrors `visit::walk_ty`, but tracks relevant state. |
9fa01778 | 157 | fn walk_ty(&mut self, t: &'a Ty) { |
e74abb32 | 158 | match t.kind { |
9fa01778 | 159 | TyKind::ImplTrait(..) => { |
60c5eb7d | 160 | self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) |
9fa01778 | 161 | } |
94222f64 | 162 | TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)), |
9fa01778 XL |
163 | TyKind::Path(ref qself, ref path) => { |
164 | // We allow these: | |
165 | // - `Option<impl Trait>` | |
166 | // - `option::Option<impl Trait>` | |
167 | // - `option::Option<T>::Foo<impl Trait> | |
168 | // | |
169 | // But not these: | |
170 | // - `<impl Trait>::Foo` | |
171 | // - `option::Option<impl Trait>::Foo`. | |
172 | // | |
173 | // To implement this, we disallow `impl Trait` from `qself` | |
174 | // (for cases like `<impl Trait>::Foo>`) | |
175 | // but we allow `impl Trait` in `GenericArgs` | |
176 | // iff there are no more PathSegments. | |
177 | if let Some(ref qself) = *qself { | |
178 | // `impl Trait` in `qself` is always illegal | |
179 | self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); | |
180 | } | |
181 | ||
182 | // Note that there should be a call to visit_path here, | |
183 | // so if any logic is added to process `Path`s a call to it should be | |
184 | // added both in visit_path and here. This code mirrors visit::walk_path. | |
185 | for (i, segment) in path.segments.iter().enumerate() { | |
186 | // Allow `impl Trait` iff we're on the final path segment | |
187 | if i == path.segments.len() - 1 { | |
188 | self.visit_path_segment(path.span, segment); | |
189 | } else { | |
190 | self.with_banned_impl_trait(|this| { | |
191 | this.visit_path_segment(path.span, segment) | |
192 | }); | |
193 | } | |
194 | } | |
195 | } | |
196 | _ => visit::walk_ty(self, t), | |
197 | } | |
198 | } | |
199 | ||
17df50a5 XL |
200 | fn visit_struct_field_def(&mut self, field: &'a FieldDef) { |
201 | if let Some(ident) = field.ident { | |
202 | if ident.name == kw::Underscore { | |
17df50a5 XL |
203 | self.visit_vis(&field.vis); |
204 | self.visit_ident(ident); | |
205 | self.visit_ty_common(&field.ty); | |
206 | self.walk_ty(&field.ty); | |
207 | walk_list!(self, visit_attribute, &field.attrs); | |
208 | return; | |
209 | } | |
210 | } | |
211 | self.visit_field_def(field); | |
212 | } | |
213 | ||
dfeec247 | 214 | fn err_handler(&self) -> &rustc_errors::Handler { |
b7449926 | 215 | &self.session.diagnostic() |
3157f602 XL |
216 | } |
217 | ||
83c7162d | 218 | fn check_lifetime(&self, ident: Ident) { |
5869c6ff | 219 | let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; |
94b46f34 | 220 | if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { |
83c7162d | 221 | self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); |
ff7c6d11 XL |
222 | } |
223 | } | |
224 | ||
83c7162d | 225 | fn check_label(&self, ident: Ident) { |
94b46f34 | 226 | if ident.without_first_quote().is_reserved() { |
83c7162d XL |
227 | self.err_handler() |
228 | .span_err(ident.span, &format!("invalid label name `{}`", ident.name)); | |
3157f602 | 229 | } |
3157f602 XL |
230 | } |
231 | ||
0531ce1d | 232 | fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { |
1b1a35ee | 233 | if let VisibilityKind::Inherited = vis.kind { |
dfeec247 | 234 | return; |
8faf50e0 XL |
235 | } |
236 | ||
dfeec247 XL |
237 | let mut err = |
238 | struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier"); | |
1b1a35ee | 239 | if vis.kind.is_pub() { |
8faf50e0 | 240 | err.span_label(vis.span, "`pub` not permitted here because it's implied"); |
3157f602 | 241 | } |
8faf50e0 XL |
242 | if let Some(note) = note { |
243 | err.note(note); | |
244 | } | |
245 | err.emit(); | |
3157f602 | 246 | } |
5bcae85e | 247 | |
5869c6ff | 248 | fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) { |
60c5eb7d XL |
249 | for Param { pat, .. } in &decl.inputs { |
250 | match pat.kind { | |
dfeec247 | 251 | PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {} |
5869c6ff XL |
252 | PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => { |
253 | report_err(pat.span, Some(ident), true) | |
dfeec247 | 254 | } |
5869c6ff | 255 | _ => report_err(pat.span, None, false), |
5bcae85e SL |
256 | } |
257 | } | |
258 | } | |
9e0c209e | 259 | |
74b04a01 XL |
260 | fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) { |
261 | if let Async::Yes { span, .. } = asyncness { | |
262 | struct_span_err!( | |
263 | self.session, | |
264 | fn_span, | |
265 | E0706, | |
266 | "functions in traits cannot be declared `async`" | |
267 | ) | |
268 | .span_label(span, "`async` because of this") | |
269 | .note("`async` trait functions are not currently supported") | |
270 | .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait") | |
271 | .emit(); | |
8faf50e0 XL |
272 | } |
273 | } | |
274 | ||
74b04a01 XL |
275 | fn check_trait_fn_not_const(&self, constness: Const) { |
276 | if let Const::Yes(span) = constness { | |
dfeec247 XL |
277 | struct_span_err!( |
278 | self.session, | |
74b04a01 | 279 | span, |
dfeec247 | 280 | E0379, |
74b04a01 | 281 | "functions in traits cannot be declared const" |
dfeec247 | 282 | ) |
74b04a01 | 283 | .span_label(span, "functions in traits cannot be const") |
dfeec247 | 284 | .emit(); |
9e0c209e SL |
285 | } |
286 | } | |
476ff2be | 287 | |
dfeec247 | 288 | // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`. |
8faf50e0 | 289 | fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) { |
476ff2be | 290 | for bound in bounds { |
8faf50e0 | 291 | if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound { |
dfeec247 XL |
292 | let mut err = self.err_handler().struct_span_err( |
293 | poly.span, | |
294 | &format!("`?Trait` is not permitted in {}", where_), | |
295 | ); | |
476ff2be | 296 | if is_trait { |
e74abb32 XL |
297 | let path_str = pprust::path_to_string(&poly.trait_ref.path); |
298 | err.note(&format!("traits are `?{}` by default", path_str)); | |
476ff2be SL |
299 | } |
300 | err.emit(); | |
301 | } | |
302 | } | |
303 | } | |
041b39d2 | 304 | |
9fa01778 XL |
305 | /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`, |
306 | /// or paths for ranges. | |
307 | // | |
308 | // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions? | |
309 | // That means making this work: | |
310 | // | |
311 | // ```rust,ignore (FIXME) | |
312 | // struct S; | |
313 | // macro_rules! m { | |
314 | // ($a:expr) => { | |
315 | // let $a = S; | |
316 | // } | |
317 | // } | |
318 | // m!(S); | |
319 | // ``` | |
041b39d2 | 320 | fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { |
e74abb32 | 321 | match expr.kind { |
29967ef6 | 322 | ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {} |
041b39d2 | 323 | ExprKind::Path(..) if allow_paths => {} |
ba9703b0 | 324 | ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} |
dfeec247 XL |
325 | _ => self.err_handler().span_err( |
326 | expr.span, | |
327 | "arbitrary expressions aren't allowed \ | |
328 | in patterns", | |
329 | ), | |
041b39d2 XL |
330 | } |
331 | } | |
0531ce1d | 332 | |
8faf50e0 XL |
333 | fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { |
334 | // Check only lifetime parameters are present and that the lifetime | |
335 | // parameters that are present have no bounds. | |
dfeec247 XL |
336 | let non_lt_param_spans: Vec<_> = params |
337 | .iter() | |
338 | .filter_map(|param| match param.kind { | |
339 | GenericParamKind::Lifetime { .. } => { | |
340 | if !param.bounds.is_empty() { | |
341 | let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); | |
342 | self.err_handler() | |
343 | .span_err(spans, "lifetime bounds cannot be used in this context"); | |
344 | } | |
345 | None | |
0531ce1d | 346 | } |
dfeec247 XL |
347 | _ => Some(param.ident.span), |
348 | }) | |
349 | .collect(); | |
8faf50e0 | 350 | if !non_lt_param_spans.is_empty() { |
dfeec247 XL |
351 | self.err_handler().span_err( |
352 | non_lt_param_spans, | |
353 | "only lifetime parameters can be used in this context", | |
354 | ); | |
0531ce1d XL |
355 | } |
356 | } | |
b7449926 | 357 | |
74b04a01 | 358 | fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { |
c295e0f8 | 359 | self.check_decl_num_args(fn_decl); |
74b04a01 XL |
360 | self.check_decl_cvaradic_pos(fn_decl); |
361 | self.check_decl_attrs(fn_decl); | |
362 | self.check_decl_self_param(fn_decl, self_semantic); | |
363 | } | |
364 | ||
c295e0f8 XL |
365 | /// Emits fatal error if function declaration has more than `u16::MAX` arguments |
366 | /// Error is fatal to prevent errors during typechecking | |
367 | fn check_decl_num_args(&self, fn_decl: &FnDecl) { | |
368 | let max_num_args: usize = u16::MAX.into(); | |
369 | if fn_decl.inputs.len() > max_num_args { | |
370 | let Param { span, .. } = fn_decl.inputs[0]; | |
371 | self.err_handler().span_fatal( | |
372 | span, | |
373 | &format!("function can not have more than {} arguments", max_num_args), | |
374 | ); | |
375 | } | |
376 | } | |
377 | ||
74b04a01 | 378 | fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) { |
dfeec247 XL |
379 | match &*fn_decl.inputs { |
380 | [Param { ty, span, .. }] => { | |
381 | if let TyKind::CVarArgs = ty.kind { | |
382 | self.err_handler().span_err( | |
383 | *span, | |
384 | "C-variadic function must be declared with at least one named argument", | |
385 | ); | |
386 | } | |
387 | } | |
388 | [ps @ .., _] => { | |
389 | for Param { ty, span, .. } in ps { | |
390 | if let TyKind::CVarArgs = ty.kind { | |
391 | self.err_handler().span_err( | |
392 | *span, | |
393 | "`...` must be the last argument of a C-variadic function", | |
394 | ); | |
395 | } | |
396 | } | |
397 | } | |
398 | _ => {} | |
399 | } | |
74b04a01 | 400 | } |
dfeec247 | 401 | |
74b04a01 | 402 | fn check_decl_attrs(&self, fn_decl: &FnDecl) { |
dc9dc135 XL |
403 | fn_decl |
404 | .inputs | |
405 | .iter() | |
406 | .flat_map(|i| i.attrs.as_ref()) | |
407 | .filter(|attr| { | |
408 | let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn]; | |
74b04a01 | 409 | !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr) |
dc9dc135 | 410 | }) |
dfeec247 XL |
411 | .for_each(|attr| { |
412 | if attr.is_doc_comment() { | |
413 | self.err_handler() | |
414 | .struct_span_err( | |
415 | attr.span, | |
416 | "documentation comments cannot be applied to function parameters", | |
417 | ) | |
418 | .span_label(attr.span, "doc comments are not allowed here") | |
419 | .emit(); | |
420 | } else { | |
421 | self.err_handler().span_err( | |
422 | attr.span, | |
423 | "allow, cfg, cfg_attr, deny, \ | |
424 | forbid, and warn are the only allowed built-in attributes in function parameters", | |
425 | ) | |
426 | } | |
dc9dc135 | 427 | }); |
b7449926 | 428 | } |
dfeec247 | 429 | |
74b04a01 XL |
430 | fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { |
431 | if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { | |
432 | if param.is_self() { | |
433 | self.err_handler() | |
434 | .struct_span_err( | |
435 | param.span, | |
436 | "`self` parameter is only allowed in associated functions", | |
437 | ) | |
438 | .span_label(param.span, "not semantically valid as function parameter") | |
439 | .note("associated functions are those in `impl` or `trait` definitions") | |
440 | .emit(); | |
441 | } | |
442 | } | |
443 | } | |
444 | ||
dfeec247 | 445 | fn check_defaultness(&self, span: Span, defaultness: Defaultness) { |
74b04a01 | 446 | if let Defaultness::Default(def_span) = defaultness { |
ba9703b0 | 447 | let span = self.session.source_map().guess_head_span(span); |
dfeec247 | 448 | self.err_handler() |
fc512014 | 449 | .struct_span_err(span, "`default` is only allowed on items in trait impls") |
74b04a01 | 450 | .span_label(def_span, "`default` because of this") |
dfeec247 XL |
451 | .emit(); |
452 | } | |
453 | } | |
454 | ||
74b04a01 | 455 | fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) { |
dfeec247 | 456 | self.err_handler() |
74b04a01 | 457 | .struct_span_err(sp, msg) |
dfeec247 XL |
458 | .span_suggestion( |
459 | self.session.source_map().end_point(sp), | |
460 | &format!("provide a definition for the {}", ctx), | |
461 | sugg.to_string(), | |
462 | Applicability::HasPlaceholders, | |
463 | ) | |
464 | .emit(); | |
465 | } | |
466 | ||
74b04a01 XL |
467 | fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) { |
468 | if body.is_none() { | |
469 | let msg = format!("associated {} in `impl` without body", ctx); | |
470 | self.error_item_without_body(sp, ctx, &msg, sugg); | |
471 | } | |
472 | } | |
473 | ||
474 | fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) { | |
dfeec247 XL |
475 | let span = match bounds { |
476 | [] => return, | |
477 | [b0] => b0.span(), | |
478 | [b0, .., bl] => b0.span().to(bl.span()), | |
479 | }; | |
480 | self.err_handler() | |
74b04a01 | 481 | .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx)) |
dfeec247 XL |
482 | .emit(); |
483 | } | |
484 | ||
74b04a01 XL |
485 | fn check_foreign_ty_genericless(&self, generics: &Generics) { |
486 | let cannot_have = |span, descr, remove_descr| { | |
487 | self.err_handler() | |
488 | .struct_span_err( | |
489 | span, | |
490 | &format!("`type`s inside `extern` blocks cannot have {}", descr), | |
491 | ) | |
492 | .span_suggestion( | |
493 | span, | |
494 | &format!("remove the {}", remove_descr), | |
495 | String::new(), | |
496 | Applicability::MaybeIncorrect, | |
497 | ) | |
498 | .span_label(self.current_extern_span(), "`extern` block begins here") | |
499 | .note(MORE_EXTERN) | |
500 | .emit(); | |
501 | }; | |
502 | ||
503 | if !generics.params.is_empty() { | |
504 | cannot_have(generics.span, "generic parameters", "generic parameters"); | |
505 | } | |
506 | ||
507 | if !generics.where_clause.predicates.is_empty() { | |
508 | cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause"); | |
509 | } | |
510 | } | |
511 | ||
512 | fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) { | |
513 | let body = match body { | |
514 | None => return, | |
515 | Some(body) => body, | |
516 | }; | |
517 | self.err_handler() | |
518 | .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind)) | |
519 | .span_label(ident.span, "cannot have a body") | |
520 | .span_label(body, "the invalid body") | |
521 | .span_label( | |
522 | self.current_extern_span(), | |
523 | format!( | |
524 | "`extern` blocks define existing foreign {0}s and {0}s \ | |
525 | inside of them cannot have a body", | |
526 | kind | |
527 | ), | |
528 | ) | |
529 | .note(MORE_EXTERN) | |
530 | .emit(); | |
531 | } | |
532 | ||
533 | /// An `fn` in `extern { ... }` cannot have a body `{ ... }`. | |
534 | fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) { | |
535 | let body = match body { | |
536 | None => return, | |
537 | Some(body) => body, | |
538 | }; | |
539 | self.err_handler() | |
540 | .struct_span_err(ident.span, "incorrect function inside `extern` block") | |
541 | .span_label(ident.span, "cannot have a body") | |
542 | .span_suggestion( | |
543 | body.span, | |
544 | "remove the invalid body", | |
545 | ";".to_string(), | |
546 | Applicability::MaybeIncorrect, | |
547 | ) | |
548 | .help( | |
549 | "you might have meant to write a function accessible through FFI, \ | |
550 | which can be done by writing `extern fn` outside of the `extern` block", | |
551 | ) | |
552 | .span_label( | |
553 | self.current_extern_span(), | |
554 | "`extern` blocks define existing foreign functions and functions \ | |
555 | inside of them cannot have a body", | |
556 | ) | |
557 | .note(MORE_EXTERN) | |
558 | .emit(); | |
559 | } | |
560 | ||
561 | fn current_extern_span(&self) -> Span { | |
ba9703b0 | 562 | self.session.source_map().guess_head_span(self.extern_mod.unwrap().span) |
74b04a01 XL |
563 | } |
564 | ||
29967ef6 | 565 | /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. |
74b04a01 XL |
566 | fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { |
567 | if header.has_qualifiers() { | |
568 | self.err_handler() | |
569 | .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers") | |
570 | .span_label(self.current_extern_span(), "in this `extern` block") | |
fc512014 | 571 | .span_suggestion_verbose( |
74b04a01 XL |
572 | span.until(ident.span.shrink_to_lo()), |
573 | "remove the qualifiers", | |
574 | "fn ".to_string(), | |
575 | Applicability::MaybeIncorrect, | |
576 | ) | |
577 | .emit(); | |
578 | } | |
579 | } | |
580 | ||
cdc7bbd5 XL |
581 | /// An item in `extern { ... }` cannot use non-ascii identifier. |
582 | fn check_foreign_item_ascii_only(&self, ident: Ident) { | |
583 | let symbol_str = ident.as_str(); | |
584 | if !symbol_str.is_ascii() { | |
585 | let n = 83942; | |
586 | self.err_handler() | |
587 | .struct_span_err( | |
588 | ident.span, | |
589 | "items in `extern` blocks cannot use non-ascii identifiers", | |
590 | ) | |
591 | .span_label(self.current_extern_span(), "in this `extern` block") | |
592 | .note(&format!( | |
c295e0f8 | 593 | "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information", |
cdc7bbd5 XL |
594 | n, n, |
595 | )) | |
596 | .emit(); | |
597 | } | |
598 | } | |
599 | ||
74b04a01 XL |
600 | /// Reject C-varadic type unless the function is foreign, |
601 | /// or free and `unsafe extern "C"` semantically. | |
602 | fn check_c_varadic_type(&self, fk: FnKind<'a>) { | |
603 | match (fk.ctxt(), fk.header()) { | |
604 | (Some(FnCtxt::Foreign), _) => return, | |
605 | (Some(FnCtxt::Free), Some(header)) => match header.ext { | |
606 | Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit | |
607 | if matches!(header.unsafety, Unsafe::Yes(_)) => | |
608 | { | |
609 | return; | |
610 | } | |
611 | _ => {} | |
612 | }, | |
613 | _ => {} | |
614 | }; | |
615 | ||
616 | for Param { ty, span, .. } in &fk.decl().inputs { | |
dfeec247 XL |
617 | if let TyKind::CVarArgs = ty.kind { |
618 | self.err_handler() | |
619 | .struct_span_err( | |
620 | *span, | |
136023e0 | 621 | "only foreign or `unsafe extern \"C\"` functions may be C-variadic", |
dfeec247 XL |
622 | ) |
623 | .emit(); | |
624 | } | |
625 | } | |
626 | } | |
9fa01778 | 627 | |
74b04a01 XL |
628 | fn check_item_named(&self, ident: Ident, kind: &str) { |
629 | if ident.name != kw::Underscore { | |
630 | return; | |
631 | } | |
632 | self.err_handler() | |
633 | .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind)) | |
634 | .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind)) | |
635 | .emit(); | |
636 | } | |
ba9703b0 | 637 | |
f9f354fc XL |
638 | fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) { |
639 | if ident.name.as_str().is_ascii() { | |
640 | return; | |
641 | } | |
642 | let head_span = self.session.source_map().guess_head_span(item_span); | |
643 | struct_span_err!( | |
644 | self.session, | |
645 | head_span, | |
646 | E0754, | |
647 | "`#[no_mangle]` requires ASCII identifier" | |
648 | ) | |
649 | .emit(); | |
650 | } | |
651 | ||
652 | fn check_mod_file_item_asciionly(&self, ident: Ident) { | |
653 | if ident.name.as_str().is_ascii() { | |
654 | return; | |
655 | } | |
656 | struct_span_err!( | |
657 | self.session, | |
658 | ident.span, | |
659 | E0754, | |
cdc7bbd5 | 660 | "trying to load file for module `{}` with non-ascii identifier name", |
f9f354fc XL |
661 | ident.name |
662 | ) | |
663 | .help("consider using `#[path]` attribute to specify filesystem path") | |
664 | .emit(); | |
665 | } | |
666 | ||
ba9703b0 XL |
667 | fn deny_generic_params(&self, generics: &Generics, ident_span: Span) { |
668 | if !generics.params.is_empty() { | |
669 | struct_span_err!( | |
670 | self.session, | |
671 | generics.span, | |
672 | E0567, | |
673 | "auto traits cannot have generic parameters" | |
674 | ) | |
675 | .span_label(ident_span, "auto trait cannot have generic parameters") | |
676 | .span_suggestion( | |
677 | generics.span, | |
678 | "remove the parameters", | |
679 | String::new(), | |
680 | Applicability::MachineApplicable, | |
681 | ) | |
682 | .emit(); | |
683 | } | |
684 | } | |
685 | ||
c295e0f8 XL |
686 | fn emit_e0568(&self, span: Span, ident_span: Span) { |
687 | struct_span_err!( | |
688 | self.session, | |
689 | span, | |
690 | E0568, | |
691 | "auto traits cannot have super traits or lifetime bounds" | |
692 | ) | |
693 | .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds") | |
694 | .span_suggestion( | |
695 | span, | |
696 | "remove the super traits or lifetime bounds", | |
697 | String::new(), | |
698 | Applicability::MachineApplicable, | |
699 | ) | |
700 | .emit(); | |
701 | } | |
702 | ||
ba9703b0 | 703 | fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { |
c295e0f8 XL |
704 | if let [.., last] = &bounds[..] { |
705 | let span = ident_span.shrink_to_hi().to(last.span()); | |
706 | self.emit_e0568(span, ident_span); | |
707 | } | |
708 | } | |
709 | ||
710 | fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) { | |
711 | if !where_clause.predicates.is_empty() { | |
712 | self.emit_e0568(where_clause.span, ident_span); | |
ba9703b0 XL |
713 | } |
714 | } | |
715 | ||
716 | fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) { | |
717 | if !trait_items.is_empty() { | |
718 | let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); | |
c295e0f8 | 719 | let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); |
ba9703b0 XL |
720 | struct_span_err!( |
721 | self.session, | |
722 | spans, | |
723 | E0380, | |
c295e0f8 XL |
724 | "auto traits cannot have associated items" |
725 | ) | |
726 | .span_suggestion( | |
727 | total_span, | |
728 | "remove these associated items", | |
729 | String::new(), | |
730 | Applicability::MachineApplicable, | |
ba9703b0 | 731 | ) |
c295e0f8 | 732 | .span_label(ident_span, "auto trait cannot have associated items") |
ba9703b0 XL |
733 | .emit(); |
734 | } | |
735 | } | |
736 | ||
737 | fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String { | |
738 | // Lifetimes always come first. | |
739 | let lt_sugg = data.args.iter().filter_map(|arg| match arg { | |
740 | AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => { | |
741 | Some(pprust::to_string(|s| s.print_generic_arg(lt))) | |
742 | } | |
743 | _ => None, | |
744 | }); | |
745 | let args_sugg = data.args.iter().filter_map(|a| match a { | |
746 | AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => { | |
747 | None | |
748 | } | |
749 | AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))), | |
750 | }); | |
751 | // Constraints always come last. | |
752 | let constraint_sugg = data.args.iter().filter_map(|a| match a { | |
753 | AngleBracketedArg::Arg(_) => None, | |
754 | AngleBracketedArg::Constraint(c) => { | |
755 | Some(pprust::to_string(|s| s.print_assoc_constraint(c))) | |
756 | } | |
757 | }); | |
758 | format!( | |
759 | "<{}>", | |
760 | lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ") | |
761 | ) | |
762 | } | |
763 | ||
764 | /// Enforce generic args coming before constraints in `<...>` of a path segment. | |
765 | fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) { | |
766 | // Early exit in case it's partitioned as it should be. | |
767 | if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) { | |
768 | return; | |
769 | } | |
770 | // Find all generic argument coming after the first constraint... | |
771 | let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) = | |
772 | data.args.iter().partition_map(|arg| match arg { | |
773 | AngleBracketedArg::Constraint(c) => Either::Left(c.span), | |
774 | AngleBracketedArg::Arg(a) => Either::Right(a.span()), | |
775 | }); | |
776 | let args_len = arg_spans.len(); | |
777 | let constraint_len = constraint_spans.len(); | |
778 | // ...and then error: | |
779 | self.err_handler() | |
780 | .struct_span_err( | |
781 | arg_spans.clone(), | |
782 | "generic arguments must come before the first constraint", | |
783 | ) | |
784 | .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len))) | |
785 | .span_label( | |
786 | *arg_spans.iter().last().unwrap(), | |
787 | &format!("generic argument{}", pluralize!(args_len)), | |
788 | ) | |
789 | .span_labels(constraint_spans, "") | |
790 | .span_labels(arg_spans, "") | |
791 | .span_suggestion_verbose( | |
792 | data.span, | |
793 | &format!( | |
794 | "move the constraint{} after the generic argument{}", | |
795 | pluralize!(constraint_len), | |
796 | pluralize!(args_len) | |
797 | ), | |
798 | self.correct_generic_order_suggestion(&data), | |
799 | Applicability::MachineApplicable, | |
800 | ) | |
801 | .emit(); | |
802 | } | |
17df50a5 XL |
803 | |
804 | fn visit_ty_common(&mut self, ty: &'a Ty) { | |
805 | match ty.kind { | |
806 | TyKind::BareFn(ref bfty) => { | |
807 | self.check_fn_decl(&bfty.decl, SelfSemantic::No); | |
808 | Self::check_decl_no_pat(&bfty.decl, |span, _, _| { | |
809 | struct_span_err!( | |
810 | self.session, | |
811 | span, | |
812 | E0561, | |
813 | "patterns aren't allowed in function pointer types" | |
814 | ) | |
815 | .emit(); | |
816 | }); | |
817 | self.check_late_bound_lifetime_defs(&bfty.generic_params); | |
94222f64 XL |
818 | if let Extern::Implicit = bfty.ext { |
819 | let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo()); | |
820 | self.maybe_lint_missing_abi(sig_span, ty.id); | |
821 | } | |
17df50a5 XL |
822 | } |
823 | TyKind::TraitObject(ref bounds, ..) => { | |
824 | let mut any_lifetime_bounds = false; | |
825 | for bound in bounds { | |
826 | if let GenericBound::Outlives(ref lifetime) = *bound { | |
827 | if any_lifetime_bounds { | |
828 | struct_span_err!( | |
829 | self.session, | |
830 | lifetime.ident.span, | |
831 | E0226, | |
832 | "only a single explicit lifetime bound is permitted" | |
833 | ) | |
834 | .emit(); | |
835 | break; | |
836 | } | |
837 | any_lifetime_bounds = true; | |
838 | } | |
839 | } | |
840 | self.no_questions_in_bounds(bounds, "trait object types", false); | |
841 | } | |
842 | TyKind::ImplTrait(_, ref bounds) => { | |
843 | if self.is_impl_trait_banned { | |
844 | struct_span_err!( | |
845 | self.session, | |
846 | ty.span, | |
847 | E0667, | |
848 | "`impl Trait` is not allowed in path parameters" | |
849 | ) | |
850 | .emit(); | |
851 | } | |
852 | ||
853 | if let Some(outer_impl_trait_sp) = self.outer_impl_trait { | |
854 | struct_span_err!( | |
855 | self.session, | |
856 | ty.span, | |
857 | E0666, | |
858 | "nested `impl Trait` is not allowed" | |
859 | ) | |
860 | .span_label(outer_impl_trait_sp, "outer `impl Trait`") | |
861 | .span_label(ty.span, "nested `impl Trait` here") | |
862 | .emit(); | |
863 | } | |
864 | ||
865 | if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { | |
866 | self.err_handler().span_err(ty.span, "at least one trait must be specified"); | |
867 | } | |
868 | } | |
869 | _ => {} | |
870 | } | |
871 | } | |
94222f64 XL |
872 | |
873 | fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) { | |
874 | // FIXME(davidtwco): This is a hack to detect macros which produce spans of the | |
875 | // call site which do not have a macro backtrace. See #61963. | |
876 | let is_macro_callsite = self | |
877 | .session | |
878 | .source_map() | |
879 | .span_to_snippet(span) | |
880 | .map(|snippet| snippet.starts_with("#[")) | |
881 | .unwrap_or(true); | |
882 | if !is_macro_callsite { | |
883 | self.lint_buffer.buffer_lint_with_diagnostic( | |
884 | MISSING_ABI, | |
885 | id, | |
886 | span, | |
887 | "extern declarations without an explicit ABI are deprecated", | |
888 | BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK), | |
889 | ) | |
890 | } | |
891 | } | |
9fa01778 | 892 | } |
b7449926 | 893 | |
ba9703b0 XL |
894 | /// Checks that generic parameters are in the correct order, |
895 | /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`) | |
5869c6ff | 896 | fn validate_generic_param_order( |
532ac7d7 | 897 | sess: &Session, |
dfeec247 | 898 | handler: &rustc_errors::Handler, |
5869c6ff | 899 | generics: &[GenericParam], |
9fa01778 XL |
900 | span: Span, |
901 | ) { | |
902 | let mut max_param: Option<ParamKindOrd> = None; | |
903 | let mut out_of_order = FxHashMap::default(); | |
136023e0 | 904 | let mut param_idents = Vec::with_capacity(generics.len()); |
9fa01778 | 905 | |
136023e0 XL |
906 | for (idx, param) in generics.iter().enumerate() { |
907 | let ident = param.ident; | |
908 | let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span); | |
5869c6ff | 909 | let (ord_kind, ident) = match ¶m.kind { |
136023e0 XL |
910 | GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()), |
911 | GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()), | |
5869c6ff XL |
912 | GenericParamKind::Const { ref ty, kw_span: _, default: _ } => { |
913 | let ty = pprust::ty_to_string(ty); | |
cdc7bbd5 | 914 | let unordered = sess.features_untracked().unordered_const_ty_params(); |
136023e0 | 915 | (ParamKindOrd::Const { unordered }, format!("const {}: {}", ident, ty)) |
5869c6ff XL |
916 | } |
917 | }; | |
136023e0 | 918 | param_idents.push((kind, ord_kind, bounds, idx, ident)); |
9fa01778 | 919 | match max_param { |
136023e0 XL |
920 | Some(max_param) if max_param > ord_kind => { |
921 | let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![])); | |
9fa01778 XL |
922 | entry.1.push(span); |
923 | } | |
136023e0 | 924 | Some(_) | None => max_param = Some(ord_kind), |
9fa01778 XL |
925 | }; |
926 | } | |
927 | ||
9fa01778 | 928 | if !out_of_order.is_empty() { |
136023e0 | 929 | let mut ordered_params = "<".to_string(); |
5869c6ff | 930 | param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i)); |
9fa01778 | 931 | let mut first = true; |
5869c6ff | 932 | for (kind, _, bounds, _, ident) in param_idents { |
9fa01778 XL |
933 | if !first { |
934 | ordered_params += ", "; | |
935 | } | |
936 | ordered_params += &ident; | |
136023e0 XL |
937 | |
938 | if !bounds.is_empty() { | |
939 | ordered_params += ": "; | |
940 | ordered_params += &pprust::bounds_to_string(&bounds); | |
532ac7d7 | 941 | } |
136023e0 | 942 | |
5869c6ff XL |
943 | match kind { |
944 | GenericParamKind::Type { default: Some(default) } => { | |
945 | ordered_params += " = "; | |
946 | ordered_params += &pprust::ty_to_string(default); | |
947 | } | |
948 | GenericParamKind::Type { default: None } => (), | |
949 | GenericParamKind::Lifetime => (), | |
17df50a5 XL |
950 | GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { |
951 | ordered_params += " = "; | |
952 | ordered_params += &pprust::expr_to_string(&*default.value); | |
953 | } | |
954 | GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), | |
5869c6ff | 955 | } |
9fa01778 XL |
956 | first = false; |
957 | } | |
9fa01778 | 958 | |
136023e0 XL |
959 | ordered_params += ">"; |
960 | ||
961 | for (param_ord, (max_param, spans)) in &out_of_order { | |
962 | let mut err = handler.struct_span_err( | |
74b04a01 | 963 | spans.clone(), |
532ac7d7 | 964 | &format!( |
74b04a01 XL |
965 | "{} parameters must be declared prior to {} parameters", |
966 | param_ord, max_param, | |
532ac7d7 | 967 | ), |
9fa01778 | 968 | ); |
136023e0 XL |
969 | err.span_suggestion( |
970 | span, | |
971 | &format!( | |
972 | "reorder the parameters: lifetimes, {}", | |
973 | if sess.features_untracked().unordered_const_ty_params() { | |
974 | "then consts and types" | |
975 | } else { | |
976 | "then types, then consts" | |
977 | } | |
978 | ), | |
979 | ordered_params.clone(), | |
980 | Applicability::MachineApplicable, | |
981 | ); | |
982 | err.emit(); | |
983 | } | |
9fa01778 | 984 | } |
3157f602 XL |
985 | } |
986 | ||
476ff2be | 987 | impl<'a> Visitor<'a> for AstValidator<'a> { |
60c5eb7d XL |
988 | fn visit_attribute(&mut self, attr: &Attribute) { |
989 | validate_attr::check_meta(&self.session.parse_sess, attr); | |
990 | } | |
991 | ||
476ff2be | 992 | fn visit_expr(&mut self, expr: &'a Expr) { |
94222f64 XL |
993 | self.with_let_allowed(false, |this, let_allowed| match &expr.kind { |
994 | ExprKind::If(cond, then, opt_else) => { | |
995 | this.visit_block(then); | |
996 | walk_list!(this, visit_expr, opt_else); | |
997 | this.with_let_allowed(true, |this, _| this.visit_expr(cond)); | |
998 | return; | |
999 | } | |
1000 | ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr), | |
1001 | ExprKind::LlvmInlineAsm(..) if !this.session.target.allow_asm => { | |
dfeec247 | 1002 | struct_span_err!( |
94222f64 | 1003 | this.session, |
dfeec247 XL |
1004 | expr.span, |
1005 | E0472, | |
ba9703b0 | 1006 | "llvm_asm! is unsupported on this target" |
dfeec247 XL |
1007 | ) |
1008 | .emit(); | |
3157f602 | 1009 | } |
94222f64 XL |
1010 | ExprKind::Match(expr, arms) => { |
1011 | this.visit_expr(expr); | |
1012 | for arm in arms { | |
1013 | this.visit_expr(&arm.body); | |
1014 | this.visit_pat(&arm.pat); | |
1015 | walk_list!(this, visit_attribute, &arm.attrs); | |
1016 | if let Some(ref guard) = arm.guard { | |
1017 | if let ExprKind::Let(_, ref expr, _) = guard.kind { | |
1018 | this.with_let_allowed(true, |this, _| this.visit_expr(expr)); | |
1019 | return; | |
1020 | } | |
1021 | } | |
1022 | } | |
1023 | } | |
1024 | ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => { | |
1025 | this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr)); | |
1026 | return; | |
1027 | } | |
1028 | ExprKind::While(cond, then, opt_label) => { | |
1029 | walk_list!(this, visit_label, opt_label); | |
1030 | this.visit_block(then); | |
1031 | this.with_let_allowed(true, |this, _| this.visit_expr(cond)); | |
1032 | return; | |
1033 | } | |
1034 | _ => visit::walk_expr(this, expr), | |
1035 | }); | |
3157f602 XL |
1036 | } |
1037 | ||
476ff2be | 1038 | fn visit_ty(&mut self, ty: &'a Ty) { |
17df50a5 | 1039 | self.visit_ty_common(ty); |
9fa01778 | 1040 | self.walk_ty(ty) |
5bcae85e SL |
1041 | } |
1042 | ||
2c00a5a8 | 1043 | fn visit_label(&mut self, label: &'a Label) { |
83c7162d | 1044 | self.check_label(label.ident); |
2c00a5a8 XL |
1045 | visit::walk_label(self, label); |
1046 | } | |
1047 | ||
ff7c6d11 | 1048 | fn visit_lifetime(&mut self, lifetime: &'a Lifetime) { |
83c7162d | 1049 | self.check_lifetime(lifetime.ident); |
ff7c6d11 | 1050 | visit::walk_lifetime(self, lifetime); |
3157f602 XL |
1051 | } |
1052 | ||
17df50a5 | 1053 | fn visit_field_def(&mut self, s: &'a FieldDef) { |
17df50a5 XL |
1054 | visit::walk_field_def(self, s) |
1055 | } | |
1056 | ||
476ff2be | 1057 | fn visit_item(&mut self, item: &'a Item) { |
3dfed10e | 1058 | if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) { |
9fa01778 XL |
1059 | self.has_proc_macro_decls = true; |
1060 | } | |
1061 | ||
3dfed10e | 1062 | if self.session.contains_name(&item.attrs, sym::no_mangle) { |
f9f354fc XL |
1063 | self.check_nomangle_item_asciionly(item.ident, item.span); |
1064 | } | |
1065 | ||
e74abb32 | 1066 | match item.kind { |
5869c6ff | 1067 | ItemKind::Impl(box ImplKind { |
dfeec247 XL |
1068 | unsafety, |
1069 | polarity, | |
1070 | defaultness: _, | |
94222f64 XL |
1071 | constness, |
1072 | ref generics, | |
ba9703b0 | 1073 | of_trait: Some(ref t), |
dfeec247 | 1074 | ref self_ty, |
94222f64 | 1075 | ref items, |
5869c6ff | 1076 | }) => { |
94222f64 | 1077 | self.with_in_trait_impl(true, Some(constness), |this| { |
74b04a01 XL |
1078 | this.invalid_visibility(&item.vis, None); |
1079 | if let TyKind::Err = self_ty.kind { | |
1080 | this.err_handler() | |
1081 | .struct_span_err( | |
1082 | item.span, | |
1083 | "`impl Trait for .. {}` is an obsolete syntax", | |
1084 | ) | |
1085 | .help("use `auto trait Trait {}` instead") | |
1086 | .emit(); | |
1087 | } | |
ba9703b0 | 1088 | if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) { |
74b04a01 XL |
1089 | struct_span_err!( |
1090 | this.session, | |
ba9703b0 | 1091 | sp.to(t.path.span), |
74b04a01 XL |
1092 | E0198, |
1093 | "negative impls cannot be unsafe" | |
1094 | ) | |
ba9703b0 | 1095 | .span_label(sp, "negative because of this") |
74b04a01 | 1096 | .span_label(span, "unsafe because of this") |
dfeec247 | 1097 | .emit(); |
9e0c209e | 1098 | } |
74b04a01 | 1099 | |
94222f64 XL |
1100 | this.visit_vis(&item.vis); |
1101 | this.visit_ident(item.ident); | |
1102 | if let Const::Yes(_) = constness { | |
1103 | this.with_tilde_const_allowed(|this| this.visit_generics(generics)); | |
1104 | } else { | |
1105 | this.visit_generics(generics); | |
1106 | } | |
1107 | this.visit_trait_ref(t); | |
1108 | this.visit_ty(self_ty); | |
1109 | ||
1110 | walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); | |
74b04a01 XL |
1111 | }); |
1112 | return; // Avoid visiting again. | |
3157f602 | 1113 | } |
5869c6ff | 1114 | ItemKind::Impl(box ImplKind { |
dfeec247 XL |
1115 | unsafety, |
1116 | polarity, | |
1117 | defaultness, | |
1118 | constness, | |
1119 | generics: _, | |
1120 | of_trait: None, | |
ba9703b0 | 1121 | ref self_ty, |
dfeec247 | 1122 | items: _, |
5869c6ff | 1123 | }) => { |
ba9703b0 XL |
1124 | let error = |annotation_span, annotation| { |
1125 | let mut err = self.err_handler().struct_span_err( | |
1126 | self_ty.span, | |
1127 | &format!("inherent impls cannot be {}", annotation), | |
1128 | ); | |
1129 | err.span_label(annotation_span, &format!("{} because of this", annotation)); | |
1130 | err.span_label(self_ty.span, "inherent impl for this type"); | |
1131 | err | |
1132 | }; | |
1133 | ||
dfeec247 XL |
1134 | self.invalid_visibility( |
1135 | &item.vis, | |
1136 | Some("place qualifiers on individual impl items instead"), | |
1137 | ); | |
74b04a01 | 1138 | if let Unsafe::Yes(span) = unsafety { |
ba9703b0 | 1139 | error(span, "unsafe").code(error_code!(E0197)).emit(); |
2c00a5a8 | 1140 | } |
ba9703b0 XL |
1141 | if let ImplPolarity::Negative(span) = polarity { |
1142 | error(span, "negative").emit(); | |
2c00a5a8 | 1143 | } |
74b04a01 | 1144 | if let Defaultness::Default(def_span) = defaultness { |
ba9703b0 | 1145 | error(def_span, "`default`") |
74b04a01 | 1146 | .note("only trait implementations may be annotated with `default`") |
dfeec247 XL |
1147 | .emit(); |
1148 | } | |
74b04a01 | 1149 | if let Const::Yes(span) = constness { |
ba9703b0 | 1150 | error(span, "`const`") |
dfeec247 XL |
1151 | .note("only trait implementations may be annotated with `const`") |
1152 | .emit(); | |
2c00a5a8 | 1153 | } |
3157f602 | 1154 | } |
94222f64 | 1155 | ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => { |
74b04a01 | 1156 | self.check_defaultness(item.span, def); |
74b04a01 XL |
1157 | |
1158 | if body.is_none() { | |
1159 | let msg = "free function without a body"; | |
1160 | self.error_item_without_body(item.span, "function", msg, " { <body> }"); | |
dfeec247 | 1161 | } |
94222f64 XL |
1162 | self.visit_vis(&item.vis); |
1163 | self.visit_ident(item.ident); | |
1164 | if let Const::Yes(_) = sig.header.constness { | |
1165 | self.with_tilde_const_allowed(|this| this.visit_generics(generics)); | |
1166 | } else { | |
1167 | self.visit_generics(generics); | |
1168 | } | |
1169 | let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); | |
1170 | self.visit_fn(kind, item.span, item.id); | |
1171 | walk_list!(self, visit_attribute, &item.attrs); | |
1172 | return; // Avoid visiting again. | |
9fa01778 | 1173 | } |
94222f64 | 1174 | ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => { |
74b04a01 | 1175 | let old_item = mem::replace(&mut self.extern_mod, Some(item)); |
0531ce1d XL |
1176 | self.invalid_visibility( |
1177 | &item.vis, | |
1178 | Some("place qualifiers on individual foreign items instead"), | |
1179 | ); | |
1b1a35ee XL |
1180 | if let Unsafe::Yes(span) = unsafety { |
1181 | self.err_handler().span_err(span, "extern block cannot be declared unsafe"); | |
1182 | } | |
94222f64 XL |
1183 | if abi.is_none() { |
1184 | self.maybe_lint_missing_abi(item.span, item.id); | |
1185 | } | |
74b04a01 XL |
1186 | visit::walk_item(self, item); |
1187 | self.extern_mod = old_item; | |
1188 | return; // Avoid visiting again. | |
3157f602 XL |
1189 | } |
1190 | ItemKind::Enum(ref def, _) => { | |
1191 | for variant in &def.variants { | |
60c5eb7d | 1192 | self.invalid_visibility(&variant.vis, None); |
e1599b0c | 1193 | for field in variant.data.fields() { |
0531ce1d | 1194 | self.invalid_visibility(&field.vis, None); |
3157f602 XL |
1195 | } |
1196 | } | |
1197 | } | |
5869c6ff XL |
1198 | ItemKind::Trait(box TraitKind( |
1199 | is_auto, | |
1200 | _, | |
1201 | ref generics, | |
1202 | ref bounds, | |
1203 | ref trait_items, | |
1204 | )) => { | |
abe05a73 XL |
1205 | if is_auto == IsAuto::Yes { |
1206 | // Auto traits cannot have generics, super traits nor contain items. | |
ba9703b0 XL |
1207 | self.deny_generic_params(generics, item.ident.span); |
1208 | self.deny_super_traits(bounds, item.ident.span); | |
c295e0f8 | 1209 | self.deny_where_clause(&generics.where_clause, item.ident.span); |
ba9703b0 | 1210 | self.deny_items(trait_items, item.ident.span); |
abe05a73 | 1211 | } |
476ff2be | 1212 | self.no_questions_in_bounds(bounds, "supertraits", true); |
dfeec247 XL |
1213 | |
1214 | // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound | |
1215 | // context for the supertraits. | |
1216 | self.visit_vis(&item.vis); | |
1217 | self.visit_ident(item.ident); | |
1218 | self.visit_generics(generics); | |
94222f64 | 1219 | self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds)); |
74b04a01 | 1220 | walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait); |
dfeec247 XL |
1221 | walk_list!(self, visit_attribute, &item.attrs); |
1222 | return; | |
9e0c209e | 1223 | } |
6a06907d | 1224 | ItemKind::Mod(unsafety, ref mod_kind) => { |
1b1a35ee XL |
1225 | if let Unsafe::Yes(span) = unsafety { |
1226 | self.err_handler().span_err(span, "module cannot be declared unsafe"); | |
1227 | } | |
0731742a | 1228 | // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). |
6a06907d XL |
1229 | if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) |
1230 | && !self.session.contains_name(&item.attrs, sym::path) | |
1231 | { | |
f9f354fc XL |
1232 | self.check_mod_file_item_asciionly(item.ident); |
1233 | } | |
5bcae85e | 1234 | } |
17df50a5 XL |
1235 | ItemKind::Struct(ref vdata, ref generics) => match vdata { |
1236 | // Duplicating the `Visitor` logic allows catching all cases | |
1237 | // of `Anonymous(Struct, Union)` outside of a field struct or union. | |
1238 | // | |
1239 | // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it | |
1240 | // encounters, and only on `ItemKind::Struct` and `ItemKind::Union` | |
1241 | // it uses `visit_ty_common`, which doesn't contain that specific check. | |
1242 | VariantData::Struct(ref fields, ..) => { | |
1243 | self.visit_vis(&item.vis); | |
1244 | self.visit_ident(item.ident); | |
1245 | self.visit_generics(generics); | |
1246 | self.with_banned_assoc_ty_bound(|this| { | |
1247 | walk_list!(this, visit_struct_field_def, fields); | |
1248 | }); | |
1249 | walk_list!(self, visit_attribute, &item.attrs); | |
1250 | return; | |
9e0c209e | 1251 | } |
17df50a5 XL |
1252 | _ => {} |
1253 | }, | |
1254 | ItemKind::Union(ref vdata, ref generics) => { | |
b7449926 | 1255 | if vdata.fields().is_empty() { |
dfeec247 | 1256 | self.err_handler().span_err(item.span, "unions cannot have zero fields"); |
9e0c209e | 1257 | } |
17df50a5 XL |
1258 | match vdata { |
1259 | VariantData::Struct(ref fields, ..) => { | |
1260 | self.visit_vis(&item.vis); | |
1261 | self.visit_ident(item.ident); | |
1262 | self.visit_generics(generics); | |
1263 | self.with_banned_assoc_ty_bound(|this| { | |
1264 | walk_list!(this, visit_struct_field_def, fields); | |
1265 | }); | |
1266 | walk_list!(self, visit_attribute, &item.attrs); | |
1267 | return; | |
1268 | } | |
1269 | _ => {} | |
1270 | } | |
9e0c209e | 1271 | } |
74b04a01 XL |
1272 | ItemKind::Const(def, .., None) => { |
1273 | self.check_defaultness(item.span, def); | |
1274 | let msg = "free constant item without body"; | |
1275 | self.error_item_without_body(item.span, "constant", msg, " = <expr>;"); | |
1276 | } | |
1277 | ItemKind::Static(.., None) => { | |
1278 | let msg = "free static item without body"; | |
1279 | self.error_item_without_body(item.span, "static", msg, " = <expr>;"); | |
1280 | } | |
5869c6ff | 1281 | ItemKind::TyAlias(box TyAliasKind(def, _, ref bounds, ref body)) => { |
74b04a01 XL |
1282 | self.check_defaultness(item.span, def); |
1283 | if body.is_none() { | |
1284 | let msg = "free type alias without body"; | |
1285 | self.error_item_without_body(item.span, "type", msg, " = <type>;"); | |
1286 | } | |
1287 | self.check_type_no_bounds(bounds, "this context"); | |
1288 | } | |
3157f602 XL |
1289 | _ => {} |
1290 | } | |
1291 | ||
94222f64 | 1292 | visit::walk_item(self, item); |
3157f602 XL |
1293 | } |
1294 | ||
476ff2be | 1295 | fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { |
74b04a01 | 1296 | match &fi.kind { |
5869c6ff | 1297 | ForeignItemKind::Fn(box FnKind(def, sig, _, body)) => { |
74b04a01 XL |
1298 | self.check_defaultness(fi.span, *def); |
1299 | self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); | |
1300 | self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); | |
cdc7bbd5 | 1301 | self.check_foreign_item_ascii_only(fi.ident); |
3157f602 | 1302 | } |
5869c6ff | 1303 | ForeignItemKind::TyAlias(box TyAliasKind(def, generics, bounds, body)) => { |
74b04a01 XL |
1304 | self.check_defaultness(fi.span, *def); |
1305 | self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span)); | |
1306 | self.check_type_no_bounds(bounds, "`extern` blocks"); | |
1307 | self.check_foreign_ty_genericless(generics); | |
cdc7bbd5 | 1308 | self.check_foreign_item_ascii_only(fi.ident); |
74b04a01 XL |
1309 | } |
1310 | ForeignItemKind::Static(_, _, body) => { | |
1311 | self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span)); | |
cdc7bbd5 | 1312 | self.check_foreign_item_ascii_only(fi.ident); |
74b04a01 | 1313 | } |
ba9703b0 | 1314 | ForeignItemKind::MacCall(..) => {} |
3157f602 XL |
1315 | } |
1316 | ||
5bcae85e | 1317 | visit::walk_foreign_item(self, fi) |
3157f602 XL |
1318 | } |
1319 | ||
dc9dc135 | 1320 | // Mirrors `visit::walk_generic_args`, but tracks relevant state. |
9fa01778 XL |
1321 | fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { |
1322 | match *generic_args { | |
1323 | GenericArgs::AngleBracketed(ref data) => { | |
ba9703b0 XL |
1324 | self.check_generic_args_before_constraints(data); |
1325 | ||
1326 | for arg in &data.args { | |
1327 | match arg { | |
1328 | AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg), | |
1329 | // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>` | |
1330 | // are allowed to contain nested `impl Trait`. | |
1331 | AngleBracketedArg::Constraint(constraint) => { | |
1332 | self.with_impl_trait(None, |this| { | |
1333 | this.visit_assoc_ty_constraint_from_generic_args(constraint); | |
1334 | }); | |
1335 | } | |
1336 | } | |
1337 | } | |
9fa01778 XL |
1338 | } |
1339 | GenericArgs::Parenthesized(ref data) => { | |
1340 | walk_list!(self, visit_ty, &data.inputs); | |
74b04a01 | 1341 | if let FnRetTy::Ty(ty) = &data.output { |
9fa01778 XL |
1342 | // `-> Foo` syntax is essentially an associated type binding, |
1343 | // so it is also allowed to contain nested `impl Trait`. | |
dfeec247 | 1344 | self.with_impl_trait(None, |this| this.visit_ty(ty)); |
9fa01778 XL |
1345 | } |
1346 | } | |
1347 | } | |
1348 | } | |
1349 | ||
8faf50e0 | 1350 | fn visit_generics(&mut self, generics: &'a Generics) { |
94222f64 | 1351 | let cg_defaults = self.session.features_untracked().unordered_const_ty_params(); |
cdc7bbd5 XL |
1352 | |
1353 | let mut prev_param_default = None; | |
8faf50e0 | 1354 | for param in &generics.params { |
3dfed10e XL |
1355 | match param.kind { |
1356 | GenericParamKind::Lifetime => (), | |
cdc7bbd5 XL |
1357 | GenericParamKind::Type { default: Some(_), .. } |
1358 | | GenericParamKind::Const { default: Some(_), .. } => { | |
1359 | prev_param_default = Some(param.ident.span); | |
3dfed10e XL |
1360 | } |
1361 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { | |
cdc7bbd5 | 1362 | if let Some(span) = prev_param_default { |
3dfed10e XL |
1363 | let mut err = self.err_handler().struct_span_err( |
1364 | span, | |
cdc7bbd5 | 1365 | "generic parameters with a default must be trailing", |
3dfed10e | 1366 | ); |
cdc7bbd5 | 1367 | if matches!(param.kind, GenericParamKind::Const { .. }) && !cg_defaults { |
3dfed10e XL |
1368 | err.note( |
1369 | "using type defaults and const parameters \ | |
1370 | in the same parameter list is currently not permitted", | |
1371 | ); | |
1372 | } | |
1373 | err.emit(); | |
1374 | break; | |
1375 | } | |
ff7c6d11 XL |
1376 | } |
1377 | } | |
32a655c1 | 1378 | } |
9fa01778 | 1379 | |
74b04a01 | 1380 | validate_generic_param_order( |
532ac7d7 XL |
1381 | self.session, |
1382 | self.err_handler(), | |
5869c6ff | 1383 | &generics.params, |
532ac7d7 XL |
1384 | generics.span, |
1385 | ); | |
9fa01778 | 1386 | |
8faf50e0 | 1387 | for predicate in &generics.where_clause.predicates { |
32a655c1 | 1388 | if let WherePredicate::EqPredicate(ref predicate) = *predicate { |
f9f354fc | 1389 | deny_equality_constraints(self, predicate, generics); |
32a655c1 SL |
1390 | } |
1391 | } | |
cdc7bbd5 XL |
1392 | walk_list!(self, visit_generic_param, &generics.params); |
1393 | for predicate in &generics.where_clause.predicates { | |
1394 | match predicate { | |
1395 | WherePredicate::BoundPredicate(bound_pred) => { | |
1396 | // A type binding, eg `for<'c> Foo: Send+Clone+'c` | |
1397 | self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); | |
1398 | ||
1399 | // This is slightly complicated. Our representation for poly-trait-refs contains a single | |
1400 | // binder and thus we only allow a single level of quantification. However, | |
1401 | // the syntax of Rust permits quantification in two places in where clauses, | |
1402 | // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are | |
1403 | // defined, then error. | |
1404 | if !bound_pred.bound_generic_params.is_empty() { | |
1405 | for bound in &bound_pred.bounds { | |
1406 | match bound { | |
1407 | GenericBound::Trait(t, _) => { | |
1408 | if !t.bound_generic_params.is_empty() { | |
1409 | struct_span_err!( | |
1410 | self.err_handler(), | |
1411 | t.span, | |
1412 | E0316, | |
1413 | "nested quantification of lifetimes" | |
1414 | ) | |
1415 | .emit(); | |
1416 | } | |
1417 | } | |
1418 | GenericBound::Outlives(_) => {} | |
1419 | } | |
1420 | } | |
1421 | } | |
1422 | } | |
1423 | _ => {} | |
1424 | } | |
1425 | self.visit_where_predicate(predicate); | |
1426 | } | |
32a655c1 | 1427 | } |
041b39d2 | 1428 | |
94b46f34 | 1429 | fn visit_generic_param(&mut self, param: &'a GenericParam) { |
8faf50e0 XL |
1430 | if let GenericParamKind::Lifetime { .. } = param.kind { |
1431 | self.check_lifetime(param.ident); | |
94b46f34 XL |
1432 | } |
1433 | visit::walk_generic_param(self, param); | |
1434 | } | |
1435 | ||
dfeec247 XL |
1436 | fn visit_param_bound(&mut self, bound: &'a GenericBound) { |
1437 | match bound { | |
1438 | GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => { | |
94222f64 XL |
1439 | if !self.is_tilde_const_allowed { |
1440 | self.err_handler() | |
1441 | .struct_span_err(bound.span(), "`~const` is not allowed here") | |
1442 | .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions") | |
1443 | .emit(); | |
dfeec247 XL |
1444 | } |
1445 | } | |
1446 | ||
1447 | GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { | |
1448 | self.err_handler() | |
94222f64 | 1449 | .span_err(bound.span(), "`~const` and `?` are mutually exclusive"); |
dfeec247 XL |
1450 | } |
1451 | ||
1452 | _ => {} | |
1453 | } | |
1454 | ||
1455 | visit::walk_param_bound(self, bound) | |
1456 | } | |
1457 | ||
041b39d2 | 1458 | fn visit_pat(&mut self, pat: &'a Pat) { |
5869c6ff XL |
1459 | match &pat.kind { |
1460 | PatKind::Lit(expr) => { | |
041b39d2 XL |
1461 | self.check_expr_within_pat(expr, false); |
1462 | } | |
5869c6ff | 1463 | PatKind::Range(start, end, _) => { |
dfeec247 XL |
1464 | if let Some(expr) = start { |
1465 | self.check_expr_within_pat(expr, true); | |
1466 | } | |
1467 | if let Some(expr) = end { | |
1468 | self.check_expr_within_pat(expr, true); | |
1469 | } | |
041b39d2 XL |
1470 | } |
1471 | _ => {} | |
1472 | } | |
1473 | ||
1474 | visit::walk_pat(self, pat) | |
1475 | } | |
0531ce1d | 1476 | |
0531ce1d XL |
1477 | fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { |
1478 | self.check_late_bound_lifetime_defs(&t.bound_generic_params); | |
1479 | visit::walk_poly_trait_ref(self, t, m); | |
1480 | } | |
83c7162d | 1481 | |
e1599b0c | 1482 | fn visit_variant_data(&mut self, s: &'a VariantData) { |
dc9dc135 XL |
1483 | self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) |
1484 | } | |
1485 | ||
dfeec247 XL |
1486 | fn visit_enum_def( |
1487 | &mut self, | |
1488 | enum_definition: &'a EnumDef, | |
1489 | generics: &'a Generics, | |
1490 | item_id: NodeId, | |
1491 | _: Span, | |
1492 | ) { | |
1493 | self.with_banned_assoc_ty_bound(|this| { | |
1494 | visit::walk_enum_def(this, enum_definition, generics, item_id) | |
1495 | }) | |
dc9dc135 XL |
1496 | } |
1497 | ||
74b04a01 XL |
1498 | fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { |
1499 | // Only associated `fn`s can have `self` parameters. | |
1500 | let self_semantic = match fk.ctxt() { | |
1501 | Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes, | |
1502 | _ => SelfSemantic::No, | |
1503 | }; | |
1504 | self.check_fn_decl(fk.decl(), self_semantic); | |
1505 | ||
1506 | self.check_c_varadic_type(fk); | |
1507 | ||
1508 | // Functions cannot both be `const async` | |
1509 | if let Some(FnHeader { | |
1510 | constness: Const::Yes(cspan), | |
1511 | asyncness: Async::Yes { span: aspan, .. }, | |
1512 | .. | |
1513 | }) = fk.header() | |
1514 | { | |
1515 | self.err_handler() | |
ba9703b0 XL |
1516 | .struct_span_err( |
1517 | vec![*cspan, *aspan], | |
1518 | "functions cannot be both `const` and `async`", | |
1519 | ) | |
74b04a01 XL |
1520 | .span_label(*cspan, "`const` because of this") |
1521 | .span_label(*aspan, "`async` because of this") | |
ba9703b0 | 1522 | .span_label(span, "") // Point at the fn header. |
74b04a01 | 1523 | .emit(); |
532ac7d7 | 1524 | } |
60c5eb7d | 1525 | |
94222f64 XL |
1526 | if let FnKind::Fn( |
1527 | _, | |
1528 | _, | |
1529 | FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. }, | |
1530 | _, | |
1531 | _, | |
1532 | ) = fk | |
1533 | { | |
1534 | self.maybe_lint_missing_abi(*sig_span, id); | |
1535 | } | |
1536 | ||
74b04a01 XL |
1537 | // Functions without bodies cannot have patterns. |
1538 | if let FnKind::Fn(ctxt, _, sig, _, None) = fk { | |
5869c6ff | 1539 | Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { |
74b04a01 XL |
1540 | let (code, msg, label) = match ctxt { |
1541 | FnCtxt::Foreign => ( | |
1542 | error_code!(E0130), | |
1543 | "patterns aren't allowed in foreign function declarations", | |
1544 | "pattern not allowed in foreign function", | |
1545 | ), | |
1546 | _ => ( | |
1547 | error_code!(E0642), | |
1548 | "patterns aren't allowed in functions without bodies", | |
1549 | "pattern not allowed in function without body", | |
1550 | ), | |
1551 | }; | |
1552 | if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { | |
5869c6ff XL |
1553 | if let Some(ident) = ident { |
1554 | let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident); | |
1555 | self.lint_buffer.buffer_lint_with_diagnostic( | |
1556 | PATTERNS_IN_FNS_WITHOUT_BODY, | |
1557 | id, | |
1558 | span, | |
1559 | msg, | |
1560 | diag, | |
1561 | ) | |
1562 | } | |
74b04a01 XL |
1563 | } else { |
1564 | self.err_handler() | |
1565 | .struct_span_err(span, msg) | |
1566 | .span_label(span, label) | |
1567 | .code(code) | |
dfeec247 | 1568 | .emit(); |
74b04a01 XL |
1569 | } |
1570 | }); | |
dfeec247 XL |
1571 | } |
1572 | ||
74b04a01 | 1573 | visit::walk_fn(self, fk, span); |
60c5eb7d | 1574 | } |
dfeec247 | 1575 | |
74b04a01 | 1576 | fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { |
94222f64 XL |
1577 | if self.session.contains_name(&item.attrs, sym::no_mangle) { |
1578 | self.check_nomangle_item_asciionly(item.ident, item.span); | |
1579 | } | |
1580 | ||
74b04a01 XL |
1581 | if ctxt == AssocCtxt::Trait || !self.in_trait_impl { |
1582 | self.check_defaultness(item.span, item.kind.defaultness()); | |
1583 | } | |
1584 | ||
1585 | if ctxt == AssocCtxt::Impl { | |
1586 | match &item.kind { | |
1587 | AssocItemKind::Const(_, _, body) => { | |
1588 | self.check_impl_item_provided(item.span, body, "constant", " = <expr>;"); | |
1589 | } | |
5869c6ff | 1590 | AssocItemKind::Fn(box FnKind(_, _, _, body)) => { |
74b04a01 XL |
1591 | self.check_impl_item_provided(item.span, body, "function", " { <body> }"); |
1592 | } | |
5869c6ff | 1593 | AssocItemKind::TyAlias(box TyAliasKind(_, _, bounds, body)) => { |
74b04a01 XL |
1594 | self.check_impl_item_provided(item.span, body, "type", " = <type>;"); |
1595 | self.check_type_no_bounds(bounds, "`impl`s"); | |
1596 | } | |
1597 | _ => {} | |
1598 | } | |
dfeec247 | 1599 | } |
74b04a01 XL |
1600 | |
1601 | if ctxt == AssocCtxt::Trait || self.in_trait_impl { | |
1602 | self.invalid_visibility(&item.vis, None); | |
5869c6ff | 1603 | if let AssocItemKind::Fn(box FnKind(_, sig, _, _)) = &item.kind { |
74b04a01 XL |
1604 | self.check_trait_fn_not_const(sig.header.constness); |
1605 | self.check_trait_fn_not_async(item.span, sig.header.asyncness); | |
1606 | } | |
1607 | } | |
1608 | ||
1609 | if let AssocItemKind::Const(..) = item.kind { | |
1610 | self.check_item_named(item.ident, "const"); | |
1611 | } | |
1612 | ||
94222f64 XL |
1613 | match item.kind { |
1614 | AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty)) | |
1615 | if ctxt == AssocCtxt::Trait => | |
1616 | { | |
1617 | self.visit_vis(&item.vis); | |
1618 | self.visit_ident(item.ident); | |
1619 | walk_list!(self, visit_attribute, &item.attrs); | |
1620 | self.with_tilde_const_allowed(|this| { | |
1621 | this.visit_generics(generics); | |
1622 | walk_list!(this, visit_param_bound, bounds); | |
1623 | }); | |
1624 | walk_list!(self, visit_ty, ty); | |
1625 | } | |
1626 | AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) | |
c295e0f8 XL |
1627 | if self.in_const_trait_impl |
1628 | || ctxt == AssocCtxt::Trait | |
1629 | || matches!(sig.header.constness, Const::Yes(_)) => | |
94222f64 XL |
1630 | { |
1631 | self.visit_vis(&item.vis); | |
1632 | self.visit_ident(item.ident); | |
1633 | self.with_tilde_const_allowed(|this| this.visit_generics(generics)); | |
1634 | let kind = | |
1635 | FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref()); | |
1636 | self.visit_fn(kind, item.span, item.id); | |
1637 | } | |
1638 | _ => self | |
1639 | .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)), | |
1640 | } | |
dfeec247 | 1641 | } |
0531ce1d XL |
1642 | } |
1643 | ||
f9f354fc XL |
1644 | /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems |
1645 | /// like it's setting an associated type, provide an appropriate suggestion. | |
1646 | fn deny_equality_constraints( | |
1647 | this: &mut AstValidator<'_>, | |
1648 | predicate: &WhereEqPredicate, | |
1649 | generics: &Generics, | |
1650 | ) { | |
1651 | let mut err = this.err_handler().struct_span_err( | |
1652 | predicate.span, | |
1653 | "equality constraints are not yet supported in `where` clauses", | |
1654 | ); | |
1655 | err.span_label(predicate.span, "not supported"); | |
1656 | ||
1657 | // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. | |
1658 | if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind { | |
1659 | if let TyKind::Path(None, path) = &qself.ty.kind { | |
1660 | match &path.segments[..] { | |
1661 | [PathSegment { ident, args: None, .. }] => { | |
1662 | for param in &generics.params { | |
1663 | if param.ident == *ident { | |
1664 | let param = ident; | |
1665 | match &full_path.segments[qself.position..] { | |
fc512014 | 1666 | [PathSegment { ident, args, .. }] => { |
f9f354fc XL |
1667 | // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`. |
1668 | let mut assoc_path = full_path.clone(); | |
1669 | // Remove `Bar` from `Foo::Bar`. | |
1670 | assoc_path.segments.pop(); | |
1671 | let len = assoc_path.segments.len() - 1; | |
fc512014 | 1672 | let gen_args = args.as_ref().map(|p| (**p).clone()); |
f9f354fc XL |
1673 | // Build `<Bar = RhsTy>`. |
1674 | let arg = AngleBracketedArg::Constraint(AssocTyConstraint { | |
1675 | id: rustc_ast::node_id::DUMMY_NODE_ID, | |
1676 | ident: *ident, | |
fc512014 | 1677 | gen_args, |
f9f354fc XL |
1678 | kind: AssocTyConstraintKind::Equality { |
1679 | ty: predicate.rhs_ty.clone(), | |
1680 | }, | |
1681 | span: ident.span, | |
1682 | }); | |
1683 | // Add `<Bar = RhsTy>` to `Foo`. | |
1684 | match &mut assoc_path.segments[len].args { | |
1685 | Some(args) => match args.deref_mut() { | |
1686 | GenericArgs::Parenthesized(_) => continue, | |
1687 | GenericArgs::AngleBracketed(args) => { | |
1688 | args.args.push(arg); | |
1689 | } | |
1690 | }, | |
1691 | empty_args => { | |
1692 | *empty_args = AngleBracketedArgs { | |
1693 | span: ident.span, | |
1694 | args: vec![arg], | |
1695 | } | |
1696 | .into(); | |
1697 | } | |
1698 | } | |
1699 | err.span_suggestion_verbose( | |
1700 | predicate.span, | |
1701 | &format!( | |
1702 | "if `{}` is an associated type you're trying to set, \ | |
1703 | use the associated type binding syntax", | |
1704 | ident | |
1705 | ), | |
1706 | format!( | |
1707 | "{}: {}", | |
1708 | param, | |
1709 | pprust::path_to_string(&assoc_path) | |
1710 | ), | |
1711 | Applicability::MaybeIncorrect, | |
1712 | ); | |
1713 | } | |
1714 | _ => {} | |
1715 | }; | |
1716 | } | |
1717 | } | |
1718 | } | |
1719 | _ => {} | |
1720 | } | |
1721 | } | |
1722 | } | |
1723 | err.note( | |
1724 | "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information", | |
1725 | ); | |
1726 | err.emit(); | |
1727 | } | |
1728 | ||
dfeec247 | 1729 | pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool { |
9fa01778 XL |
1730 | let mut validator = AstValidator { |
1731 | session, | |
74b04a01 XL |
1732 | extern_mod: None, |
1733 | in_trait_impl: false, | |
94222f64 | 1734 | in_const_trait_impl: false, |
9fa01778 | 1735 | has_proc_macro_decls: false, |
9fa01778 | 1736 | outer_impl_trait: None, |
94222f64 | 1737 | is_tilde_const_allowed: false, |
9fa01778 | 1738 | is_impl_trait_banned: false, |
dc9dc135 | 1739 | is_assoc_ty_bound_banned: false, |
94222f64 | 1740 | is_let_allowed: false, |
e74abb32 | 1741 | lint_buffer: lints, |
9fa01778 XL |
1742 | }; |
1743 | visit::walk_crate(&mut validator, krate); | |
1744 | ||
416331ca | 1745 | validator.has_proc_macro_decls |
3157f602 | 1746 | } |