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 fn check_item_named(&self, ident: Ident, kind: &str) {
565 if ident.name != kw::Underscore {
569 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
570 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
574 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
575 if !generics.params.is_empty() {
580 "auto traits cannot have generic parameters"
582 .span_label(ident_span, "auto trait cannot have generic parameters")
585 "remove the parameters",
587 Applicability::MachineApplicable,
593 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
594 if let [first @ last] | [first, .., last] = &bounds[..] {
595 let span = first.span().to(last.span());
596 struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
597 .span_label(ident_span, "auto trait cannot have super traits")
600 "remove the super traits",
602 Applicability::MachineApplicable,
608 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
609 if !trait_items.is_empty() {
610 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
615 "auto traits cannot have methods or associated items"
617 .span_label(ident_span, "auto trait cannot have items")
622 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
623 // Lifetimes always come first.
624 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
625 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
626 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
630 let args_sugg = data.args.iter().filter_map(|a| match a {
631 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
634 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
636 // Constraints always come last.
637 let constraint_sugg = data.args.iter().filter_map(|a| match a {
638 AngleBracketedArg::Arg(_) => None,
639 AngleBracketedArg::Constraint(c) => {
640 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
645 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
649 /// Enforce generic args coming before constraints in `<...>` of a path segment.
650 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
651 // Early exit in case it's partitioned as it should be.
652 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
655 // Find all generic argument coming after the first constraint...
656 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
657 data.args.iter().partition_map(|arg| match arg {
658 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
659 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
661 let args_len = arg_spans.len();
662 let constraint_len = constraint_spans.len();
663 // ...and then error:
667 "generic arguments must come before the first constraint",
669 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
671 *arg_spans.iter().last().unwrap(),
672 &format!("generic argument{}", pluralize!(args_len)),
674 .span_labels(constraint_spans, "")
675 .span_labels(arg_spans, "")
676 .span_suggestion_verbose(
679 "move the constraint{} after the generic argument{}",
680 pluralize!(constraint_len),
683 self.correct_generic_order_suggestion(&data),
684 Applicability::MachineApplicable,
690 /// Checks that generic parameters are in the correct order,
691 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
692 fn validate_generic_param_order<'a>(
694 handler: &rustc_errors::Handler,
695 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
698 let mut max_param: Option<ParamKindOrd> = None;
699 let mut out_of_order = FxHashMap::default();
700 let mut param_idents = vec![];
702 for (kind, bounds, span, ident) in generics {
703 if let Some(ident) = ident {
704 param_idents.push((kind, bounds, param_idents.len(), ident));
706 let max_param = &mut max_param;
708 Some(max_param) if *max_param > kind => {
709 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
712 Some(_) | None => *max_param = Some(kind),
716 let mut ordered_params = "<".to_string();
717 if !out_of_order.is_empty() {
718 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
719 let mut first = true;
720 for (_, bounds, _, ident) in param_idents {
722 ordered_params += ", ";
724 ordered_params += &ident;
725 if let Some(bounds) = bounds {
726 if !bounds.is_empty() {
727 ordered_params += ": ";
728 ordered_params += &pprust::bounds_to_string(&bounds);
734 ordered_params += ">";
736 for (param_ord, (max_param, spans)) in &out_of_order {
738 handler.struct_span_err(
741 "{} parameters must be declared prior to {} parameters",
742 param_ord, max_param,
748 "reorder the parameters: lifetimes, then types{}",
749 if sess.features_untracked().const_generics { ", then consts" } else { "" },
751 ordered_params.clone(),
752 Applicability::MachineApplicable,
758 impl<'a> Visitor<'a> for AstValidator<'a> {
759 fn visit_attribute(&mut self, attr: &Attribute) {
760 validate_attr::check_meta(&self.session.parse_sess, attr);
763 fn visit_expr(&mut self, expr: &'a Expr) {
765 ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => {
770 "llvm_asm! is unsupported on this target"
777 visit::walk_expr(self, expr);
780 fn visit_ty(&mut self, ty: &'a Ty) {
782 TyKind::BareFn(ref bfty) => {
783 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
784 Self::check_decl_no_pat(&bfty.decl, |span, _| {
789 "patterns aren't allowed in function pointer types"
793 self.check_late_bound_lifetime_defs(&bfty.generic_params);
795 TyKind::TraitObject(ref bounds, ..) => {
796 let mut any_lifetime_bounds = false;
797 for bound in bounds {
798 if let GenericBound::Outlives(ref lifetime) = *bound {
799 if any_lifetime_bounds {
804 "only a single explicit lifetime bound is permitted"
809 any_lifetime_bounds = true;
812 self.no_questions_in_bounds(bounds, "trait object types", false);
814 TyKind::ImplTrait(_, ref bounds) => {
815 if self.is_impl_trait_banned {
820 "`impl Trait` is not allowed in path parameters"
825 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
830 "nested `impl Trait` is not allowed"
832 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
833 .span_label(ty.span, "nested `impl Trait` here")
839 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
841 self.err_handler().span_err(ty.span, "at least one trait must be specified");
853 fn visit_label(&mut self, label: &'a Label) {
854 self.check_label(label.ident);
855 visit::walk_label(self, label);
858 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
859 self.check_lifetime(lifetime.ident);
860 visit::walk_lifetime(self, lifetime);
863 fn visit_item(&mut self, item: &'a Item) {
864 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
865 self.has_proc_macro_decls = true;
875 of_trait: Some(ref t),
879 self.with_in_trait_impl(true, |this| {
880 this.invalid_visibility(&item.vis, None);
881 if let TyKind::Err = self_ty.kind {
885 "`impl Trait for .. {}` is an obsolete syntax",
887 .help("use `auto trait Trait {}` instead")
890 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
895 "negative impls cannot be unsafe"
897 .span_label(sp, "negative because of this")
898 .span_label(span, "unsafe because of this")
902 visit::walk_item(this, item);
904 return; // Avoid visiting again.
916 let error = |annotation_span, annotation| {
917 let mut err = self.err_handler().struct_span_err(
919 &format!("inherent impls cannot be {}", annotation),
921 err.span_label(annotation_span, &format!("{} because of this", annotation));
922 err.span_label(self_ty.span, "inherent impl for this type");
926 self.invalid_visibility(
928 Some("place qualifiers on individual impl items instead"),
930 if let Unsafe::Yes(span) = unsafety {
931 error(span, "unsafe").code(error_code!(E0197)).emit();
933 if let ImplPolarity::Negative(span) = polarity {
934 error(span, "negative").emit();
936 if let Defaultness::Default(def_span) = defaultness {
937 error(def_span, "`default`")
938 .note("only trait implementations may be annotated with `default`")
941 if let Const::Yes(span) = constness {
942 error(span, "`const`")
943 .note("only trait implementations may be annotated with `const`")
947 ItemKind::Fn(def, _, _, ref body) => {
948 self.check_defaultness(item.span, def);
951 let msg = "free function without a body";
952 self.error_item_without_body(item.span, "function", msg, " { <body> }");
955 ItemKind::ForeignMod(_) => {
956 let old_item = mem::replace(&mut self.extern_mod, Some(item));
957 self.invalid_visibility(
959 Some("place qualifiers on individual foreign items instead"),
961 visit::walk_item(self, item);
962 self.extern_mod = old_item;
963 return; // Avoid visiting again.
965 ItemKind::Enum(ref def, _) => {
966 for variant in &def.variants {
967 self.invalid_visibility(&variant.vis, None);
968 for field in variant.data.fields() {
969 self.invalid_visibility(&field.vis, None);
973 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
974 if is_auto == IsAuto::Yes {
975 // Auto traits cannot have generics, super traits nor contain items.
976 self.deny_generic_params(generics, item.ident.span);
977 self.deny_super_traits(bounds, item.ident.span);
978 self.deny_items(trait_items, item.ident.span);
980 self.no_questions_in_bounds(bounds, "supertraits", true);
982 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
983 // context for the supertraits.
984 self.visit_vis(&item.vis);
985 self.visit_ident(item.ident);
986 self.visit_generics(generics);
987 self.with_bound_context(BoundContext::TraitBounds, |this| {
988 walk_list!(this, visit_param_bound, bounds);
990 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
991 walk_list!(self, visit_attribute, &item.attrs);
994 ItemKind::Mod(_) => {
995 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
996 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
998 ItemKind::Union(ref vdata, _) => {
999 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
1001 .span_err(item.span, "tuple and unit unions are not permitted");
1003 if vdata.fields().is_empty() {
1004 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1007 ItemKind::Const(def, .., None) => {
1008 self.check_defaultness(item.span, def);
1009 let msg = "free constant item without body";
1010 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1012 ItemKind::Static(.., None) => {
1013 let msg = "free static item without body";
1014 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1016 ItemKind::TyAlias(def, _, ref bounds, ref body) => {
1017 self.check_defaultness(item.span, def);
1019 let msg = "free type alias without body";
1020 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1022 self.check_type_no_bounds(bounds, "this context");
1027 visit::walk_item(self, item)
1030 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1032 ForeignItemKind::Fn(def, sig, _, body) => {
1033 self.check_defaultness(fi.span, *def);
1034 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1035 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1037 ForeignItemKind::TyAlias(def, generics, bounds, body) => {
1038 self.check_defaultness(fi.span, *def);
1039 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1040 self.check_type_no_bounds(bounds, "`extern` blocks");
1041 self.check_foreign_ty_genericless(generics);
1043 ForeignItemKind::Static(_, _, body) => {
1044 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1046 ForeignItemKind::MacCall(..) => {}
1049 visit::walk_foreign_item(self, fi)
1052 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1053 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1054 match *generic_args {
1055 GenericArgs::AngleBracketed(ref data) => {
1056 self.check_generic_args_before_constraints(data);
1058 for arg in &data.args {
1060 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1061 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1062 // are allowed to contain nested `impl Trait`.
1063 AngleBracketedArg::Constraint(constraint) => {
1064 self.with_impl_trait(None, |this| {
1065 this.visit_assoc_ty_constraint_from_generic_args(constraint);
1071 GenericArgs::Parenthesized(ref data) => {
1072 walk_list!(self, visit_ty, &data.inputs);
1073 if let FnRetTy::Ty(ty) = &data.output {
1074 // `-> Foo` syntax is essentially an associated type binding,
1075 // so it is also allowed to contain nested `impl Trait`.
1076 self.with_impl_trait(None, |this| this.visit_ty(ty));
1082 fn visit_generics(&mut self, generics: &'a Generics) {
1083 let mut prev_ty_default = None;
1084 for param in &generics.params {
1085 if let GenericParamKind::Type { ref default, .. } = param.kind {
1086 if default.is_some() {
1087 prev_ty_default = Some(param.ident.span);
1088 } else if let Some(span) = prev_ty_default {
1090 .span_err(span, "type parameters with a default must be trailing");
1096 validate_generic_param_order(
1099 generics.params.iter().map(|param| {
1100 let ident = Some(param.ident.to_string());
1101 let (kind, ident) = match ¶m.kind {
1102 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1103 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1104 GenericParamKind::Const { ref ty } => {
1105 let ty = pprust::ty_to_string(ty);
1106 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1109 (kind, Some(&*param.bounds), param.ident.span, ident)
1114 for predicate in &generics.where_clause.predicates {
1115 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1119 "equality constraints are not yet supported in `where` clauses",
1121 .span_label(predicate.span, "not supported")
1123 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1124 for more information",
1130 visit::walk_generics(self, generics)
1133 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1134 if let GenericParamKind::Lifetime { .. } = param.kind {
1135 self.check_lifetime(param.ident);
1137 visit::walk_generic_param(self, param);
1140 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1142 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1143 if let Some(ctx) = self.bound_context {
1144 let msg = format!("`?const` is not permitted in {}", ctx.description());
1145 self.err_handler().span_err(bound.span(), &msg);
1149 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1151 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1157 visit::walk_param_bound(self, bound)
1160 fn visit_pat(&mut self, pat: &'a Pat) {
1162 PatKind::Lit(ref expr) => {
1163 self.check_expr_within_pat(expr, false);
1165 PatKind::Range(ref start, ref end, _) => {
1166 if let Some(expr) = start {
1167 self.check_expr_within_pat(expr, true);
1169 if let Some(expr) = end {
1170 self.check_expr_within_pat(expr, true);
1176 visit::walk_pat(self, pat)
1179 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1180 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1181 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1182 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1184 visit::walk_where_predicate(self, p);
1187 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1188 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1189 visit::walk_poly_trait_ref(self, t, m);
1192 fn visit_variant_data(&mut self, s: &'a VariantData) {
1193 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1198 enum_definition: &'a EnumDef,
1199 generics: &'a Generics,
1203 self.with_banned_assoc_ty_bound(|this| {
1204 visit::walk_enum_def(this, enum_definition, generics, item_id)
1208 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1209 // Only associated `fn`s can have `self` parameters.
1210 let self_semantic = match fk.ctxt() {
1211 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1212 _ => SelfSemantic::No,
1214 self.check_fn_decl(fk.decl(), self_semantic);
1216 self.check_c_varadic_type(fk);
1218 // Functions cannot both be `const async`
1219 if let Some(FnHeader {
1220 constness: Const::Yes(cspan),
1221 asyncness: Async::Yes { span: aspan, .. },
1227 vec![*cspan, *aspan],
1228 "functions cannot be both `const` and `async`",
1230 .span_label(*cspan, "`const` because of this")
1231 .span_label(*aspan, "`async` because of this")
1232 .span_label(span, "") // Point at the fn header.
1236 // Functions without bodies cannot have patterns.
1237 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1238 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1239 let (code, msg, label) = match ctxt {
1240 FnCtxt::Foreign => (
1242 "patterns aren't allowed in foreign function declarations",
1243 "pattern not allowed in foreign function",
1247 "patterns aren't allowed in functions without bodies",
1248 "pattern not allowed in function without body",
1251 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1252 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1255 .struct_span_err(span, msg)
1256 .span_label(span, label)
1263 visit::walk_fn(self, fk, span);
1266 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1267 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1268 self.check_defaultness(item.span, item.kind.defaultness());
1271 if ctxt == AssocCtxt::Impl {
1273 AssocItemKind::Const(_, _, body) => {
1274 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1276 AssocItemKind::Fn(_, _, _, body) => {
1277 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1279 AssocItemKind::TyAlias(_, _, bounds, body) => {
1280 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1281 self.check_type_no_bounds(bounds, "`impl`s");
1287 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1288 self.invalid_visibility(&item.vis, None);
1289 if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
1290 self.check_trait_fn_not_const(sig.header.constness);
1291 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1295 if let AssocItemKind::Const(..) = item.kind {
1296 self.check_item_named(item.ident, "const");
1299 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1303 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1304 let mut validator = AstValidator {
1307 in_trait_impl: false,
1308 has_proc_macro_decls: false,
1309 outer_impl_trait: None,
1310 bound_context: None,
1311 is_impl_trait_banned: false,
1312 is_assoc_ty_bound_banned: false,
1315 visit::walk_crate(&mut validator, krate);
1317 validator.has_proc_macro_decls