1 // Validate AST before lowering it to HIR.
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.
9 use itertools::{Either, Itertools};
10 use rustc_ast::ast::*;
12 use rustc_ast::expand::is_proc_macro_attr;
13 use rustc_ast::ptr::P;
14 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
15 use rustc_ast::walk_list;
16 use rustc_ast_pretty::pprust;
17 use rustc_data_structures::fx::FxHashMap;
18 use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
19 use rustc_parse::validate_attr;
20 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
21 use rustc_session::lint::LintBuffer;
22 use rustc_session::Session;
23 use rustc_span::symbol::{kw, sym};
27 const MORE_EXTERN: &str =
28 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
30 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
36 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
37 #[derive(Clone, Copy)]
45 fn description(&self) -> &'static str {
47 Self::ImplTrait => "`impl Trait`",
48 Self::TraitBounds => "supertraits",
49 Self::TraitObject => "trait objects",
54 struct AstValidator<'a> {
57 /// The span of the `extern` in an `extern { ... }` block, if any.
58 extern_mod: Option<&'a Item>,
60 /// Are we inside a trait impl?
63 has_proc_macro_decls: bool,
65 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
66 /// Nested `impl Trait` _is_ allowed in associated type position,
67 /// e.g., `impl Iterator<Item = impl Debug>`.
68 outer_impl_trait: Option<Span>,
70 /// Keeps track of the `BoundContext` as we recurse.
72 /// This is used to forbid `?const Trait` bounds in, e.g.,
73 /// `impl Iterator<Item = Box<dyn ?const Trait>`.
74 bound_context: Option<BoundContext>,
76 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
77 /// or `Foo::Bar<impl Trait>`
78 is_impl_trait_banned: bool,
80 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
81 /// certain positions.
82 is_assoc_ty_bound_banned: bool,
84 lint_buffer: &'a mut LintBuffer,
87 impl<'a> AstValidator<'a> {
88 fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
89 let old = mem::replace(&mut self.in_trait_impl, is_in);
91 self.in_trait_impl = old;
94 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
95 let old = mem::replace(&mut self.is_impl_trait_banned, true);
97 self.is_impl_trait_banned = old;
100 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
101 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
103 self.is_assoc_ty_bound_banned = old;
106 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
107 let old = mem::replace(&mut self.outer_impl_trait, outer);
109 self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
113 self.outer_impl_trait = old;
116 fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
117 let old = self.bound_context.replace(ctx);
119 self.bound_context = old;
122 fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
123 match constraint.kind {
124 AssocTyConstraintKind::Equality { .. } => {}
125 AssocTyConstraintKind::Bound { .. } => {
126 if self.is_assoc_ty_bound_banned {
127 self.err_handler().span_err(
129 "associated type bounds are not allowed within structs, enums, or unions",
134 self.visit_assoc_ty_constraint(constraint);
137 // Mirrors `visit::walk_ty`, but tracks relevant state.
138 fn walk_ty(&mut self, t: &'a Ty) {
140 TyKind::ImplTrait(..) => {
141 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
143 TyKind::TraitObject(..) => {
144 self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
146 TyKind::Path(ref qself, ref path) => {
148 // - `Option<impl Trait>`
149 // - `option::Option<impl Trait>`
150 // - `option::Option<T>::Foo<impl Trait>
153 // - `<impl Trait>::Foo`
154 // - `option::Option<impl Trait>::Foo`.
156 // To implement this, we disallow `impl Trait` from `qself`
157 // (for cases like `<impl Trait>::Foo>`)
158 // but we allow `impl Trait` in `GenericArgs`
159 // iff there are no more PathSegments.
160 if let Some(ref qself) = *qself {
161 // `impl Trait` in `qself` is always illegal
162 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
165 // Note that there should be a call to visit_path here,
166 // so if any logic is added to process `Path`s a call to it should be
167 // added both in visit_path and here. This code mirrors visit::walk_path.
168 for (i, segment) in path.segments.iter().enumerate() {
169 // Allow `impl Trait` iff we're on the final path segment
170 if i == path.segments.len() - 1 {
171 self.visit_path_segment(path.span, segment);
173 self.with_banned_impl_trait(|this| {
174 this.visit_path_segment(path.span, segment)
179 _ => visit::walk_ty(self, t),
183 fn err_handler(&self) -> &rustc_errors::Handler {
184 &self.session.diagnostic()
187 fn check_lifetime(&self, ident: Ident) {
188 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
189 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
190 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
194 fn check_label(&self, ident: Ident) {
195 if ident.without_first_quote().is_reserved() {
197 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
201 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
202 if let VisibilityKind::Inherited = vis.node {
207 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
208 if vis.node.is_pub() {
209 err.span_label(vis.span, "`pub` not permitted here because it's implied");
211 if let Some(note) = note {
217 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
218 for Param { pat, .. } in &decl.inputs {
220 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
221 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
222 report_err(pat.span, true)
224 _ => report_err(pat.span, false),
229 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
230 if let Async::Yes { span, .. } = asyncness {
235 "functions in traits cannot be declared `async`"
237 .span_label(span, "`async` because of this")
238 .note("`async` trait functions are not currently supported")
239 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
244 fn check_trait_fn_not_const(&self, constness: Const) {
245 if let Const::Yes(span) = constness {
250 "functions in traits cannot be declared const"
252 .span_label(span, "functions in traits cannot be const")
257 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
258 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
259 for bound in bounds {
260 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
261 let mut err = self.err_handler().struct_span_err(
263 &format!("`?Trait` is not permitted in {}", where_),
266 let path_str = pprust::path_to_string(&poly.trait_ref.path);
267 err.note(&format!("traits are `?{}` by default", path_str));
274 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
275 /// or paths for ranges.
277 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
278 // That means making this work:
280 // ```rust,ignore (FIXME)
289 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
291 ExprKind::Lit(..) | ExprKind::Err => {}
292 ExprKind::Path(..) if allow_paths => {}
293 ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
294 _ => self.err_handler().span_err(
296 "arbitrary expressions aren't allowed \
302 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
303 // Check only lifetime parameters are present and that the lifetime
304 // parameters that are present have no bounds.
305 let non_lt_param_spans: Vec<_> = params
307 .filter_map(|param| match param.kind {
308 GenericParamKind::Lifetime { .. } => {
309 if !param.bounds.is_empty() {
310 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
312 .span_err(spans, "lifetime bounds cannot be used in this context");
316 _ => Some(param.ident.span),
319 if !non_lt_param_spans.is_empty() {
320 self.err_handler().span_err(
322 "only lifetime parameters can be used in this context",
327 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
328 self.check_decl_cvaradic_pos(fn_decl);
329 self.check_decl_attrs(fn_decl);
330 self.check_decl_self_param(fn_decl, self_semantic);
333 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
334 match &*fn_decl.inputs {
335 [Param { ty, span, .. }] => {
336 if let TyKind::CVarArgs = ty.kind {
337 self.err_handler().span_err(
339 "C-variadic function must be declared with at least one named argument",
344 for Param { ty, span, .. } in ps {
345 if let TyKind::CVarArgs = ty.kind {
346 self.err_handler().span_err(
348 "`...` must be the last argument of a C-variadic function",
357 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
361 .flat_map(|i| i.attrs.as_ref())
363 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
364 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
367 if attr.is_doc_comment() {
371 "documentation comments cannot be applied to function parameters",
373 .span_label(attr.span, "doc comments are not allowed here")
376 self.err_handler().span_err(
378 "allow, cfg, cfg_attr, deny, \
379 forbid, and warn are the only allowed built-in attributes in function parameters",
385 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
386 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
391 "`self` parameter is only allowed in associated functions",
393 .span_label(param.span, "not semantically valid as function parameter")
394 .note("associated functions are those in `impl` or `trait` definitions")
400 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
401 if let Defaultness::Default(def_span) = defaultness {
402 let span = self.session.source_map().guess_head_span(span);
404 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
405 .span_label(def_span, "`default` because of this")
410 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
412 .struct_span_err(sp, msg)
414 self.session.source_map().end_point(sp),
415 &format!("provide a definition for the {}", ctx),
417 Applicability::HasPlaceholders,
422 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
424 let msg = format!("associated {} in `impl` without body", ctx);
425 self.error_item_without_body(sp, ctx, &msg, sugg);
429 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
430 let span = match bounds {
433 [b0, .., bl] => b0.span().to(bl.span()),
436 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
440 fn check_foreign_ty_genericless(&self, generics: &Generics) {
441 let cannot_have = |span, descr, remove_descr| {
445 &format!("`type`s inside `extern` blocks cannot have {}", descr),
449 &format!("remove the {}", remove_descr),
451 Applicability::MaybeIncorrect,
453 .span_label(self.current_extern_span(), "`extern` block begins here")
458 if !generics.params.is_empty() {
459 cannot_have(generics.span, "generic parameters", "generic parameters");
462 if !generics.where_clause.predicates.is_empty() {
463 cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
467 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
468 let body = match body {
473 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
474 .span_label(ident.span, "cannot have a body")
475 .span_label(body, "the invalid body")
477 self.current_extern_span(),
479 "`extern` blocks define existing foreign {0}s and {0}s \
480 inside of them cannot have a body",
488 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
489 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
490 let body = match body {
495 .struct_span_err(ident.span, "incorrect function inside `extern` block")
496 .span_label(ident.span, "cannot have a body")
499 "remove the invalid body",
501 Applicability::MaybeIncorrect,
504 "you might have meant to write a function accessible through FFI, \
505 which can be done by writing `extern fn` outside of the `extern` block",
508 self.current_extern_span(),
509 "`extern` blocks define existing foreign functions and functions \
510 inside of them cannot have a body",
516 fn current_extern_span(&self) -> Span {
517 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
520 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
521 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
522 if header.has_qualifiers() {
524 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
525 .span_label(self.current_extern_span(), "in this `extern` block")
527 span.until(ident.span.shrink_to_lo()),
528 "remove the qualifiers",
530 Applicability::MaybeIncorrect,
536 /// Reject C-varadic type unless the function is foreign,
537 /// or free and `unsafe extern "C"` semantically.
538 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
539 match (fk.ctxt(), fk.header()) {
540 (Some(FnCtxt::Foreign), _) => return,
541 (Some(FnCtxt::Free), Some(header)) => match header.ext {
542 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
543 if matches!(header.unsafety, Unsafe::Yes(_)) =>
552 for Param { ty, span, .. } in &fk.decl().inputs {
553 if let TyKind::CVarArgs = ty.kind {
557 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
564 /// We currently do not permit const generics in `const fn`,
565 /// as this is tantamount to allowing compile-time dependent typing.
567 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
568 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
569 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
570 if let Const::Yes(const_span) = sig.header.constness {
571 // Look for const generics and error if we find any.
572 for param in &generics.params {
573 if let GenericParamKind::Const { .. } = param.kind {
577 "const parameters are not permitted in const functions",
579 .span_label(const_span, "`const` because of this")
586 fn check_item_named(&self, ident: Ident, kind: &str) {
587 if ident.name != kw::Underscore {
591 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
592 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
596 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
597 if !generics.params.is_empty() {
602 "auto traits cannot have generic parameters"
604 .span_label(ident_span, "auto trait cannot have generic parameters")
607 "remove the parameters",
609 Applicability::MachineApplicable,
615 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
616 if let [first @ last] | [first, .., last] = &bounds[..] {
617 let span = first.span().to(last.span());
618 struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
619 .span_label(ident_span, "auto trait cannot have super traits")
622 "remove the super traits",
624 Applicability::MachineApplicable,
630 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
631 if !trait_items.is_empty() {
632 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
637 "auto traits cannot have methods or associated items"
639 .span_label(ident_span, "auto trait cannot have items")
644 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
645 // Lifetimes always come first.
646 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
647 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
648 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
652 let args_sugg = data.args.iter().filter_map(|a| match a {
653 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
656 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
658 // Constraints always come last.
659 let constraint_sugg = data.args.iter().filter_map(|a| match a {
660 AngleBracketedArg::Arg(_) => None,
661 AngleBracketedArg::Constraint(c) => {
662 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
667 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
671 /// Enforce generic args coming before constraints in `<...>` of a path segment.
672 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
673 // Early exit in case it's partitioned as it should be.
674 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
677 // Find all generic argument coming after the first constraint...
678 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
679 data.args.iter().partition_map(|arg| match arg {
680 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
681 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
683 let args_len = arg_spans.len();
684 let constraint_len = constraint_spans.len();
685 // ...and then error:
689 "generic arguments must come before the first constraint",
691 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
693 *arg_spans.iter().last().unwrap(),
694 &format!("generic argument{}", pluralize!(args_len)),
696 .span_labels(constraint_spans, "")
697 .span_labels(arg_spans, "")
698 .span_suggestion_verbose(
701 "move the constraint{} after the generic argument{}",
702 pluralize!(constraint_len),
705 self.correct_generic_order_suggestion(&data),
706 Applicability::MachineApplicable,
712 /// Checks that generic parameters are in the correct order,
713 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
714 fn validate_generic_param_order<'a>(
716 handler: &rustc_errors::Handler,
717 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
720 let mut max_param: Option<ParamKindOrd> = None;
721 let mut out_of_order = FxHashMap::default();
722 let mut param_idents = vec![];
724 for (kind, bounds, span, ident) in generics {
725 if let Some(ident) = ident {
726 param_idents.push((kind, bounds, param_idents.len(), ident));
728 let max_param = &mut max_param;
730 Some(max_param) if *max_param > kind => {
731 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
734 Some(_) | None => *max_param = Some(kind),
738 let mut ordered_params = "<".to_string();
739 if !out_of_order.is_empty() {
740 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
741 let mut first = true;
742 for (_, bounds, _, ident) in param_idents {
744 ordered_params += ", ";
746 ordered_params += &ident;
747 if let Some(bounds) = bounds {
748 if !bounds.is_empty() {
749 ordered_params += ": ";
750 ordered_params += &pprust::bounds_to_string(&bounds);
756 ordered_params += ">";
758 for (param_ord, (max_param, spans)) in &out_of_order {
760 handler.struct_span_err(
763 "{} parameters must be declared prior to {} parameters",
764 param_ord, max_param,
770 "reorder the parameters: lifetimes, then types{}",
771 if sess.features_untracked().const_generics { ", then consts" } else { "" },
773 ordered_params.clone(),
774 Applicability::MachineApplicable,
780 impl<'a> Visitor<'a> for AstValidator<'a> {
781 fn visit_attribute(&mut self, attr: &Attribute) {
782 validate_attr::check_meta(&self.session.parse_sess, attr);
785 fn visit_expr(&mut self, expr: &'a Expr) {
787 ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => {
792 "llvm_asm! is unsupported on this target"
799 visit::walk_expr(self, expr);
802 fn visit_ty(&mut self, ty: &'a Ty) {
804 TyKind::BareFn(ref bfty) => {
805 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
806 Self::check_decl_no_pat(&bfty.decl, |span, _| {
811 "patterns aren't allowed in function pointer types"
815 self.check_late_bound_lifetime_defs(&bfty.generic_params);
817 TyKind::TraitObject(ref bounds, ..) => {
818 let mut any_lifetime_bounds = false;
819 for bound in bounds {
820 if let GenericBound::Outlives(ref lifetime) = *bound {
821 if any_lifetime_bounds {
826 "only a single explicit lifetime bound is permitted"
831 any_lifetime_bounds = true;
834 self.no_questions_in_bounds(bounds, "trait object types", false);
836 TyKind::ImplTrait(_, ref bounds) => {
837 if self.is_impl_trait_banned {
842 "`impl Trait` is not allowed in path parameters"
847 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
852 "nested `impl Trait` is not allowed"
854 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
855 .span_label(ty.span, "nested `impl Trait` here")
861 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
863 self.err_handler().span_err(ty.span, "at least one trait must be specified");
875 fn visit_label(&mut self, label: &'a Label) {
876 self.check_label(label.ident);
877 visit::walk_label(self, label);
880 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
881 self.check_lifetime(lifetime.ident);
882 visit::walk_lifetime(self, lifetime);
885 fn visit_item(&mut self, item: &'a Item) {
886 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
887 self.has_proc_macro_decls = true;
897 of_trait: Some(ref t),
901 self.with_in_trait_impl(true, |this| {
902 this.invalid_visibility(&item.vis, None);
903 if let TyKind::Err = self_ty.kind {
907 "`impl Trait for .. {}` is an obsolete syntax",
909 .help("use `auto trait Trait {}` instead")
912 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
917 "negative impls cannot be unsafe"
919 .span_label(sp, "negative because of this")
920 .span_label(span, "unsafe because of this")
924 visit::walk_item(this, item);
926 return; // Avoid visiting again.
938 let error = |annotation_span, annotation| {
939 let mut err = self.err_handler().struct_span_err(
941 &format!("inherent impls cannot be {}", annotation),
943 err.span_label(annotation_span, &format!("{} because of this", annotation));
944 err.span_label(self_ty.span, "inherent impl for this type");
948 self.invalid_visibility(
950 Some("place qualifiers on individual impl items instead"),
952 if let Unsafe::Yes(span) = unsafety {
953 error(span, "unsafe").code(error_code!(E0197)).emit();
955 if let ImplPolarity::Negative(span) = polarity {
956 error(span, "negative").emit();
958 if let Defaultness::Default(def_span) = defaultness {
959 error(def_span, "`default`")
960 .note("only trait implementations may be annotated with `default`")
963 if let Const::Yes(span) = constness {
964 error(span, "`const`")
965 .note("only trait implementations may be annotated with `const`")
969 ItemKind::Fn(def, ref sig, ref generics, ref body) => {
970 self.check_defaultness(item.span, def);
971 self.check_const_fn_const_generic(item.span, sig, generics);
974 let msg = "free function without a body";
975 self.error_item_without_body(item.span, "function", msg, " { <body> }");
978 ItemKind::ForeignMod(_) => {
979 let old_item = mem::replace(&mut self.extern_mod, Some(item));
980 self.invalid_visibility(
982 Some("place qualifiers on individual foreign items instead"),
984 visit::walk_item(self, item);
985 self.extern_mod = old_item;
986 return; // Avoid visiting again.
988 ItemKind::Enum(ref def, _) => {
989 for variant in &def.variants {
990 self.invalid_visibility(&variant.vis, None);
991 for field in variant.data.fields() {
992 self.invalid_visibility(&field.vis, None);
996 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
997 if is_auto == IsAuto::Yes {
998 // Auto traits cannot have generics, super traits nor contain items.
999 self.deny_generic_params(generics, item.ident.span);
1000 self.deny_super_traits(bounds, item.ident.span);
1001 self.deny_items(trait_items, item.ident.span);
1003 self.no_questions_in_bounds(bounds, "supertraits", true);
1005 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1006 // context for the supertraits.
1007 self.visit_vis(&item.vis);
1008 self.visit_ident(item.ident);
1009 self.visit_generics(generics);
1010 self.with_bound_context(BoundContext::TraitBounds, |this| {
1011 walk_list!(this, visit_param_bound, bounds);
1013 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
1014 walk_list!(self, visit_attribute, &item.attrs);
1017 ItemKind::Mod(_) => {
1018 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1019 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
1021 ItemKind::Union(ref vdata, _) => {
1022 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
1024 .span_err(item.span, "tuple and unit unions are not permitted");
1026 if vdata.fields().is_empty() {
1027 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1030 ItemKind::Const(def, .., None) => {
1031 self.check_defaultness(item.span, def);
1032 let msg = "free constant item without body";
1033 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1035 ItemKind::Static(.., None) => {
1036 let msg = "free static item without body";
1037 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1039 ItemKind::TyAlias(def, _, ref bounds, ref body) => {
1040 self.check_defaultness(item.span, def);
1042 let msg = "free type alias without body";
1043 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1045 self.check_type_no_bounds(bounds, "this context");
1050 visit::walk_item(self, item)
1053 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1055 ForeignItemKind::Fn(def, sig, _, body) => {
1056 self.check_defaultness(fi.span, *def);
1057 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1058 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1060 ForeignItemKind::TyAlias(def, generics, bounds, body) => {
1061 self.check_defaultness(fi.span, *def);
1062 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1063 self.check_type_no_bounds(bounds, "`extern` blocks");
1064 self.check_foreign_ty_genericless(generics);
1066 ForeignItemKind::Static(_, _, body) => {
1067 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1069 ForeignItemKind::MacCall(..) => {}
1072 visit::walk_foreign_item(self, fi)
1075 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1076 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1077 match *generic_args {
1078 GenericArgs::AngleBracketed(ref data) => {
1079 self.check_generic_args_before_constraints(data);
1081 for arg in &data.args {
1083 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1084 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1085 // are allowed to contain nested `impl Trait`.
1086 AngleBracketedArg::Constraint(constraint) => {
1087 self.with_impl_trait(None, |this| {
1088 this.visit_assoc_ty_constraint_from_generic_args(constraint);
1094 GenericArgs::Parenthesized(ref data) => {
1095 walk_list!(self, visit_ty, &data.inputs);
1096 if let FnRetTy::Ty(ty) = &data.output {
1097 // `-> Foo` syntax is essentially an associated type binding,
1098 // so it is also allowed to contain nested `impl Trait`.
1099 self.with_impl_trait(None, |this| this.visit_ty(ty));
1105 fn visit_generics(&mut self, generics: &'a Generics) {
1106 let mut prev_ty_default = None;
1107 for param in &generics.params {
1108 if let GenericParamKind::Type { ref default, .. } = param.kind {
1109 if default.is_some() {
1110 prev_ty_default = Some(param.ident.span);
1111 } else if let Some(span) = prev_ty_default {
1113 .span_err(span, "type parameters with a default must be trailing");
1119 validate_generic_param_order(
1122 generics.params.iter().map(|param| {
1123 let ident = Some(param.ident.to_string());
1124 let (kind, ident) = match ¶m.kind {
1125 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1126 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1127 GenericParamKind::Const { ref ty } => {
1128 let ty = pprust::ty_to_string(ty);
1129 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1132 (kind, Some(&*param.bounds), param.ident.span, ident)
1137 for predicate in &generics.where_clause.predicates {
1138 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1142 "equality constraints are not yet supported in `where` clauses",
1144 .span_label(predicate.span, "not supported")
1146 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1147 for more information",
1153 visit::walk_generics(self, generics)
1156 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1157 if let GenericParamKind::Lifetime { .. } = param.kind {
1158 self.check_lifetime(param.ident);
1160 visit::walk_generic_param(self, param);
1163 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1165 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1166 if let Some(ctx) = self.bound_context {
1167 let msg = format!("`?const` is not permitted in {}", ctx.description());
1168 self.err_handler().span_err(bound.span(), &msg);
1172 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1174 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1180 visit::walk_param_bound(self, bound)
1183 fn visit_pat(&mut self, pat: &'a Pat) {
1185 PatKind::Lit(ref expr) => {
1186 self.check_expr_within_pat(expr, false);
1188 PatKind::Range(ref start, ref end, _) => {
1189 if let Some(expr) = start {
1190 self.check_expr_within_pat(expr, true);
1192 if let Some(expr) = end {
1193 self.check_expr_within_pat(expr, true);
1199 visit::walk_pat(self, pat)
1202 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1203 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1204 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1205 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1207 visit::walk_where_predicate(self, p);
1210 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1211 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1212 visit::walk_poly_trait_ref(self, t, m);
1215 fn visit_variant_data(&mut self, s: &'a VariantData) {
1216 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1221 enum_definition: &'a EnumDef,
1222 generics: &'a Generics,
1226 self.with_banned_assoc_ty_bound(|this| {
1227 visit::walk_enum_def(this, enum_definition, generics, item_id)
1231 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1232 // Only associated `fn`s can have `self` parameters.
1233 let self_semantic = match fk.ctxt() {
1234 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1235 _ => SelfSemantic::No,
1237 self.check_fn_decl(fk.decl(), self_semantic);
1239 self.check_c_varadic_type(fk);
1241 // Functions cannot both be `const async`
1242 if let Some(FnHeader {
1243 constness: Const::Yes(cspan),
1244 asyncness: Async::Yes { span: aspan, .. },
1250 vec![*cspan, *aspan],
1251 "functions cannot be both `const` and `async`",
1253 .span_label(*cspan, "`const` because of this")
1254 .span_label(*aspan, "`async` because of this")
1255 .span_label(span, "") // Point at the fn header.
1259 // Functions without bodies cannot have patterns.
1260 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1261 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1262 let (code, msg, label) = match ctxt {
1263 FnCtxt::Foreign => (
1265 "patterns aren't allowed in foreign function declarations",
1266 "pattern not allowed in foreign function",
1270 "patterns aren't allowed in functions without bodies",
1271 "pattern not allowed in function without body",
1274 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1275 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1278 .struct_span_err(span, msg)
1279 .span_label(span, label)
1286 visit::walk_fn(self, fk, span);
1289 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1290 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1291 self.check_defaultness(item.span, item.kind.defaultness());
1294 if ctxt == AssocCtxt::Impl {
1296 AssocItemKind::Const(_, _, body) => {
1297 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1299 AssocItemKind::Fn(_, _, _, body) => {
1300 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1302 AssocItemKind::TyAlias(_, _, bounds, body) => {
1303 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1304 self.check_type_no_bounds(bounds, "`impl`s");
1310 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1311 self.invalid_visibility(&item.vis, None);
1312 if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
1313 self.check_trait_fn_not_const(sig.header.constness);
1314 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1318 if let AssocItemKind::Const(..) = item.kind {
1319 self.check_item_named(item.ident, "const");
1322 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1326 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1327 let mut validator = AstValidator {
1330 in_trait_impl: false,
1331 has_proc_macro_decls: false,
1332 outer_impl_trait: None,
1333 bound_context: None,
1334 is_impl_trait_banned: false,
1335 is_assoc_ty_bound_banned: false,
1338 visit::walk_crate(&mut validator, krate);
1340 validator.has_proc_macro_decls