]>
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 | ||
9fa01778 | 9 | use std::mem; |
3157f602 XL |
10 | use rustc::lint; |
11 | use rustc::session::Session; | |
9fa01778 | 12 | use rustc_data_structures::fx::FxHashMap; |
60c5eb7d | 13 | use rustc_parse::validate_attr; |
3157f602 | 14 | use syntax::ast::*; |
5bcae85e | 15 | use syntax::attr; |
e74abb32 | 16 | use syntax::expand::is_proc_macro_attr; |
60c5eb7d | 17 | use syntax::print::pprust; |
b7449926 | 18 | use syntax::source_map::Spanned; |
dc9dc135 | 19 | use syntax::symbol::{kw, sym}; |
3157f602 | 20 | use syntax::visit::{self, Visitor}; |
9fa01778 | 21 | use syntax::{span_err, struct_span_err, walk_list}; |
60c5eb7d | 22 | use syntax_pos::Span; |
48663c56 | 23 | use errors::{Applicability, FatalError}; |
9fa01778 | 24 | |
60c5eb7d | 25 | use rustc_error_codes::*; |
3157f602 XL |
26 | |
27 | struct AstValidator<'a> { | |
28 | session: &'a Session, | |
9fa01778 | 29 | has_proc_macro_decls: bool, |
9fa01778 | 30 | |
48663c56 XL |
31 | /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`. |
32 | /// Nested `impl Trait` _is_ allowed in associated type position, | |
dc9dc135 | 33 | /// e.g., `impl Iterator<Item = impl Debug>`. |
60c5eb7d | 34 | outer_impl_trait: Option<Span>, |
9fa01778 | 35 | |
48663c56 XL |
36 | /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` |
37 | /// or `Foo::Bar<impl Trait>` | |
9fa01778 XL |
38 | is_impl_trait_banned: bool, |
39 | ||
dc9dc135 XL |
40 | /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in |
41 | /// certain positions. | |
42 | is_assoc_ty_bound_banned: bool, | |
43 | ||
e74abb32 | 44 | lint_buffer: &'a mut lint::LintBuffer, |
3157f602 XL |
45 | } |
46 | ||
47 | impl<'a> AstValidator<'a> { | |
9fa01778 XL |
48 | fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { |
49 | let old = mem::replace(&mut self.is_impl_trait_banned, true); | |
50 | f(self); | |
51 | self.is_impl_trait_banned = old; | |
52 | } | |
53 | ||
dc9dc135 XL |
54 | fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) { |
55 | let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true); | |
56 | f(self); | |
57 | self.is_assoc_ty_bound_banned = old; | |
58 | } | |
59 | ||
60c5eb7d | 60 | fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { |
9fa01778 XL |
61 | let old = mem::replace(&mut self.outer_impl_trait, outer); |
62 | f(self); | |
63 | self.outer_impl_trait = old; | |
64 | } | |
65 | ||
dc9dc135 XL |
66 | fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { |
67 | match constraint.kind { | |
60c5eb7d | 68 | AssocTyConstraintKind::Equality { .. } => {} |
dc9dc135 XL |
69 | AssocTyConstraintKind::Bound { .. } => { |
70 | if self.is_assoc_ty_bound_banned { | |
71 | self.err_handler().span_err(constraint.span, | |
72 | "associated type bounds are not allowed within structs, enums, or unions" | |
73 | ); | |
74 | } | |
75 | } | |
9fa01778 | 76 | } |
dc9dc135 | 77 | self.visit_assoc_ty_constraint(constraint); |
9fa01778 XL |
78 | } |
79 | ||
dc9dc135 | 80 | // Mirrors `visit::walk_ty`, but tracks relevant state. |
9fa01778 | 81 | fn walk_ty(&mut self, t: &'a Ty) { |
e74abb32 | 82 | match t.kind { |
9fa01778 | 83 | TyKind::ImplTrait(..) => { |
60c5eb7d | 84 | self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) |
9fa01778 XL |
85 | } |
86 | TyKind::Path(ref qself, ref path) => { | |
87 | // We allow these: | |
88 | // - `Option<impl Trait>` | |
89 | // - `option::Option<impl Trait>` | |
90 | // - `option::Option<T>::Foo<impl Trait> | |
91 | // | |
92 | // But not these: | |
93 | // - `<impl Trait>::Foo` | |
94 | // - `option::Option<impl Trait>::Foo`. | |
95 | // | |
96 | // To implement this, we disallow `impl Trait` from `qself` | |
97 | // (for cases like `<impl Trait>::Foo>`) | |
98 | // but we allow `impl Trait` in `GenericArgs` | |
99 | // iff there are no more PathSegments. | |
100 | if let Some(ref qself) = *qself { | |
101 | // `impl Trait` in `qself` is always illegal | |
102 | self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); | |
103 | } | |
104 | ||
105 | // Note that there should be a call to visit_path here, | |
106 | // so if any logic is added to process `Path`s a call to it should be | |
107 | // added both in visit_path and here. This code mirrors visit::walk_path. | |
108 | for (i, segment) in path.segments.iter().enumerate() { | |
109 | // Allow `impl Trait` iff we're on the final path segment | |
110 | if i == path.segments.len() - 1 { | |
111 | self.visit_path_segment(path.span, segment); | |
112 | } else { | |
113 | self.with_banned_impl_trait(|this| { | |
114 | this.visit_path_segment(path.span, segment) | |
115 | }); | |
116 | } | |
117 | } | |
118 | } | |
119 | _ => visit::walk_ty(self, t), | |
120 | } | |
121 | } | |
122 | ||
3157f602 | 123 | fn err_handler(&self) -> &errors::Handler { |
b7449926 | 124 | &self.session.diagnostic() |
3157f602 XL |
125 | } |
126 | ||
83c7162d | 127 | fn check_lifetime(&self, ident: Ident) { |
dc9dc135 XL |
128 | let valid_names = [kw::UnderscoreLifetime, |
129 | kw::StaticLifetime, | |
130 | kw::Invalid]; | |
94b46f34 | 131 | if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { |
83c7162d | 132 | self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); |
ff7c6d11 XL |
133 | } |
134 | } | |
135 | ||
83c7162d | 136 | fn check_label(&self, ident: Ident) { |
94b46f34 | 137 | if ident.without_first_quote().is_reserved() { |
83c7162d XL |
138 | self.err_handler() |
139 | .span_err(ident.span, &format!("invalid label name `{}`", ident.name)); | |
3157f602 | 140 | } |
3157f602 XL |
141 | } |
142 | ||
0531ce1d | 143 | fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { |
8faf50e0 XL |
144 | if let VisibilityKind::Inherited = vis.node { |
145 | return | |
146 | } | |
147 | ||
148 | let mut err = struct_span_err!(self.session, | |
149 | vis.span, | |
150 | E0449, | |
151 | "unnecessary visibility qualifier"); | |
152 | if vis.node.is_pub() { | |
153 | err.span_label(vis.span, "`pub` not permitted here because it's implied"); | |
3157f602 | 154 | } |
8faf50e0 XL |
155 | if let Some(note) = note { |
156 | err.note(note); | |
157 | } | |
158 | err.emit(); | |
3157f602 | 159 | } |
5bcae85e | 160 | |
60c5eb7d XL |
161 | fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) { |
162 | for Param { pat, .. } in &decl.inputs { | |
163 | match pat.kind { | |
5bcae85e SL |
164 | PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) | |
165 | PatKind::Wild => {} | |
abe05a73 | 166 | PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), _, None) => |
60c5eb7d XL |
167 | report_err(pat.span, true), |
168 | _ => report_err(pat.span, false), | |
5bcae85e SL |
169 | } |
170 | } | |
171 | } | |
9e0c209e | 172 | |
dc9dc135 | 173 | fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) { |
8faf50e0 | 174 | if asyncness.is_async() { |
60c5eb7d XL |
175 | struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`") |
176 | .note("`async` trait functions are not currently supported") | |
177 | .note("consider using the `async-trait` crate: \ | |
178 | https://crates.io/crates/async-trait") | |
179 | .emit(); | |
8faf50e0 XL |
180 | } |
181 | } | |
182 | ||
9e0c209e | 183 | fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) { |
b7449926 XL |
184 | if constness.node == Constness::Const { |
185 | struct_span_err!(self.session, constness.span, E0379, | |
186 | "trait fns cannot be declared const") | |
187 | .span_label(constness.span, "trait fns cannot be const") | |
188 | .emit(); | |
9e0c209e SL |
189 | } |
190 | } | |
476ff2be | 191 | |
8faf50e0 | 192 | fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) { |
476ff2be | 193 | for bound in bounds { |
8faf50e0 | 194 | if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound { |
476ff2be | 195 | let mut err = self.err_handler().struct_span_err(poly.span, |
b7449926 | 196 | &format!("`?Trait` is not permitted in {}", where_)); |
476ff2be | 197 | if is_trait { |
e74abb32 XL |
198 | let path_str = pprust::path_to_string(&poly.trait_ref.path); |
199 | err.note(&format!("traits are `?{}` by default", path_str)); | |
476ff2be SL |
200 | } |
201 | err.emit(); | |
202 | } | |
203 | } | |
204 | } | |
041b39d2 | 205 | |
9fa01778 XL |
206 | /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`, |
207 | /// or paths for ranges. | |
208 | // | |
209 | // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions? | |
210 | // That means making this work: | |
211 | // | |
212 | // ```rust,ignore (FIXME) | |
213 | // struct S; | |
214 | // macro_rules! m { | |
215 | // ($a:expr) => { | |
216 | // let $a = S; | |
217 | // } | |
218 | // } | |
219 | // m!(S); | |
220 | // ``` | |
041b39d2 | 221 | fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { |
e74abb32 | 222 | match expr.kind { |
416331ca | 223 | ExprKind::Lit(..) | ExprKind::Err => {} |
041b39d2 XL |
224 | ExprKind::Path(..) if allow_paths => {} |
225 | ExprKind::Unary(UnOp::Neg, ref inner) | |
e74abb32 | 226 | if match inner.kind { ExprKind::Lit(_) => true, _ => false } => {} |
041b39d2 XL |
227 | _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \ |
228 | in patterns") | |
229 | } | |
230 | } | |
0531ce1d | 231 | |
8faf50e0 XL |
232 | fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { |
233 | // Check only lifetime parameters are present and that the lifetime | |
234 | // parameters that are present have no bounds. | |
235 | let non_lt_param_spans: Vec<_> = params.iter().filter_map(|param| match param.kind { | |
b7449926 XL |
236 | GenericParamKind::Lifetime { .. } => { |
237 | if !param.bounds.is_empty() { | |
238 | let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); | |
239 | self.err_handler() | |
240 | .span_err(spans, "lifetime bounds cannot be used in this context"); | |
0531ce1d | 241 | } |
b7449926 XL |
242 | None |
243 | } | |
244 | _ => Some(param.ident.span), | |
245 | }).collect(); | |
8faf50e0 XL |
246 | if !non_lt_param_spans.is_empty() { |
247 | self.err_handler().span_err(non_lt_param_spans, | |
248 | "only lifetime parameters can be used in this context"); | |
0531ce1d XL |
249 | } |
250 | } | |
b7449926 | 251 | |
dc9dc135 XL |
252 | fn check_fn_decl(&self, fn_decl: &FnDecl) { |
253 | fn_decl | |
254 | .inputs | |
255 | .iter() | |
256 | .flat_map(|i| i.attrs.as_ref()) | |
257 | .filter(|attr| { | |
258 | let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn]; | |
60c5eb7d | 259 | !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr) |
dc9dc135 | 260 | }) |
60c5eb7d | 261 | .for_each(|attr| if attr.is_doc_comment() { |
dc9dc135 XL |
262 | let mut err = self.err_handler().struct_span_err( |
263 | attr.span, | |
264 | "documentation comments cannot be applied to function parameters" | |
b7449926 | 265 | ); |
dc9dc135 XL |
266 | err.span_label(attr.span, "doc comments are not allowed here"); |
267 | err.emit(); | |
b7449926 | 268 | } |
dc9dc135 XL |
269 | else { |
270 | self.err_handler().span_err(attr.span, "allow, cfg, cfg_attr, deny, \ | |
271 | forbid, and warn are the only allowed built-in attributes in function parameters") | |
272 | }); | |
b7449926 | 273 | } |
9fa01778 XL |
274 | } |
275 | ||
276 | enum GenericPosition { | |
277 | Param, | |
278 | Arg, | |
279 | } | |
b7449926 | 280 | |
9fa01778 | 281 | fn validate_generics_order<'a>( |
532ac7d7 | 282 | sess: &Session, |
9fa01778 | 283 | handler: &errors::Handler, |
532ac7d7 XL |
284 | generics: impl Iterator< |
285 | Item = ( | |
286 | ParamKindOrd, | |
287 | Option<&'a [GenericBound]>, | |
288 | Span, | |
289 | Option<String> | |
290 | ), | |
291 | >, | |
9fa01778 XL |
292 | pos: GenericPosition, |
293 | span: Span, | |
294 | ) { | |
295 | let mut max_param: Option<ParamKindOrd> = None; | |
296 | let mut out_of_order = FxHashMap::default(); | |
297 | let mut param_idents = vec![]; | |
48663c56 XL |
298 | let mut found_type = false; |
299 | let mut found_const = false; | |
9fa01778 | 300 | |
532ac7d7 | 301 | for (kind, bounds, span, ident) in generics { |
9fa01778 | 302 | if let Some(ident) = ident { |
532ac7d7 | 303 | param_idents.push((kind, bounds, param_idents.len(), ident)); |
9fa01778 XL |
304 | } |
305 | let max_param = &mut max_param; | |
306 | match max_param { | |
307 | Some(max_param) if *max_param > kind => { | |
308 | let entry = out_of_order.entry(kind).or_insert((*max_param, vec![])); | |
309 | entry.1.push(span); | |
310 | } | |
311 | Some(_) | None => *max_param = Some(kind), | |
312 | }; | |
48663c56 XL |
313 | match kind { |
314 | ParamKindOrd::Type => found_type = true, | |
315 | ParamKindOrd::Const => found_const = true, | |
316 | _ => {} | |
317 | } | |
9fa01778 XL |
318 | } |
319 | ||
320 | let mut ordered_params = "<".to_string(); | |
321 | if !out_of_order.is_empty() { | |
532ac7d7 | 322 | param_idents.sort_by_key(|&(po, _, i, _)| (po, i)); |
9fa01778 | 323 | let mut first = true; |
532ac7d7 | 324 | for (_, bounds, _, ident) in param_idents { |
9fa01778 XL |
325 | if !first { |
326 | ordered_params += ", "; | |
327 | } | |
328 | ordered_params += &ident; | |
532ac7d7 XL |
329 | if let Some(bounds) = bounds { |
330 | if !bounds.is_empty() { | |
331 | ordered_params += ": "; | |
332 | ordered_params += &pprust::bounds_to_string(&bounds); | |
333 | } | |
334 | } | |
9fa01778 XL |
335 | first = false; |
336 | } | |
337 | } | |
338 | ordered_params += ">"; | |
339 | ||
340 | let pos_str = match pos { | |
341 | GenericPosition::Param => "parameter", | |
342 | GenericPosition::Arg => "argument", | |
343 | }; | |
344 | ||
48663c56 XL |
345 | for (param_ord, (max_param, spans)) in &out_of_order { |
346 | let mut err = handler.struct_span_err(spans.clone(), | |
9fa01778 XL |
347 | &format!( |
348 | "{} {pos}s must be declared prior to {} {pos}s", | |
349 | param_ord, | |
350 | max_param, | |
351 | pos = pos_str, | |
352 | )); | |
353 | if let GenericPosition::Param = pos { | |
354 | err.span_suggestion( | |
355 | span, | |
532ac7d7 XL |
356 | &format!( |
357 | "reorder the {}s: lifetimes, then types{}", | |
358 | pos_str, | |
359 | if sess.features_untracked().const_generics { ", then consts" } else { "" }, | |
360 | ), | |
9fa01778 XL |
361 | ordered_params.clone(), |
362 | Applicability::MachineApplicable, | |
363 | ); | |
364 | } | |
365 | err.emit(); | |
366 | } | |
48663c56 XL |
367 | |
368 | // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs | |
369 | // if we don't. Const parameters and type parameters can currently conflict if they | |
370 | // are out-of-order. | |
371 | if !out_of_order.is_empty() && found_type && found_const { | |
372 | FatalError.raise(); | |
373 | } | |
3157f602 XL |
374 | } |
375 | ||
476ff2be | 376 | impl<'a> Visitor<'a> for AstValidator<'a> { |
60c5eb7d XL |
377 | fn visit_attribute(&mut self, attr: &Attribute) { |
378 | validate_attr::check_meta(&self.session.parse_sess, attr); | |
379 | } | |
380 | ||
476ff2be | 381 | fn visit_expr(&mut self, expr: &'a Expr) { |
e74abb32 | 382 | match &expr.kind { |
dc9dc135 XL |
383 | ExprKind::Closure(_, _, _, fn_decl, _, _) => { |
384 | self.check_fn_decl(fn_decl); | |
385 | } | |
2c00a5a8 XL |
386 | ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => { |
387 | span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target"); | |
3157f602 XL |
388 | } |
389 | _ => {} | |
390 | } | |
391 | ||
dc9dc135 | 392 | visit::walk_expr(self, expr); |
3157f602 XL |
393 | } |
394 | ||
476ff2be | 395 | fn visit_ty(&mut self, ty: &'a Ty) { |
e74abb32 | 396 | match ty.kind { |
5bcae85e | 397 | TyKind::BareFn(ref bfty) => { |
dc9dc135 | 398 | self.check_fn_decl(&bfty.decl); |
e74abb32 | 399 | Self::check_decl_no_pat(&bfty.decl, |span, _| { |
abe05a73 XL |
400 | struct_span_err!(self.session, span, E0561, |
401 | "patterns aren't allowed in function pointer types").emit(); | |
5bcae85e | 402 | }); |
0531ce1d | 403 | self.check_late_bound_lifetime_defs(&bfty.generic_params); |
5bcae85e | 404 | } |
abe05a73 | 405 | TyKind::TraitObject(ref bounds, ..) => { |
32a655c1 SL |
406 | let mut any_lifetime_bounds = false; |
407 | for bound in bounds { | |
8faf50e0 | 408 | if let GenericBound::Outlives(ref lifetime) = *bound { |
32a655c1 | 409 | if any_lifetime_bounds { |
83c7162d | 410 | span_err!(self.session, lifetime.ident.span, E0226, |
32a655c1 SL |
411 | "only a single explicit lifetime bound is permitted"); |
412 | break; | |
413 | } | |
414 | any_lifetime_bounds = true; | |
415 | } | |
416 | } | |
476ff2be SL |
417 | self.no_questions_in_bounds(bounds, "trait object types", false); |
418 | } | |
8faf50e0 | 419 | TyKind::ImplTrait(_, ref bounds) => { |
9fa01778 | 420 | if self.is_impl_trait_banned { |
60c5eb7d XL |
421 | struct_span_err!( |
422 | self.session, ty.span, E0667, | |
423 | "`impl Trait` is not allowed in path parameters" | |
424 | ) | |
425 | .emit(); | |
9fa01778 XL |
426 | } |
427 | ||
60c5eb7d XL |
428 | if let Some(outer_impl_trait_sp) = self.outer_impl_trait { |
429 | struct_span_err!( | |
430 | self.session, ty.span, E0666, | |
431 | "nested `impl Trait` is not allowed" | |
432 | ) | |
433 | .span_label(outer_impl_trait_sp, "outer `impl Trait`") | |
434 | .span_label(ty.span, "nested `impl Trait` here") | |
435 | .emit(); | |
9fa01778 XL |
436 | } |
437 | ||
32a655c1 | 438 | if !bounds.iter() |
8faf50e0 | 439 | .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { |
32a655c1 SL |
440 | self.err_handler().span_err(ty.span, "at least one trait must be specified"); |
441 | } | |
9fa01778 | 442 | |
60c5eb7d | 443 | self.walk_ty(ty); |
9fa01778 | 444 | return; |
32a655c1 | 445 | } |
5bcae85e SL |
446 | _ => {} |
447 | } | |
448 | ||
9fa01778 | 449 | self.walk_ty(ty) |
5bcae85e SL |
450 | } |
451 | ||
2c00a5a8 | 452 | fn visit_label(&mut self, label: &'a Label) { |
83c7162d | 453 | self.check_label(label.ident); |
2c00a5a8 XL |
454 | visit::walk_label(self, label); |
455 | } | |
456 | ||
ff7c6d11 | 457 | fn visit_lifetime(&mut self, lifetime: &'a Lifetime) { |
83c7162d | 458 | self.check_lifetime(lifetime.ident); |
ff7c6d11 | 459 | visit::walk_lifetime(self, lifetime); |
3157f602 XL |
460 | } |
461 | ||
476ff2be | 462 | fn visit_item(&mut self, item: &'a Item) { |
9fa01778 XL |
463 | if item.attrs.iter().any(|attr| is_proc_macro_attr(attr) ) { |
464 | self.has_proc_macro_decls = true; | |
465 | } | |
466 | ||
e74abb32 | 467 | match item.kind { |
2c00a5a8 | 468 | ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { |
0531ce1d | 469 | self.invalid_visibility(&item.vis, None); |
e74abb32 | 470 | if let TyKind::Err = ty.kind { |
2c00a5a8 XL |
471 | self.err_handler() |
472 | .struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax") | |
473 | .help("use `auto trait Trait {}` instead").emit(); | |
474 | } | |
475 | if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative { | |
476 | span_err!(self.session, item.span, E0198, "negative impls cannot be unsafe"); | |
477 | } | |
3157f602 | 478 | for impl_item in impl_items { |
0531ce1d | 479 | self.invalid_visibility(&impl_item.vis, None); |
e74abb32 | 480 | if let ImplItemKind::Method(ref sig, _) = impl_item.kind { |
8faf50e0 | 481 | self.check_trait_fn_not_const(sig.header.constness); |
dc9dc135 | 482 | self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node); |
9e0c209e | 483 | } |
3157f602 XL |
484 | } |
485 | } | |
2c00a5a8 | 486 | ItemKind::Impl(unsafety, polarity, defaultness, _, None, _, _) => { |
5bcae85e | 487 | self.invalid_visibility(&item.vis, |
5bcae85e | 488 | Some("place qualifiers on individual impl items instead")); |
2c00a5a8 XL |
489 | if unsafety == Unsafety::Unsafe { |
490 | span_err!(self.session, item.span, E0197, "inherent impls cannot be unsafe"); | |
491 | } | |
492 | if polarity == ImplPolarity::Negative { | |
493 | self.err_handler().span_err(item.span, "inherent impls cannot be negative"); | |
494 | } | |
495 | if defaultness == Defaultness::Default { | |
83c7162d XL |
496 | self.err_handler() |
497 | .struct_span_err(item.span, "inherent impls cannot be default") | |
498 | .note("only trait implementations may be annotated with default").emit(); | |
2c00a5a8 | 499 | } |
3157f602 | 500 | } |
60c5eb7d XL |
501 | ItemKind::Fn(ref sig, ref generics, _) => { |
502 | self.visit_fn_header(&sig.header); | |
503 | self.check_fn_decl(&sig.decl); | |
9fa01778 XL |
504 | // We currently do not permit const generics in `const fn`, as |
505 | // this is tantamount to allowing compile-time dependent typing. | |
60c5eb7d | 506 | if sig.header.constness.node == Constness::Const { |
9fa01778 XL |
507 | // Look for const generics and error if we find any. |
508 | for param in &generics.params { | |
509 | match param.kind { | |
510 | GenericParamKind::Const { .. } => { | |
511 | self.err_handler() | |
512 | .struct_span_err( | |
513 | item.span, | |
514 | "const parameters are not permitted in `const fn`", | |
515 | ) | |
516 | .emit(); | |
517 | } | |
518 | _ => {} | |
519 | } | |
520 | } | |
521 | } | |
522 | } | |
3157f602 | 523 | ItemKind::ForeignMod(..) => { |
0531ce1d XL |
524 | self.invalid_visibility( |
525 | &item.vis, | |
526 | Some("place qualifiers on individual foreign items instead"), | |
527 | ); | |
3157f602 XL |
528 | } |
529 | ItemKind::Enum(ref def, _) => { | |
530 | for variant in &def.variants { | |
60c5eb7d | 531 | self.invalid_visibility(&variant.vis, None); |
e1599b0c | 532 | for field in variant.data.fields() { |
0531ce1d | 533 | self.invalid_visibility(&field.vis, None); |
3157f602 XL |
534 | } |
535 | } | |
536 | } | |
abe05a73 XL |
537 | ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => { |
538 | if is_auto == IsAuto::Yes { | |
539 | // Auto traits cannot have generics, super traits nor contain items. | |
8faf50e0 | 540 | if !generics.params.is_empty() { |
2c00a5a8 | 541 | struct_span_err!(self.session, item.span, E0567, |
dc9dc135 XL |
542 | "auto traits cannot have generic parameters" |
543 | ).emit(); | |
abe05a73 XL |
544 | } |
545 | if !bounds.is_empty() { | |
2c00a5a8 | 546 | struct_span_err!(self.session, item.span, E0568, |
dc9dc135 XL |
547 | "auto traits cannot have super traits" |
548 | ).emit(); | |
abe05a73 XL |
549 | } |
550 | if !trait_items.is_empty() { | |
2c00a5a8 | 551 | struct_span_err!(self.session, item.span, E0380, |
dc9dc135 XL |
552 | "auto traits cannot have methods or associated items" |
553 | ).emit(); | |
abe05a73 XL |
554 | } |
555 | } | |
476ff2be | 556 | self.no_questions_in_bounds(bounds, "supertraits", true); |
9e0c209e | 557 | for trait_item in trait_items { |
e74abb32 | 558 | if let TraitItemKind::Method(ref sig, ref block) = trait_item.kind { |
dc9dc135 XL |
559 | self.check_fn_decl(&sig.decl); |
560 | self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node); | |
8faf50e0 | 561 | self.check_trait_fn_not_const(sig.header.constness); |
c30ab7b3 | 562 | if block.is_none() { |
e74abb32 | 563 | Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { |
abe05a73 | 564 | if mut_ident { |
e74abb32 | 565 | self.lint_buffer.buffer_lint( |
abe05a73 XL |
566 | lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY, |
567 | trait_item.id, span, | |
568 | "patterns aren't allowed in methods without bodies"); | |
569 | } else { | |
570 | struct_span_err!(self.session, span, E0642, | |
571 | "patterns aren't allowed in methods without bodies").emit(); | |
572 | } | |
c30ab7b3 SL |
573 | }); |
574 | } | |
9e0c209e SL |
575 | } |
576 | } | |
577 | } | |
5bcae85e | 578 | ItemKind::Mod(_) => { |
0731742a | 579 | // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). |
48663c56 | 580 | attr::first_attr_value_str_by_name(&item.attrs, sym::path); |
5bcae85e | 581 | } |
9e0c209e | 582 | ItemKind::Union(ref vdata, _) => { |
532ac7d7 | 583 | if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata { |
9e0c209e SL |
584 | self.err_handler().span_err(item.span, |
585 | "tuple and unit unions are not permitted"); | |
586 | } | |
b7449926 | 587 | if vdata.fields().is_empty() { |
9e0c209e SL |
588 | self.err_handler().span_err(item.span, |
589 | "unions cannot have zero fields"); | |
590 | } | |
591 | } | |
3157f602 XL |
592 | _ => {} |
593 | } | |
594 | ||
595 | visit::walk_item(self, item) | |
596 | } | |
597 | ||
476ff2be | 598 | fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { |
e74abb32 | 599 | match fi.kind { |
5bcae85e | 600 | ForeignItemKind::Fn(ref decl, _) => { |
dc9dc135 | 601 | self.check_fn_decl(decl); |
e74abb32 | 602 | Self::check_decl_no_pat(decl, |span, _| { |
abe05a73 XL |
603 | struct_span_err!(self.session, span, E0130, |
604 | "patterns aren't allowed in foreign function declarations") | |
605 | .span_label(span, "pattern not allowed in foreign function").emit(); | |
5bcae85e | 606 | }); |
3157f602 | 607 | } |
83c7162d | 608 | ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} |
3157f602 XL |
609 | } |
610 | ||
5bcae85e | 611 | visit::walk_foreign_item(self, fi) |
3157f602 XL |
612 | } |
613 | ||
dc9dc135 | 614 | // Mirrors `visit::walk_generic_args`, but tracks relevant state. |
9fa01778 XL |
615 | fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { |
616 | match *generic_args { | |
617 | GenericArgs::AngleBracketed(ref data) => { | |
618 | walk_list!(self, visit_generic_arg, &data.args); | |
532ac7d7 XL |
619 | validate_generics_order( |
620 | self.session, | |
621 | self.err_handler(), | |
622 | data.args.iter().map(|arg| { | |
623 | (match arg { | |
624 | GenericArg::Lifetime(..) => ParamKindOrd::Lifetime, | |
625 | GenericArg::Type(..) => ParamKindOrd::Type, | |
626 | GenericArg::Const(..) => ParamKindOrd::Const, | |
627 | }, None, arg.span(), None) | |
628 | }), | |
629 | GenericPosition::Arg, | |
630 | generic_args.span(), | |
631 | ); | |
9fa01778 | 632 | |
dc9dc135 | 633 | // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>` |
9fa01778 XL |
634 | // are allowed to contain nested `impl Trait`. |
635 | self.with_impl_trait(None, |this| { | |
dc9dc135 XL |
636 | walk_list!(this, visit_assoc_ty_constraint_from_generic_args, |
637 | &data.constraints); | |
9fa01778 XL |
638 | }); |
639 | } | |
640 | GenericArgs::Parenthesized(ref data) => { | |
641 | walk_list!(self, visit_ty, &data.inputs); | |
642 | if let Some(ref type_) = data.output { | |
643 | // `-> Foo` syntax is essentially an associated type binding, | |
644 | // so it is also allowed to contain nested `impl Trait`. | |
60c5eb7d | 645 | self.with_impl_trait(None, |this| this.visit_ty(type_)); |
9fa01778 XL |
646 | } |
647 | } | |
648 | } | |
649 | } | |
650 | ||
8faf50e0 | 651 | fn visit_generics(&mut self, generics: &'a Generics) { |
9fa01778 | 652 | let mut prev_ty_default = None; |
8faf50e0 | 653 | for param in &generics.params { |
9fa01778 XL |
654 | if let GenericParamKind::Type { ref default, .. } = param.kind { |
655 | if default.is_some() { | |
656 | prev_ty_default = Some(param.ident.span); | |
657 | } else if let Some(span) = prev_ty_default { | |
ff7c6d11 | 658 | self.err_handler() |
9fa01778 XL |
659 | .span_err(span, "type parameters with a default must be trailing"); |
660 | break; | |
ff7c6d11 XL |
661 | } |
662 | } | |
32a655c1 | 663 | } |
9fa01778 | 664 | |
532ac7d7 XL |
665 | validate_generics_order( |
666 | self.session, | |
667 | self.err_handler(), | |
668 | generics.params.iter().map(|param| { | |
669 | let ident = Some(param.ident.to_string()); | |
670 | let (kind, ident) = match ¶m.kind { | |
671 | GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident), | |
672 | GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident), | |
673 | GenericParamKind::Const { ref ty } => { | |
674 | let ty = pprust::ty_to_string(ty); | |
675 | (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty))) | |
676 | } | |
677 | }; | |
678 | (kind, Some(&*param.bounds), param.ident.span, ident) | |
679 | }), | |
680 | GenericPosition::Param, | |
681 | generics.span, | |
682 | ); | |
9fa01778 | 683 | |
8faf50e0 | 684 | for predicate in &generics.where_clause.predicates { |
32a655c1 | 685 | if let WherePredicate::EqPredicate(ref predicate) = *predicate { |
0731742a XL |
686 | self.err_handler() |
687 | .span_err(predicate.span, "equality constraints are not yet \ | |
688 | supported in where clauses (see #20041)"); | |
32a655c1 SL |
689 | } |
690 | } | |
9fa01778 | 691 | |
8faf50e0 | 692 | visit::walk_generics(self, generics) |
32a655c1 | 693 | } |
041b39d2 | 694 | |
94b46f34 | 695 | fn visit_generic_param(&mut self, param: &'a GenericParam) { |
8faf50e0 XL |
696 | if let GenericParamKind::Lifetime { .. } = param.kind { |
697 | self.check_lifetime(param.ident); | |
94b46f34 XL |
698 | } |
699 | visit::walk_generic_param(self, param); | |
700 | } | |
701 | ||
041b39d2 | 702 | fn visit_pat(&mut self, pat: &'a Pat) { |
e74abb32 | 703 | match pat.kind { |
041b39d2 XL |
704 | PatKind::Lit(ref expr) => { |
705 | self.check_expr_within_pat(expr, false); | |
706 | } | |
707 | PatKind::Range(ref start, ref end, _) => { | |
708 | self.check_expr_within_pat(start, true); | |
709 | self.check_expr_within_pat(end, true); | |
710 | } | |
711 | _ => {} | |
712 | } | |
713 | ||
714 | visit::walk_pat(self, pat) | |
715 | } | |
0531ce1d XL |
716 | |
717 | fn visit_where_predicate(&mut self, p: &'a WherePredicate) { | |
718 | if let &WherePredicate::BoundPredicate(ref bound_predicate) = p { | |
719 | // A type binding, eg `for<'c> Foo: Send+Clone+'c` | |
720 | self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params); | |
721 | } | |
722 | visit::walk_where_predicate(self, p); | |
723 | } | |
724 | ||
725 | fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { | |
726 | self.check_late_bound_lifetime_defs(&t.bound_generic_params); | |
727 | visit::walk_poly_trait_ref(self, t, m); | |
728 | } | |
83c7162d | 729 | |
e1599b0c | 730 | fn visit_variant_data(&mut self, s: &'a VariantData) { |
dc9dc135 XL |
731 | self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) |
732 | } | |
733 | ||
734 | fn visit_enum_def(&mut self, enum_definition: &'a EnumDef, | |
735 | generics: &'a Generics, item_id: NodeId, _: Span) { | |
736 | self.with_banned_assoc_ty_bound( | |
737 | |this| visit::walk_enum_def(this, enum_definition, generics, item_id)) | |
738 | } | |
739 | ||
dc9dc135 | 740 | fn visit_impl_item(&mut self, ii: &'a ImplItem) { |
e74abb32 XL |
741 | if let ImplItemKind::Method(ref sig, _) = ii.kind { |
742 | self.check_fn_decl(&sig.decl); | |
532ac7d7 | 743 | } |
dc9dc135 | 744 | visit::walk_impl_item(self, ii); |
532ac7d7 | 745 | } |
60c5eb7d XL |
746 | |
747 | fn visit_trait_item(&mut self, ti: &'a TraitItem) { | |
748 | self.invalid_visibility(&ti.vis, None); | |
749 | visit::walk_trait_item(self, ti); | |
750 | } | |
0531ce1d XL |
751 | } |
752 | ||
e74abb32 | 753 | pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool { |
9fa01778 XL |
754 | let mut validator = AstValidator { |
755 | session, | |
756 | has_proc_macro_decls: false, | |
9fa01778 XL |
757 | outer_impl_trait: None, |
758 | is_impl_trait_banned: false, | |
dc9dc135 | 759 | is_assoc_ty_bound_banned: false, |
e74abb32 | 760 | lint_buffer: lints, |
9fa01778 XL |
761 | }; |
762 | visit::walk_crate(&mut validator, krate); | |
763 | ||
416331ca | 764 | validator.has_proc_macro_decls |
3157f602 | 765 | } |