]>
Commit | Line | Data |
---|---|---|
1 | // Validate AST before lowering it to HIR. | |
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 | ||
9 | use std::mem; | |
10 | use rustc::lint; | |
11 | use rustc::session::Session; | |
12 | use rustc_data_structures::fx::FxHashMap; | |
13 | use rustc_parse::validate_attr; | |
14 | use syntax::ast::*; | |
15 | use syntax::attr; | |
16 | use syntax::expand::is_proc_macro_attr; | |
17 | use syntax::print::pprust; | |
18 | use syntax::source_map::Spanned; | |
19 | use syntax::symbol::{kw, sym}; | |
20 | use syntax::visit::{self, Visitor}; | |
21 | use syntax::{span_err, struct_span_err, walk_list}; | |
22 | use syntax_pos::Span; | |
23 | use errors::{Applicability, FatalError}; | |
24 | ||
25 | use rustc_error_codes::*; | |
26 | ||
27 | struct AstValidator<'a> { | |
28 | session: &'a Session, | |
29 | has_proc_macro_decls: bool, | |
30 | ||
31 | /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`. | |
32 | /// Nested `impl Trait` _is_ allowed in associated type position, | |
33 | /// e.g., `impl Iterator<Item = impl Debug>`. | |
34 | outer_impl_trait: Option<Span>, | |
35 | ||
36 | /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` | |
37 | /// or `Foo::Bar<impl Trait>` | |
38 | is_impl_trait_banned: bool, | |
39 | ||
40 | /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in | |
41 | /// certain positions. | |
42 | is_assoc_ty_bound_banned: bool, | |
43 | ||
44 | lint_buffer: &'a mut lint::LintBuffer, | |
45 | } | |
46 | ||
47 | impl<'a> AstValidator<'a> { | |
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 | ||
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 | ||
60 | fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { | |
61 | let old = mem::replace(&mut self.outer_impl_trait, outer); | |
62 | f(self); | |
63 | self.outer_impl_trait = old; | |
64 | } | |
65 | ||
66 | fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { | |
67 | match constraint.kind { | |
68 | AssocTyConstraintKind::Equality { .. } => {} | |
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 | } | |
76 | } | |
77 | self.visit_assoc_ty_constraint(constraint); | |
78 | } | |
79 | ||
80 | // Mirrors `visit::walk_ty`, but tracks relevant state. | |
81 | fn walk_ty(&mut self, t: &'a Ty) { | |
82 | match t.kind { | |
83 | TyKind::ImplTrait(..) => { | |
84 | self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) | |
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 | ||
123 | fn err_handler(&self) -> &errors::Handler { | |
124 | &self.session.diagnostic() | |
125 | } | |
126 | ||
127 | fn check_lifetime(&self, ident: Ident) { | |
128 | let valid_names = [kw::UnderscoreLifetime, | |
129 | kw::StaticLifetime, | |
130 | kw::Invalid]; | |
131 | if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { | |
132 | self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); | |
133 | } | |
134 | } | |
135 | ||
136 | fn check_label(&self, ident: Ident) { | |
137 | if ident.without_first_quote().is_reserved() { | |
138 | self.err_handler() | |
139 | .span_err(ident.span, &format!("invalid label name `{}`", ident.name)); | |
140 | } | |
141 | } | |
142 | ||
143 | fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { | |
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"); | |
154 | } | |
155 | if let Some(note) = note { | |
156 | err.note(note); | |
157 | } | |
158 | err.emit(); | |
159 | } | |
160 | ||
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 { | |
164 | PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) | | |
165 | PatKind::Wild => {} | |
166 | PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), _, None) => | |
167 | report_err(pat.span, true), | |
168 | _ => report_err(pat.span, false), | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
173 | fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) { | |
174 | if asyncness.is_async() { | |
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(); | |
180 | } | |
181 | } | |
182 | ||
183 | fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) { | |
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(); | |
189 | } | |
190 | } | |
191 | ||
192 | fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) { | |
193 | for bound in bounds { | |
194 | if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound { | |
195 | let mut err = self.err_handler().struct_span_err(poly.span, | |
196 | &format!("`?Trait` is not permitted in {}", where_)); | |
197 | if is_trait { | |
198 | let path_str = pprust::path_to_string(&poly.trait_ref.path); | |
199 | err.note(&format!("traits are `?{}` by default", path_str)); | |
200 | } | |
201 | err.emit(); | |
202 | } | |
203 | } | |
204 | } | |
205 | ||
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 | // ``` | |
221 | fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { | |
222 | match expr.kind { | |
223 | ExprKind::Lit(..) | ExprKind::Err => {} | |
224 | ExprKind::Path(..) if allow_paths => {} | |
225 | ExprKind::Unary(UnOp::Neg, ref inner) | |
226 | if match inner.kind { ExprKind::Lit(_) => true, _ => false } => {} | |
227 | _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \ | |
228 | in patterns") | |
229 | } | |
230 | } | |
231 | ||
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 { | |
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"); | |
241 | } | |
242 | None | |
243 | } | |
244 | _ => Some(param.ident.span), | |
245 | }).collect(); | |
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"); | |
249 | } | |
250 | } | |
251 | ||
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]; | |
259 | !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr) | |
260 | }) | |
261 | .for_each(|attr| if attr.is_doc_comment() { | |
262 | let mut err = self.err_handler().struct_span_err( | |
263 | attr.span, | |
264 | "documentation comments cannot be applied to function parameters" | |
265 | ); | |
266 | err.span_label(attr.span, "doc comments are not allowed here"); | |
267 | err.emit(); | |
268 | } | |
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 | }); | |
273 | } | |
274 | } | |
275 | ||
276 | enum GenericPosition { | |
277 | Param, | |
278 | Arg, | |
279 | } | |
280 | ||
281 | fn validate_generics_order<'a>( | |
282 | sess: &Session, | |
283 | handler: &errors::Handler, | |
284 | generics: impl Iterator< | |
285 | Item = ( | |
286 | ParamKindOrd, | |
287 | Option<&'a [GenericBound]>, | |
288 | Span, | |
289 | Option<String> | |
290 | ), | |
291 | >, | |
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![]; | |
298 | let mut found_type = false; | |
299 | let mut found_const = false; | |
300 | ||
301 | for (kind, bounds, span, ident) in generics { | |
302 | if let Some(ident) = ident { | |
303 | param_idents.push((kind, bounds, param_idents.len(), ident)); | |
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 | }; | |
313 | match kind { | |
314 | ParamKindOrd::Type => found_type = true, | |
315 | ParamKindOrd::Const => found_const = true, | |
316 | _ => {} | |
317 | } | |
318 | } | |
319 | ||
320 | let mut ordered_params = "<".to_string(); | |
321 | if !out_of_order.is_empty() { | |
322 | param_idents.sort_by_key(|&(po, _, i, _)| (po, i)); | |
323 | let mut first = true; | |
324 | for (_, bounds, _, ident) in param_idents { | |
325 | if !first { | |
326 | ordered_params += ", "; | |
327 | } | |
328 | ordered_params += &ident; | |
329 | if let Some(bounds) = bounds { | |
330 | if !bounds.is_empty() { | |
331 | ordered_params += ": "; | |
332 | ordered_params += &pprust::bounds_to_string(&bounds); | |
333 | } | |
334 | } | |
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 | ||
345 | for (param_ord, (max_param, spans)) in &out_of_order { | |
346 | let mut err = handler.struct_span_err(spans.clone(), | |
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, | |
356 | &format!( | |
357 | "reorder the {}s: lifetimes, then types{}", | |
358 | pos_str, | |
359 | if sess.features_untracked().const_generics { ", then consts" } else { "" }, | |
360 | ), | |
361 | ordered_params.clone(), | |
362 | Applicability::MachineApplicable, | |
363 | ); | |
364 | } | |
365 | err.emit(); | |
366 | } | |
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 | } | |
374 | } | |
375 | ||
376 | impl<'a> Visitor<'a> for AstValidator<'a> { | |
377 | fn visit_attribute(&mut self, attr: &Attribute) { | |
378 | validate_attr::check_meta(&self.session.parse_sess, attr); | |
379 | } | |
380 | ||
381 | fn visit_expr(&mut self, expr: &'a Expr) { | |
382 | match &expr.kind { | |
383 | ExprKind::Closure(_, _, _, fn_decl, _, _) => { | |
384 | self.check_fn_decl(fn_decl); | |
385 | } | |
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"); | |
388 | } | |
389 | _ => {} | |
390 | } | |
391 | ||
392 | visit::walk_expr(self, expr); | |
393 | } | |
394 | ||
395 | fn visit_ty(&mut self, ty: &'a Ty) { | |
396 | match ty.kind { | |
397 | TyKind::BareFn(ref bfty) => { | |
398 | self.check_fn_decl(&bfty.decl); | |
399 | Self::check_decl_no_pat(&bfty.decl, |span, _| { | |
400 | struct_span_err!(self.session, span, E0561, | |
401 | "patterns aren't allowed in function pointer types").emit(); | |
402 | }); | |
403 | self.check_late_bound_lifetime_defs(&bfty.generic_params); | |
404 | } | |
405 | TyKind::TraitObject(ref bounds, ..) => { | |
406 | let mut any_lifetime_bounds = false; | |
407 | for bound in bounds { | |
408 | if let GenericBound::Outlives(ref lifetime) = *bound { | |
409 | if any_lifetime_bounds { | |
410 | span_err!(self.session, lifetime.ident.span, E0226, | |
411 | "only a single explicit lifetime bound is permitted"); | |
412 | break; | |
413 | } | |
414 | any_lifetime_bounds = true; | |
415 | } | |
416 | } | |
417 | self.no_questions_in_bounds(bounds, "trait object types", false); | |
418 | } | |
419 | TyKind::ImplTrait(_, ref bounds) => { | |
420 | if self.is_impl_trait_banned { | |
421 | struct_span_err!( | |
422 | self.session, ty.span, E0667, | |
423 | "`impl Trait` is not allowed in path parameters" | |
424 | ) | |
425 | .emit(); | |
426 | } | |
427 | ||
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(); | |
436 | } | |
437 | ||
438 | if !bounds.iter() | |
439 | .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { | |
440 | self.err_handler().span_err(ty.span, "at least one trait must be specified"); | |
441 | } | |
442 | ||
443 | self.walk_ty(ty); | |
444 | return; | |
445 | } | |
446 | _ => {} | |
447 | } | |
448 | ||
449 | self.walk_ty(ty) | |
450 | } | |
451 | ||
452 | fn visit_label(&mut self, label: &'a Label) { | |
453 | self.check_label(label.ident); | |
454 | visit::walk_label(self, label); | |
455 | } | |
456 | ||
457 | fn visit_lifetime(&mut self, lifetime: &'a Lifetime) { | |
458 | self.check_lifetime(lifetime.ident); | |
459 | visit::walk_lifetime(self, lifetime); | |
460 | } | |
461 | ||
462 | fn visit_item(&mut self, item: &'a Item) { | |
463 | if item.attrs.iter().any(|attr| is_proc_macro_attr(attr) ) { | |
464 | self.has_proc_macro_decls = true; | |
465 | } | |
466 | ||
467 | match item.kind { | |
468 | ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { | |
469 | self.invalid_visibility(&item.vis, None); | |
470 | if let TyKind::Err = ty.kind { | |
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 | } | |
478 | for impl_item in impl_items { | |
479 | self.invalid_visibility(&impl_item.vis, None); | |
480 | if let ImplItemKind::Method(ref sig, _) = impl_item.kind { | |
481 | self.check_trait_fn_not_const(sig.header.constness); | |
482 | self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node); | |
483 | } | |
484 | } | |
485 | } | |
486 | ItemKind::Impl(unsafety, polarity, defaultness, _, None, _, _) => { | |
487 | self.invalid_visibility(&item.vis, | |
488 | Some("place qualifiers on individual impl items instead")); | |
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 { | |
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(); | |
499 | } | |
500 | } | |
501 | ItemKind::Fn(ref sig, ref generics, _) => { | |
502 | self.visit_fn_header(&sig.header); | |
503 | self.check_fn_decl(&sig.decl); | |
504 | // We currently do not permit const generics in `const fn`, as | |
505 | // this is tantamount to allowing compile-time dependent typing. | |
506 | if sig.header.constness.node == Constness::Const { | |
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 | } | |
523 | ItemKind::ForeignMod(..) => { | |
524 | self.invalid_visibility( | |
525 | &item.vis, | |
526 | Some("place qualifiers on individual foreign items instead"), | |
527 | ); | |
528 | } | |
529 | ItemKind::Enum(ref def, _) => { | |
530 | for variant in &def.variants { | |
531 | self.invalid_visibility(&variant.vis, None); | |
532 | for field in variant.data.fields() { | |
533 | self.invalid_visibility(&field.vis, None); | |
534 | } | |
535 | } | |
536 | } | |
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. | |
540 | if !generics.params.is_empty() { | |
541 | struct_span_err!(self.session, item.span, E0567, | |
542 | "auto traits cannot have generic parameters" | |
543 | ).emit(); | |
544 | } | |
545 | if !bounds.is_empty() { | |
546 | struct_span_err!(self.session, item.span, E0568, | |
547 | "auto traits cannot have super traits" | |
548 | ).emit(); | |
549 | } | |
550 | if !trait_items.is_empty() { | |
551 | struct_span_err!(self.session, item.span, E0380, | |
552 | "auto traits cannot have methods or associated items" | |
553 | ).emit(); | |
554 | } | |
555 | } | |
556 | self.no_questions_in_bounds(bounds, "supertraits", true); | |
557 | for trait_item in trait_items { | |
558 | if let TraitItemKind::Method(ref sig, ref block) = trait_item.kind { | |
559 | self.check_fn_decl(&sig.decl); | |
560 | self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node); | |
561 | self.check_trait_fn_not_const(sig.header.constness); | |
562 | if block.is_none() { | |
563 | Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { | |
564 | if mut_ident { | |
565 | self.lint_buffer.buffer_lint( | |
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 | } | |
573 | }); | |
574 | } | |
575 | } | |
576 | } | |
577 | } | |
578 | ItemKind::Mod(_) => { | |
579 | // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). | |
580 | attr::first_attr_value_str_by_name(&item.attrs, sym::path); | |
581 | } | |
582 | ItemKind::Union(ref vdata, _) => { | |
583 | if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata { | |
584 | self.err_handler().span_err(item.span, | |
585 | "tuple and unit unions are not permitted"); | |
586 | } | |
587 | if vdata.fields().is_empty() { | |
588 | self.err_handler().span_err(item.span, | |
589 | "unions cannot have zero fields"); | |
590 | } | |
591 | } | |
592 | _ => {} | |
593 | } | |
594 | ||
595 | visit::walk_item(self, item) | |
596 | } | |
597 | ||
598 | fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { | |
599 | match fi.kind { | |
600 | ForeignItemKind::Fn(ref decl, _) => { | |
601 | self.check_fn_decl(decl); | |
602 | Self::check_decl_no_pat(decl, |span, _| { | |
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(); | |
606 | }); | |
607 | } | |
608 | ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} | |
609 | } | |
610 | ||
611 | visit::walk_foreign_item(self, fi) | |
612 | } | |
613 | ||
614 | // Mirrors `visit::walk_generic_args`, but tracks relevant state. | |
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); | |
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 | ); | |
632 | ||
633 | // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>` | |
634 | // are allowed to contain nested `impl Trait`. | |
635 | self.with_impl_trait(None, |this| { | |
636 | walk_list!(this, visit_assoc_ty_constraint_from_generic_args, | |
637 | &data.constraints); | |
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`. | |
645 | self.with_impl_trait(None, |this| this.visit_ty(type_)); | |
646 | } | |
647 | } | |
648 | } | |
649 | } | |
650 | ||
651 | fn visit_generics(&mut self, generics: &'a Generics) { | |
652 | let mut prev_ty_default = None; | |
653 | for param in &generics.params { | |
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 { | |
658 | self.err_handler() | |
659 | .span_err(span, "type parameters with a default must be trailing"); | |
660 | break; | |
661 | } | |
662 | } | |
663 | } | |
664 | ||
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 | ); | |
683 | ||
684 | for predicate in &generics.where_clause.predicates { | |
685 | if let WherePredicate::EqPredicate(ref predicate) = *predicate { | |
686 | self.err_handler() | |
687 | .span_err(predicate.span, "equality constraints are not yet \ | |
688 | supported in where clauses (see #20041)"); | |
689 | } | |
690 | } | |
691 | ||
692 | visit::walk_generics(self, generics) | |
693 | } | |
694 | ||
695 | fn visit_generic_param(&mut self, param: &'a GenericParam) { | |
696 | if let GenericParamKind::Lifetime { .. } = param.kind { | |
697 | self.check_lifetime(param.ident); | |
698 | } | |
699 | visit::walk_generic_param(self, param); | |
700 | } | |
701 | ||
702 | fn visit_pat(&mut self, pat: &'a Pat) { | |
703 | match pat.kind { | |
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 | } | |
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 | } | |
729 | ||
730 | fn visit_variant_data(&mut self, s: &'a VariantData) { | |
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 | ||
740 | fn visit_impl_item(&mut self, ii: &'a ImplItem) { | |
741 | if let ImplItemKind::Method(ref sig, _) = ii.kind { | |
742 | self.check_fn_decl(&sig.decl); | |
743 | } | |
744 | visit::walk_impl_item(self, ii); | |
745 | } | |
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 | } | |
751 | } | |
752 | ||
753 | pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool { | |
754 | let mut validator = AstValidator { | |
755 | session, | |
756 | has_proc_macro_decls: false, | |
757 | outer_impl_trait: None, | |
758 | is_impl_trait_banned: false, | |
759 | is_assoc_ty_bound_banned: false, | |
760 | lint_buffer: lints, | |
761 | }; | |
762 | visit::walk_crate(&mut validator, krate); | |
763 | ||
764 | validator.has_proc_macro_decls | |
765 | } |