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.
11 use rustc_ast::expand::is_proc_macro_attr;
12 use rustc_ast::ptr::P;
13 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
14 use rustc_ast::walk_list;
15 use rustc_ast_pretty::pprust;
16 use rustc_data_structures::fx::FxHashMap;
17 use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
18 use rustc_parse::validate_attr;
19 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
20 use rustc_session::lint::LintBuffer;
21 use rustc_session::Session;
22 use rustc_span::symbol::{kw, sym};
26 const MORE_EXTERN: &str =
27 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
29 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
35 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
36 #[derive(Clone, Copy)]
44 fn description(&self) -> &'static str {
46 Self::ImplTrait => "`impl Trait`",
47 Self::TraitBounds => "supertraits",
48 Self::TraitObject => "trait objects",
53 struct AstValidator<'a> {
56 /// The span of the `extern` in an `extern { ... }` block, if any.
57 extern_mod: Option<&'a Item>,
59 /// Are we inside a trait impl?
62 has_proc_macro_decls: bool,
64 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
65 /// Nested `impl Trait` _is_ allowed in associated type position,
66 /// e.g., `impl Iterator<Item = impl Debug>`.
67 outer_impl_trait: Option<Span>,
69 /// Keeps track of the `BoundContext` as we recurse.
71 /// This is used to forbid `?const Trait` bounds in, e.g.,
72 /// `impl Iterator<Item = Box<dyn ?const Trait>`.
73 bound_context: Option<BoundContext>,
75 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
76 /// or `Foo::Bar<impl Trait>`
77 is_impl_trait_banned: bool,
79 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
80 /// certain positions.
81 is_assoc_ty_bound_banned: bool,
83 lint_buffer: &'a mut LintBuffer,
86 impl<'a> AstValidator<'a> {
87 fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
88 let old = mem::replace(&mut self.in_trait_impl, is_in);
90 self.in_trait_impl = old;
93 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
94 let old = mem::replace(&mut self.is_impl_trait_banned, true);
96 self.is_impl_trait_banned = old;
99 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
100 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
102 self.is_assoc_ty_bound_banned = old;
105 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
106 let old = mem::replace(&mut self.outer_impl_trait, outer);
108 self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
112 self.outer_impl_trait = old;
115 fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
116 let old = self.bound_context.replace(ctx);
118 self.bound_context = old;
121 fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
122 match constraint.kind {
123 AssocTyConstraintKind::Equality { .. } => {}
124 AssocTyConstraintKind::Bound { .. } => {
125 if self.is_assoc_ty_bound_banned {
126 self.err_handler().span_err(
128 "associated type bounds are not allowed within structs, enums, or unions",
133 self.visit_assoc_ty_constraint(constraint);
136 // Mirrors `visit::walk_ty`, but tracks relevant state.
137 fn walk_ty(&mut self, t: &'a Ty) {
139 TyKind::ImplTrait(..) => {
140 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
142 TyKind::TraitObject(..) => {
143 self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
145 TyKind::Path(ref qself, ref path) => {
147 // - `Option<impl Trait>`
148 // - `option::Option<impl Trait>`
149 // - `option::Option<T>::Foo<impl Trait>
152 // - `<impl Trait>::Foo`
153 // - `option::Option<impl Trait>::Foo`.
155 // To implement this, we disallow `impl Trait` from `qself`
156 // (for cases like `<impl Trait>::Foo>`)
157 // but we allow `impl Trait` in `GenericArgs`
158 // iff there are no more PathSegments.
159 if let Some(ref qself) = *qself {
160 // `impl Trait` in `qself` is always illegal
161 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
164 // Note that there should be a call to visit_path here,
165 // so if any logic is added to process `Path`s a call to it should be
166 // added both in visit_path and here. This code mirrors visit::walk_path.
167 for (i, segment) in path.segments.iter().enumerate() {
168 // Allow `impl Trait` iff we're on the final path segment
169 if i == path.segments.len() - 1 {
170 self.visit_path_segment(path.span, segment);
172 self.with_banned_impl_trait(|this| {
173 this.visit_path_segment(path.span, segment)
178 _ => visit::walk_ty(self, t),
182 fn err_handler(&self) -> &rustc_errors::Handler {
183 &self.session.diagnostic()
186 fn check_lifetime(&self, ident: Ident) {
187 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
188 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
189 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
193 fn check_label(&self, ident: Ident) {
194 if ident.without_first_quote().is_reserved() {
196 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
200 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
201 if let VisibilityKind::Inherited = vis.node {
206 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
207 if vis.node.is_pub() {
208 err.span_label(vis.span, "`pub` not permitted here because it's implied");
210 if let Some(note) = note {
216 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
217 for Param { pat, .. } in &decl.inputs {
219 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
220 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
221 report_err(pat.span, true)
223 _ => report_err(pat.span, false),
228 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
229 if let Async::Yes { span, .. } = asyncness {
234 "functions in traits cannot be declared `async`"
236 .span_label(span, "`async` because of this")
237 .note("`async` trait functions are not currently supported")
238 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
243 fn check_trait_fn_not_const(&self, constness: Const) {
244 if let Const::Yes(span) = constness {
249 "functions in traits cannot be declared const"
251 .span_label(span, "functions in traits cannot be const")
256 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
257 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
258 for bound in bounds {
259 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
260 let mut err = self.err_handler().struct_span_err(
262 &format!("`?Trait` is not permitted in {}", where_),
265 let path_str = pprust::path_to_string(&poly.trait_ref.path);
266 err.note(&format!("traits are `?{}` by default", path_str));
273 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
274 /// or paths for ranges.
276 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
277 // That means making this work:
279 // ```rust,ignore (FIXME)
288 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
290 ExprKind::Lit(..) | ExprKind::Err => {}
291 ExprKind::Path(..) if allow_paths => {}
292 ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
293 _ => self.err_handler().span_err(
295 "arbitrary expressions aren't allowed \
301 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
302 // Check only lifetime parameters are present and that the lifetime
303 // parameters that are present have no bounds.
304 let non_lt_param_spans: Vec<_> = params
306 .filter_map(|param| match param.kind {
307 GenericParamKind::Lifetime { .. } => {
308 if !param.bounds.is_empty() {
309 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
311 .span_err(spans, "lifetime bounds cannot be used in this context");
315 _ => Some(param.ident.span),
318 if !non_lt_param_spans.is_empty() {
319 self.err_handler().span_err(
321 "only lifetime parameters can be used in this context",
326 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
327 self.check_decl_cvaradic_pos(fn_decl);
328 self.check_decl_attrs(fn_decl);
329 self.check_decl_self_param(fn_decl, self_semantic);
332 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
333 match &*fn_decl.inputs {
334 [Param { ty, span, .. }] => {
335 if let TyKind::CVarArgs = ty.kind {
336 self.err_handler().span_err(
338 "C-variadic function must be declared with at least one named argument",
343 for Param { ty, span, .. } in ps {
344 if let TyKind::CVarArgs = ty.kind {
345 self.err_handler().span_err(
347 "`...` must be the last argument of a C-variadic function",
356 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
360 .flat_map(|i| i.attrs.as_ref())
362 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
363 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
366 if attr.is_doc_comment() {
370 "documentation comments cannot be applied to function parameters",
372 .span_label(attr.span, "doc comments are not allowed here")
375 self.err_handler().span_err(
377 "allow, cfg, cfg_attr, deny, \
378 forbid, and warn are the only allowed built-in attributes in function parameters",
384 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
385 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
390 "`self` parameter is only allowed in associated functions",
392 .span_label(param.span, "not semantically valid as function parameter")
393 .note("associated functions are those in `impl` or `trait` definitions")
399 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
400 if let Defaultness::Default(def_span) = defaultness {
401 let span = self.session.source_map().guess_head_span(span);
403 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
404 .span_label(def_span, "`default` because of this")
409 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
411 .struct_span_err(sp, msg)
413 self.session.source_map().end_point(sp),
414 &format!("provide a definition for the {}", ctx),
416 Applicability::HasPlaceholders,
421 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
423 let msg = format!("associated {} in `impl` without body", ctx);
424 self.error_item_without_body(sp, ctx, &msg, sugg);
428 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
429 let span = match bounds {
432 [b0, .., bl] => b0.span().to(bl.span()),
435 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
439 fn check_foreign_ty_genericless(&self, generics: &Generics) {
440 let cannot_have = |span, descr, remove_descr| {
444 &format!("`type`s inside `extern` blocks cannot have {}", descr),
448 &format!("remove the {}", remove_descr),
450 Applicability::MaybeIncorrect,
452 .span_label(self.current_extern_span(), "`extern` block begins here")
457 if !generics.params.is_empty() {
458 cannot_have(generics.span, "generic parameters", "generic parameters");
461 if !generics.where_clause.predicates.is_empty() {
462 cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
466 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
467 let body = match body {
472 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
473 .span_label(ident.span, "cannot have a body")
474 .span_label(body, "the invalid body")
476 self.current_extern_span(),
478 "`extern` blocks define existing foreign {0}s and {0}s \
479 inside of them cannot have a body",
487 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
488 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
489 let body = match body {
494 .struct_span_err(ident.span, "incorrect function inside `extern` block")
495 .span_label(ident.span, "cannot have a body")
498 "remove the invalid body",
500 Applicability::MaybeIncorrect,
503 "you might have meant to write a function accessible through FFI, \
504 which can be done by writing `extern fn` outside of the `extern` block",
507 self.current_extern_span(),
508 "`extern` blocks define existing foreign functions and functions \
509 inside of them cannot have a body",
515 fn current_extern_span(&self) -> Span {
516 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
519 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
520 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
521 if header.has_qualifiers() {
523 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
524 .span_label(self.current_extern_span(), "in this `extern` block")
526 span.until(ident.span.shrink_to_lo()),
527 "remove the qualifiers",
529 Applicability::MaybeIncorrect,
535 /// Reject C-varadic type unless the function is foreign,
536 /// or free and `unsafe extern "C"` semantically.
537 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
538 match (fk.ctxt(), fk.header()) {
539 (Some(FnCtxt::Foreign), _) => return,
540 (Some(FnCtxt::Free), Some(header)) => match header.ext {
541 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
542 if matches!(header.unsafety, Unsafe::Yes(_)) =>
551 for Param { ty, span, .. } in &fk.decl().inputs {
552 if let TyKind::CVarArgs = ty.kind {
556 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
563 /// We currently do not permit const generics in `const fn`,
564 /// as this is tantamount to allowing compile-time dependent typing.
566 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
567 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
568 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
569 if let Const::Yes(const_span) = sig.header.constness {
570 // Look for const generics and error if we find any.
571 for param in &generics.params {
572 if let GenericParamKind::Const { .. } = param.kind {
576 "const parameters are not permitted in const functions",
578 .span_label(const_span, "`const` because of this")
585 fn check_item_named(&self, ident: Ident, kind: &str) {
586 if ident.name != kw::Underscore {
590 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
591 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
595 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
596 if !generics.params.is_empty() {
601 "auto traits cannot have generic parameters"
603 .span_label(ident_span, "auto trait cannot have generic parameters")
606 "remove the parameters",
608 Applicability::MachineApplicable,
614 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
615 if let [first @ last] | [first, .., last] = &bounds[..] {
616 let span = first.span().to(last.span());
617 struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
618 .span_label(ident_span, "auto trait cannot have super traits")
621 "remove the super traits",
623 Applicability::MachineApplicable,
629 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
630 if !trait_items.is_empty() {
631 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
636 "auto traits cannot have methods or associated items"
638 .span_label(ident_span, "auto trait cannot have items")
643 /// Enforce generic args coming before constraints in `<...>` of a path segment.
644 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
645 // Early exit in case it's partitioned as it should be.
646 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
649 // Find all generic argument coming after the first constraint...
650 let constraint_spans = data
653 .filter_map(|arg| match arg {
654 AngleBracketedArg::Constraint(c) => Some(c.span),
657 .collect::<Vec<_>>();
661 .filter_map(|arg| match arg {
662 AngleBracketedArg::Arg(a) => Some(a.span()),
665 .collect::<Vec<_>>();
666 let snippet_span = match &constraint_spans[..] {
668 [first, .., last] => first.to(*last),
669 [] => unreachable!(),
671 let removal_span = match &arg_spans[..] {
672 [first, ..] => snippet_span.until(*first),
673 [] => unreachable!(),
675 let sugg_span = match &arg_spans[..] {
676 [.., last] => last.shrink_to_hi(),
677 [] => unreachable!(),
679 let snippet = self.session.source_map().span_to_snippet(snippet_span).unwrap();
680 let constraint_len = constraint_spans.len();
681 // ...and then error:
685 "generic arguments must come before the first constraint",
690 "the constraint{} {} provided here",
691 pluralize!(constraint_len),
692 if constraint_len == 1 { "is" } else { "are" }
695 .span_labels(arg_spans, "generic argument")
696 .multipart_suggestion(
697 "move the constraints after the generic arguments",
699 (removal_span, String::new()),
700 (sugg_span.shrink_to_lo(), ", ".to_string()),
701 (sugg_span, snippet),
703 Applicability::MachineApplicable,
709 /// Checks that generic parameters are in the correct order,
710 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
711 fn validate_generic_param_order<'a>(
713 handler: &rustc_errors::Handler,
714 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
717 let mut max_param: Option<ParamKindOrd> = None;
718 let mut out_of_order = FxHashMap::default();
719 let mut param_idents = vec![];
721 for (kind, bounds, span, ident) in generics {
722 if let Some(ident) = ident {
723 param_idents.push((kind, bounds, param_idents.len(), ident));
725 let max_param = &mut max_param;
727 Some(max_param) if *max_param > kind => {
728 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
731 Some(_) | None => *max_param = Some(kind),
735 let mut ordered_params = "<".to_string();
736 if !out_of_order.is_empty() {
737 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
738 let mut first = true;
739 for (_, bounds, _, ident) in param_idents {
741 ordered_params += ", ";
743 ordered_params += &ident;
744 if let Some(bounds) = bounds {
745 if !bounds.is_empty() {
746 ordered_params += ": ";
747 ordered_params += &pprust::bounds_to_string(&bounds);
753 ordered_params += ">";
755 for (param_ord, (max_param, spans)) in &out_of_order {
757 handler.struct_span_err(
760 "{} parameters must be declared prior to {} parameters",
761 param_ord, max_param,
767 "reorder the parameters: lifetimes, then types{}",
768 if sess.features_untracked().const_generics { ", then consts" } else { "" },
770 ordered_params.clone(),
771 Applicability::MachineApplicable,
777 impl<'a> Visitor<'a> for AstValidator<'a> {
778 fn visit_attribute(&mut self, attr: &Attribute) {
779 validate_attr::check_meta(&self.session.parse_sess, attr);
782 fn visit_expr(&mut self, expr: &'a Expr) {
784 ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => {
789 "llvm_asm! is unsupported on this target"
796 visit::walk_expr(self, expr);
799 fn visit_ty(&mut self, ty: &'a Ty) {
801 TyKind::BareFn(ref bfty) => {
802 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
803 Self::check_decl_no_pat(&bfty.decl, |span, _| {
808 "patterns aren't allowed in function pointer types"
812 self.check_late_bound_lifetime_defs(&bfty.generic_params);
814 TyKind::TraitObject(ref bounds, ..) => {
815 let mut any_lifetime_bounds = false;
816 for bound in bounds {
817 if let GenericBound::Outlives(ref lifetime) = *bound {
818 if any_lifetime_bounds {
823 "only a single explicit lifetime bound is permitted"
828 any_lifetime_bounds = true;
831 self.no_questions_in_bounds(bounds, "trait object types", false);
833 TyKind::ImplTrait(_, ref bounds) => {
834 if self.is_impl_trait_banned {
839 "`impl Trait` is not allowed in path parameters"
844 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
849 "nested `impl Trait` is not allowed"
851 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
852 .span_label(ty.span, "nested `impl Trait` here")
858 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
860 self.err_handler().span_err(ty.span, "at least one trait must be specified");
872 fn visit_label(&mut self, label: &'a Label) {
873 self.check_label(label.ident);
874 visit::walk_label(self, label);
877 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
878 self.check_lifetime(lifetime.ident);
879 visit::walk_lifetime(self, lifetime);
882 fn visit_item(&mut self, item: &'a Item) {
883 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
884 self.has_proc_macro_decls = true;
894 of_trait: Some(ref t),
898 self.with_in_trait_impl(true, |this| {
899 this.invalid_visibility(&item.vis, None);
900 if let TyKind::Err = self_ty.kind {
904 "`impl Trait for .. {}` is an obsolete syntax",
906 .help("use `auto trait Trait {}` instead")
909 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
914 "negative impls cannot be unsafe"
916 .span_label(sp, "negative because of this")
917 .span_label(span, "unsafe because of this")
921 visit::walk_item(this, item);
923 return; // Avoid visiting again.
935 let error = |annotation_span, annotation| {
936 let mut err = self.err_handler().struct_span_err(
938 &format!("inherent impls cannot be {}", annotation),
940 err.span_label(annotation_span, &format!("{} because of this", annotation));
941 err.span_label(self_ty.span, "inherent impl for this type");
945 self.invalid_visibility(
947 Some("place qualifiers on individual impl items instead"),
949 if let Unsafe::Yes(span) = unsafety {
950 error(span, "unsafe").code(error_code!(E0197)).emit();
952 if let ImplPolarity::Negative(span) = polarity {
953 error(span, "negative").emit();
955 if let Defaultness::Default(def_span) = defaultness {
956 error(def_span, "`default`")
957 .note("only trait implementations may be annotated with `default`")
960 if let Const::Yes(span) = constness {
961 error(span, "`const`")
962 .note("only trait implementations may be annotated with `const`")
966 ItemKind::Fn(def, ref sig, ref generics, ref body) => {
967 self.check_defaultness(item.span, def);
968 self.check_const_fn_const_generic(item.span, sig, generics);
971 let msg = "free function without a body";
972 self.error_item_without_body(item.span, "function", msg, " { <body> }");
975 ItemKind::ForeignMod(_) => {
976 let old_item = mem::replace(&mut self.extern_mod, Some(item));
977 self.invalid_visibility(
979 Some("place qualifiers on individual foreign items instead"),
981 visit::walk_item(self, item);
982 self.extern_mod = old_item;
983 return; // Avoid visiting again.
985 ItemKind::Enum(ref def, _) => {
986 for variant in &def.variants {
987 self.invalid_visibility(&variant.vis, None);
988 for field in variant.data.fields() {
989 self.invalid_visibility(&field.vis, None);
993 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
994 if is_auto == IsAuto::Yes {
995 // Auto traits cannot have generics, super traits nor contain items.
996 self.deny_generic_params(generics, item.ident.span);
997 self.deny_super_traits(bounds, item.ident.span);
998 self.deny_items(trait_items, item.ident.span);
1000 self.no_questions_in_bounds(bounds, "supertraits", true);
1002 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1003 // context for the supertraits.
1004 self.visit_vis(&item.vis);
1005 self.visit_ident(item.ident);
1006 self.visit_generics(generics);
1007 self.with_bound_context(BoundContext::TraitBounds, |this| {
1008 walk_list!(this, visit_param_bound, bounds);
1010 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
1011 walk_list!(self, visit_attribute, &item.attrs);
1014 ItemKind::Mod(_) => {
1015 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1016 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
1018 ItemKind::Union(ref vdata, _) => {
1019 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
1021 .span_err(item.span, "tuple and unit unions are not permitted");
1023 if vdata.fields().is_empty() {
1024 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1027 ItemKind::Const(def, .., None) => {
1028 self.check_defaultness(item.span, def);
1029 let msg = "free constant item without body";
1030 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1032 ItemKind::Static(.., None) => {
1033 let msg = "free static item without body";
1034 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1036 ItemKind::TyAlias(def, _, ref bounds, ref body) => {
1037 self.check_defaultness(item.span, def);
1039 let msg = "free type alias without body";
1040 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1042 self.check_type_no_bounds(bounds, "this context");
1047 visit::walk_item(self, item)
1050 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1052 ForeignItemKind::Fn(def, sig, _, body) => {
1053 self.check_defaultness(fi.span, *def);
1054 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1055 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1057 ForeignItemKind::TyAlias(def, generics, bounds, body) => {
1058 self.check_defaultness(fi.span, *def);
1059 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1060 self.check_type_no_bounds(bounds, "`extern` blocks");
1061 self.check_foreign_ty_genericless(generics);
1063 ForeignItemKind::Static(_, _, body) => {
1064 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1066 ForeignItemKind::MacCall(..) => {}
1069 visit::walk_foreign_item(self, fi)
1072 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1073 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1074 match *generic_args {
1075 GenericArgs::AngleBracketed(ref data) => {
1076 self.check_generic_args_before_constraints(data);
1078 for arg in &data.args {
1080 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1081 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1082 // are allowed to contain nested `impl Trait`.
1083 AngleBracketedArg::Constraint(constraint) => {
1084 self.with_impl_trait(None, |this| {
1085 this.visit_assoc_ty_constraint_from_generic_args(constraint);
1091 GenericArgs::Parenthesized(ref data) => {
1092 walk_list!(self, visit_ty, &data.inputs);
1093 if let FnRetTy::Ty(ty) = &data.output {
1094 // `-> Foo` syntax is essentially an associated type binding,
1095 // so it is also allowed to contain nested `impl Trait`.
1096 self.with_impl_trait(None, |this| this.visit_ty(ty));
1102 fn visit_generics(&mut self, generics: &'a Generics) {
1103 let mut prev_ty_default = None;
1104 for param in &generics.params {
1105 if let GenericParamKind::Type { ref default, .. } = param.kind {
1106 if default.is_some() {
1107 prev_ty_default = Some(param.ident.span);
1108 } else if let Some(span) = prev_ty_default {
1110 .span_err(span, "type parameters with a default must be trailing");
1116 validate_generic_param_order(
1119 generics.params.iter().map(|param| {
1120 let ident = Some(param.ident.to_string());
1121 let (kind, ident) = match ¶m.kind {
1122 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1123 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1124 GenericParamKind::Const { ref ty } => {
1125 let ty = pprust::ty_to_string(ty);
1126 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1129 (kind, Some(&*param.bounds), param.ident.span, ident)
1134 for predicate in &generics.where_clause.predicates {
1135 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1139 "equality constraints are not yet supported in `where` clauses",
1141 .span_label(predicate.span, "not supported")
1143 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1144 for more information",
1150 visit::walk_generics(self, generics)
1153 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1154 if let GenericParamKind::Lifetime { .. } = param.kind {
1155 self.check_lifetime(param.ident);
1157 visit::walk_generic_param(self, param);
1160 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1162 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1163 if let Some(ctx) = self.bound_context {
1164 let msg = format!("`?const` is not permitted in {}", ctx.description());
1165 self.err_handler().span_err(bound.span(), &msg);
1169 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1171 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1177 visit::walk_param_bound(self, bound)
1180 fn visit_pat(&mut self, pat: &'a Pat) {
1182 PatKind::Lit(ref expr) => {
1183 self.check_expr_within_pat(expr, false);
1185 PatKind::Range(ref start, ref end, _) => {
1186 if let Some(expr) = start {
1187 self.check_expr_within_pat(expr, true);
1189 if let Some(expr) = end {
1190 self.check_expr_within_pat(expr, true);
1196 visit::walk_pat(self, pat)
1199 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1200 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1201 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1202 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1204 visit::walk_where_predicate(self, p);
1207 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1208 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1209 visit::walk_poly_trait_ref(self, t, m);
1212 fn visit_variant_data(&mut self, s: &'a VariantData) {
1213 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1218 enum_definition: &'a EnumDef,
1219 generics: &'a Generics,
1223 self.with_banned_assoc_ty_bound(|this| {
1224 visit::walk_enum_def(this, enum_definition, generics, item_id)
1228 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1229 // Only associated `fn`s can have `self` parameters.
1230 let self_semantic = match fk.ctxt() {
1231 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1232 _ => SelfSemantic::No,
1234 self.check_fn_decl(fk.decl(), self_semantic);
1236 self.check_c_varadic_type(fk);
1238 // Functions cannot both be `const async`
1239 if let Some(FnHeader {
1240 constness: Const::Yes(cspan),
1241 asyncness: Async::Yes { span: aspan, .. },
1247 vec![*cspan, *aspan],
1248 "functions cannot be both `const` and `async`",
1250 .span_label(*cspan, "`const` because of this")
1251 .span_label(*aspan, "`async` because of this")
1252 .span_label(span, "") // Point at the fn header.
1256 // Functions without bodies cannot have patterns.
1257 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1258 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1259 let (code, msg, label) = match ctxt {
1260 FnCtxt::Foreign => (
1262 "patterns aren't allowed in foreign function declarations",
1263 "pattern not allowed in foreign function",
1267 "patterns aren't allowed in functions without bodies",
1268 "pattern not allowed in function without body",
1271 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1272 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1275 .struct_span_err(span, msg)
1276 .span_label(span, label)
1283 visit::walk_fn(self, fk, span);
1286 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1287 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1288 self.check_defaultness(item.span, item.kind.defaultness());
1291 if ctxt == AssocCtxt::Impl {
1293 AssocItemKind::Const(_, _, body) => {
1294 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1296 AssocItemKind::Fn(_, _, _, body) => {
1297 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1299 AssocItemKind::TyAlias(_, _, bounds, body) => {
1300 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1301 self.check_type_no_bounds(bounds, "`impl`s");
1307 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1308 self.invalid_visibility(&item.vis, None);
1309 if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
1310 self.check_trait_fn_not_const(sig.header.constness);
1311 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1315 if let AssocItemKind::Const(..) = item.kind {
1316 self.check_item_named(item.ident, "const");
1319 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1323 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1324 let mut validator = AstValidator {
1327 in_trait_impl: false,
1328 has_proc_macro_decls: false,
1329 outer_impl_trait: None,
1330 bound_context: None,
1331 is_impl_trait_banned: false,
1332 is_assoc_ty_bound_banned: false,
1335 visit::walk_crate(&mut validator, krate);
1337 validator.has_proc_macro_decls