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, Ident};
26 use std::ops::DerefMut;
28 const MORE_EXTERN: &str =
29 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
31 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
37 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
38 #[derive(Clone, Copy)]
46 fn description(&self) -> &'static str {
48 Self::ImplTrait => "`impl Trait`",
49 Self::TraitBounds => "supertraits",
50 Self::TraitObject => "trait objects",
55 struct AstValidator<'a> {
58 /// The span of the `extern` in an `extern { ... }` block, if any.
59 extern_mod: Option<&'a Item>,
61 /// Are we inside a trait impl?
64 has_proc_macro_decls: bool,
66 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
67 /// Nested `impl Trait` _is_ allowed in associated type position,
68 /// e.g., `impl Iterator<Item = impl Debug>`.
69 outer_impl_trait: Option<Span>,
71 /// Keeps track of the `BoundContext` as we recurse.
73 /// This is used to forbid `?const Trait` bounds in, e.g.,
74 /// `impl Iterator<Item = Box<dyn ?const Trait>`.
75 bound_context: Option<BoundContext>,
77 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
78 /// or `Foo::Bar<impl Trait>`
79 is_impl_trait_banned: bool,
81 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
82 /// certain positions.
83 is_assoc_ty_bound_banned: bool,
85 lint_buffer: &'a mut LintBuffer,
88 impl<'a> AstValidator<'a> {
89 fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
90 let old = mem::replace(&mut self.in_trait_impl, is_in);
92 self.in_trait_impl = old;
95 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
96 let old = mem::replace(&mut self.is_impl_trait_banned, true);
98 self.is_impl_trait_banned = old;
101 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
102 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
104 self.is_assoc_ty_bound_banned = old;
107 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
108 let old = mem::replace(&mut self.outer_impl_trait, outer);
110 self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
114 self.outer_impl_trait = old;
117 fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
118 let old = self.bound_context.replace(ctx);
120 self.bound_context = old;
123 fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
124 match constraint.kind {
125 AssocTyConstraintKind::Equality { .. } => {}
126 AssocTyConstraintKind::Bound { .. } => {
127 if self.is_assoc_ty_bound_banned {
128 self.err_handler().span_err(
130 "associated type bounds are not allowed within structs, enums, or unions",
135 self.visit_assoc_ty_constraint(constraint);
138 // Mirrors `visit::walk_ty`, but tracks relevant state.
139 fn walk_ty(&mut self, t: &'a Ty) {
141 TyKind::ImplTrait(..) => {
142 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
144 TyKind::TraitObject(..) => {
145 self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
147 TyKind::Path(ref qself, ref path) => {
149 // - `Option<impl Trait>`
150 // - `option::Option<impl Trait>`
151 // - `option::Option<T>::Foo<impl Trait>
154 // - `<impl Trait>::Foo`
155 // - `option::Option<impl Trait>::Foo`.
157 // To implement this, we disallow `impl Trait` from `qself`
158 // (for cases like `<impl Trait>::Foo>`)
159 // but we allow `impl Trait` in `GenericArgs`
160 // iff there are no more PathSegments.
161 if let Some(ref qself) = *qself {
162 // `impl Trait` in `qself` is always illegal
163 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
166 // Note that there should be a call to visit_path here,
167 // so if any logic is added to process `Path`s a call to it should be
168 // added both in visit_path and here. This code mirrors visit::walk_path.
169 for (i, segment) in path.segments.iter().enumerate() {
170 // Allow `impl Trait` iff we're on the final path segment
171 if i == path.segments.len() - 1 {
172 self.visit_path_segment(path.span, segment);
174 self.with_banned_impl_trait(|this| {
175 this.visit_path_segment(path.span, segment)
180 _ => visit::walk_ty(self, t),
184 fn err_handler(&self) -> &rustc_errors::Handler {
185 &self.session.diagnostic()
188 fn check_lifetime(&self, ident: Ident) {
189 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
190 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
191 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
195 fn check_label(&self, ident: Ident) {
196 if ident.without_first_quote().is_reserved() {
198 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
202 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
203 if let VisibilityKind::Inherited = vis.node {
208 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
209 if vis.node.is_pub() {
210 err.span_label(vis.span, "`pub` not permitted here because it's implied");
212 if let Some(note) = note {
218 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
219 for Param { pat, .. } in &decl.inputs {
221 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
222 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
223 report_err(pat.span, true)
225 _ => report_err(pat.span, false),
230 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
231 if let Async::Yes { span, .. } = asyncness {
236 "functions in traits cannot be declared `async`"
238 .span_label(span, "`async` because of this")
239 .note("`async` trait functions are not currently supported")
240 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
245 fn check_trait_fn_not_const(&self, constness: Const) {
246 if let Const::Yes(span) = constness {
251 "functions in traits cannot be declared const"
253 .span_label(span, "functions in traits cannot be const")
258 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
259 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
260 for bound in bounds {
261 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
262 let mut err = self.err_handler().struct_span_err(
264 &format!("`?Trait` is not permitted in {}", where_),
267 let path_str = pprust::path_to_string(&poly.trait_ref.path);
268 err.note(&format!("traits are `?{}` by default", path_str));
275 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
276 /// or paths for ranges.
278 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
279 // That means making this work:
281 // ```rust,ignore (FIXME)
290 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
292 ExprKind::Lit(..) | ExprKind::Err => {}
293 ExprKind::Path(..) if allow_paths => {}
294 ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
295 _ => self.err_handler().span_err(
297 "arbitrary expressions aren't allowed \
303 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
304 // Check only lifetime parameters are present and that the lifetime
305 // parameters that are present have no bounds.
306 let non_lt_param_spans: Vec<_> = params
308 .filter_map(|param| match param.kind {
309 GenericParamKind::Lifetime { .. } => {
310 if !param.bounds.is_empty() {
311 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
313 .span_err(spans, "lifetime bounds cannot be used in this context");
317 _ => Some(param.ident.span),
320 if !non_lt_param_spans.is_empty() {
321 self.err_handler().span_err(
323 "only lifetime parameters can be used in this context",
328 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
329 self.check_decl_cvaradic_pos(fn_decl);
330 self.check_decl_attrs(fn_decl);
331 self.check_decl_self_param(fn_decl, self_semantic);
334 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
335 match &*fn_decl.inputs {
336 [Param { ty, span, .. }] => {
337 if let TyKind::CVarArgs = ty.kind {
338 self.err_handler().span_err(
340 "C-variadic function must be declared with at least one named argument",
345 for Param { ty, span, .. } in ps {
346 if let TyKind::CVarArgs = ty.kind {
347 self.err_handler().span_err(
349 "`...` must be the last argument of a C-variadic function",
358 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
362 .flat_map(|i| i.attrs.as_ref())
364 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
365 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
368 if attr.is_doc_comment() {
372 "documentation comments cannot be applied to function parameters",
374 .span_label(attr.span, "doc comments are not allowed here")
377 self.err_handler().span_err(
379 "allow, cfg, cfg_attr, deny, \
380 forbid, and warn are the only allowed built-in attributes in function parameters",
386 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
387 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
392 "`self` parameter is only allowed in associated functions",
394 .span_label(param.span, "not semantically valid as function parameter")
395 .note("associated functions are those in `impl` or `trait` definitions")
401 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
402 if let Defaultness::Default(def_span) = defaultness {
403 let span = self.session.source_map().guess_head_span(span);
405 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
406 .span_label(def_span, "`default` because of this")
411 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
413 .struct_span_err(sp, msg)
415 self.session.source_map().end_point(sp),
416 &format!("provide a definition for the {}", ctx),
418 Applicability::HasPlaceholders,
423 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
425 let msg = format!("associated {} in `impl` without body", ctx);
426 self.error_item_without_body(sp, ctx, &msg, sugg);
430 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
431 let span = match bounds {
434 [b0, .., bl] => b0.span().to(bl.span()),
437 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
441 fn check_foreign_ty_genericless(&self, generics: &Generics) {
442 let cannot_have = |span, descr, remove_descr| {
446 &format!("`type`s inside `extern` blocks cannot have {}", descr),
450 &format!("remove the {}", remove_descr),
452 Applicability::MaybeIncorrect,
454 .span_label(self.current_extern_span(), "`extern` block begins here")
459 if !generics.params.is_empty() {
460 cannot_have(generics.span, "generic parameters", "generic parameters");
463 if !generics.where_clause.predicates.is_empty() {
464 cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
468 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
469 let body = match body {
474 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
475 .span_label(ident.span, "cannot have a body")
476 .span_label(body, "the invalid body")
478 self.current_extern_span(),
480 "`extern` blocks define existing foreign {0}s and {0}s \
481 inside of them cannot have a body",
489 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
490 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
491 let body = match body {
496 .struct_span_err(ident.span, "incorrect function inside `extern` block")
497 .span_label(ident.span, "cannot have a body")
500 "remove the invalid body",
502 Applicability::MaybeIncorrect,
505 "you might have meant to write a function accessible through FFI, \
506 which can be done by writing `extern fn` outside of the `extern` block",
509 self.current_extern_span(),
510 "`extern` blocks define existing foreign functions and functions \
511 inside of them cannot have a body",
517 fn current_extern_span(&self) -> Span {
518 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
521 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
522 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
523 if header.has_qualifiers() {
525 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
526 .span_label(self.current_extern_span(), "in this `extern` block")
528 span.until(ident.span.shrink_to_lo()),
529 "remove the qualifiers",
531 Applicability::MaybeIncorrect,
537 /// Reject C-varadic type unless the function is foreign,
538 /// or free and `unsafe extern "C"` semantically.
539 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
540 match (fk.ctxt(), fk.header()) {
541 (Some(FnCtxt::Foreign), _) => return,
542 (Some(FnCtxt::Free), Some(header)) => match header.ext {
543 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
544 if matches!(header.unsafety, Unsafe::Yes(_)) =>
553 for Param { ty, span, .. } in &fk.decl().inputs {
554 if let TyKind::CVarArgs = ty.kind {
558 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
565 fn check_item_named(&self, ident: Ident, kind: &str) {
566 if ident.name != kw::Underscore {
570 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
571 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
575 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
576 if ident.name.as_str().is_ascii() {
579 let head_span = self.session.source_map().guess_head_span(item_span);
584 "`#[no_mangle]` requires ASCII identifier"
589 fn check_mod_file_item_asciionly(&self, ident: Ident) {
590 if ident.name.as_str().is_ascii() {
597 "trying to load file for module `{}` with non ascii identifer name",
600 .help("consider using `#[path]` attribute to specify filesystem path")
604 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
605 if !generics.params.is_empty() {
610 "auto traits cannot have generic parameters"
612 .span_label(ident_span, "auto trait cannot have generic parameters")
615 "remove the parameters",
617 Applicability::MachineApplicable,
623 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
624 if let [first @ last] | [first, .., last] = &bounds[..] {
625 let span = first.span().to(last.span());
626 struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
627 .span_label(ident_span, "auto trait cannot have super traits")
630 "remove the super traits",
632 Applicability::MachineApplicable,
638 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
639 if !trait_items.is_empty() {
640 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
645 "auto traits cannot have methods or associated items"
647 .span_label(ident_span, "auto trait cannot have items")
652 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
653 // Lifetimes always come first.
654 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
655 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
656 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
660 let args_sugg = data.args.iter().filter_map(|a| match a {
661 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
664 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
666 // Constraints always come last.
667 let constraint_sugg = data.args.iter().filter_map(|a| match a {
668 AngleBracketedArg::Arg(_) => None,
669 AngleBracketedArg::Constraint(c) => {
670 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
675 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
679 /// Enforce generic args coming before constraints in `<...>` of a path segment.
680 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
681 // Early exit in case it's partitioned as it should be.
682 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
685 // Find all generic argument coming after the first constraint...
686 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
687 data.args.iter().partition_map(|arg| match arg {
688 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
689 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
691 let args_len = arg_spans.len();
692 let constraint_len = constraint_spans.len();
693 // ...and then error:
697 "generic arguments must come before the first constraint",
699 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
701 *arg_spans.iter().last().unwrap(),
702 &format!("generic argument{}", pluralize!(args_len)),
704 .span_labels(constraint_spans, "")
705 .span_labels(arg_spans, "")
706 .span_suggestion_verbose(
709 "move the constraint{} after the generic argument{}",
710 pluralize!(constraint_len),
713 self.correct_generic_order_suggestion(&data),
714 Applicability::MachineApplicable,
720 /// Checks that generic parameters are in the correct order,
721 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
722 fn validate_generic_param_order<'a>(
724 handler: &rustc_errors::Handler,
725 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
728 let mut max_param: Option<ParamKindOrd> = None;
729 let mut out_of_order = FxHashMap::default();
730 let mut param_idents = vec![];
732 for (kind, bounds, span, ident) in generics {
733 if let Some(ident) = ident {
734 param_idents.push((kind, bounds, param_idents.len(), ident));
736 let max_param = &mut max_param;
738 Some(max_param) if *max_param > kind => {
739 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
742 Some(_) | None => *max_param = Some(kind),
746 let mut ordered_params = "<".to_string();
747 if !out_of_order.is_empty() {
748 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
749 let mut first = true;
750 for (_, bounds, _, ident) in param_idents {
752 ordered_params += ", ";
754 ordered_params += &ident;
755 if let Some(bounds) = bounds {
756 if !bounds.is_empty() {
757 ordered_params += ": ";
758 ordered_params += &pprust::bounds_to_string(&bounds);
764 ordered_params += ">";
766 for (param_ord, (max_param, spans)) in &out_of_order {
768 handler.struct_span_err(
771 "{} parameters must be declared prior to {} parameters",
772 param_ord, max_param,
778 "reorder the parameters: lifetimes, then types{}",
779 if sess.features_untracked().const_generics { ", then consts" } else { "" },
781 ordered_params.clone(),
782 Applicability::MachineApplicable,
788 impl<'a> Visitor<'a> for AstValidator<'a> {
789 fn visit_attribute(&mut self, attr: &Attribute) {
790 validate_attr::check_meta(&self.session.parse_sess, attr);
793 fn visit_expr(&mut self, expr: &'a Expr) {
795 ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => {
800 "llvm_asm! is unsupported on this target"
807 visit::walk_expr(self, expr);
810 fn visit_ty(&mut self, ty: &'a Ty) {
812 TyKind::BareFn(ref bfty) => {
813 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
814 Self::check_decl_no_pat(&bfty.decl, |span, _| {
819 "patterns aren't allowed in function pointer types"
823 self.check_late_bound_lifetime_defs(&bfty.generic_params);
825 TyKind::TraitObject(ref bounds, ..) => {
826 let mut any_lifetime_bounds = false;
827 for bound in bounds {
828 if let GenericBound::Outlives(ref lifetime) = *bound {
829 if any_lifetime_bounds {
834 "only a single explicit lifetime bound is permitted"
839 any_lifetime_bounds = true;
842 self.no_questions_in_bounds(bounds, "trait object types", false);
844 TyKind::ImplTrait(_, ref bounds) => {
845 if self.is_impl_trait_banned {
850 "`impl Trait` is not allowed in path parameters"
855 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
860 "nested `impl Trait` is not allowed"
862 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
863 .span_label(ty.span, "nested `impl Trait` here")
869 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
871 self.err_handler().span_err(ty.span, "at least one trait must be specified");
883 fn visit_label(&mut self, label: &'a Label) {
884 self.check_label(label.ident);
885 visit::walk_label(self, label);
888 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
889 self.check_lifetime(lifetime.ident);
890 visit::walk_lifetime(self, lifetime);
893 fn visit_item(&mut self, item: &'a Item) {
894 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
895 self.has_proc_macro_decls = true;
898 if attr::contains_name(&item.attrs, sym::no_mangle) {
899 self.check_nomangle_item_asciionly(item.ident, item.span);
909 of_trait: Some(ref t),
913 self.with_in_trait_impl(true, |this| {
914 this.invalid_visibility(&item.vis, None);
915 if let TyKind::Err = self_ty.kind {
919 "`impl Trait for .. {}` is an obsolete syntax",
921 .help("use `auto trait Trait {}` instead")
924 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
929 "negative impls cannot be unsafe"
931 .span_label(sp, "negative because of this")
932 .span_label(span, "unsafe because of this")
936 visit::walk_item(this, item);
938 return; // Avoid visiting again.
950 let error = |annotation_span, annotation| {
951 let mut err = self.err_handler().struct_span_err(
953 &format!("inherent impls cannot be {}", annotation),
955 err.span_label(annotation_span, &format!("{} because of this", annotation));
956 err.span_label(self_ty.span, "inherent impl for this type");
960 self.invalid_visibility(
962 Some("place qualifiers on individual impl items instead"),
964 if let Unsafe::Yes(span) = unsafety {
965 error(span, "unsafe").code(error_code!(E0197)).emit();
967 if let ImplPolarity::Negative(span) = polarity {
968 error(span, "negative").emit();
970 if let Defaultness::Default(def_span) = defaultness {
971 error(def_span, "`default`")
972 .note("only trait implementations may be annotated with `default`")
975 if let Const::Yes(span) = constness {
976 error(span, "`const`")
977 .note("only trait implementations may be annotated with `const`")
981 ItemKind::Fn(def, _, _, ref body) => {
982 self.check_defaultness(item.span, def);
985 let msg = "free function without a body";
986 self.error_item_without_body(item.span, "function", msg, " { <body> }");
989 ItemKind::ForeignMod(_) => {
990 let old_item = mem::replace(&mut self.extern_mod, Some(item));
991 self.invalid_visibility(
993 Some("place qualifiers on individual foreign items instead"),
995 visit::walk_item(self, item);
996 self.extern_mod = old_item;
997 return; // Avoid visiting again.
999 ItemKind::Enum(ref def, _) => {
1000 for variant in &def.variants {
1001 self.invalid_visibility(&variant.vis, None);
1002 for field in variant.data.fields() {
1003 self.invalid_visibility(&field.vis, None);
1007 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
1008 if is_auto == IsAuto::Yes {
1009 // Auto traits cannot have generics, super traits nor contain items.
1010 self.deny_generic_params(generics, item.ident.span);
1011 self.deny_super_traits(bounds, item.ident.span);
1012 self.deny_items(trait_items, item.ident.span);
1014 self.no_questions_in_bounds(bounds, "supertraits", true);
1016 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1017 // context for the supertraits.
1018 self.visit_vis(&item.vis);
1019 self.visit_ident(item.ident);
1020 self.visit_generics(generics);
1021 self.with_bound_context(BoundContext::TraitBounds, |this| {
1022 walk_list!(this, visit_param_bound, bounds);
1024 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
1025 walk_list!(self, visit_attribute, &item.attrs);
1028 ItemKind::Mod(Mod { inline, .. }) => {
1029 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1030 if !inline && !attr::contains_name(&item.attrs, sym::path) {
1031 self.check_mod_file_item_asciionly(item.ident);
1034 ItemKind::Union(ref vdata, _) => {
1035 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
1037 .span_err(item.span, "tuple and unit unions are not permitted");
1039 if vdata.fields().is_empty() {
1040 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1043 ItemKind::Const(def, .., None) => {
1044 self.check_defaultness(item.span, def);
1045 let msg = "free constant item without body";
1046 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1048 ItemKind::Static(.., None) => {
1049 let msg = "free static item without body";
1050 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1052 ItemKind::TyAlias(def, _, ref bounds, ref body) => {
1053 self.check_defaultness(item.span, def);
1055 let msg = "free type alias without body";
1056 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1058 self.check_type_no_bounds(bounds, "this context");
1063 visit::walk_item(self, item)
1066 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1068 ForeignItemKind::Fn(def, sig, _, body) => {
1069 self.check_defaultness(fi.span, *def);
1070 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1071 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1073 ForeignItemKind::TyAlias(def, generics, bounds, body) => {
1074 self.check_defaultness(fi.span, *def);
1075 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1076 self.check_type_no_bounds(bounds, "`extern` blocks");
1077 self.check_foreign_ty_genericless(generics);
1079 ForeignItemKind::Static(_, _, body) => {
1080 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1082 ForeignItemKind::MacCall(..) => {}
1085 visit::walk_foreign_item(self, fi)
1088 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1089 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1090 match *generic_args {
1091 GenericArgs::AngleBracketed(ref data) => {
1092 self.check_generic_args_before_constraints(data);
1094 for arg in &data.args {
1096 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1097 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1098 // are allowed to contain nested `impl Trait`.
1099 AngleBracketedArg::Constraint(constraint) => {
1100 self.with_impl_trait(None, |this| {
1101 this.visit_assoc_ty_constraint_from_generic_args(constraint);
1107 GenericArgs::Parenthesized(ref data) => {
1108 walk_list!(self, visit_ty, &data.inputs);
1109 if let FnRetTy::Ty(ty) = &data.output {
1110 // `-> Foo` syntax is essentially an associated type binding,
1111 // so it is also allowed to contain nested `impl Trait`.
1112 self.with_impl_trait(None, |this| this.visit_ty(ty));
1118 fn visit_generics(&mut self, generics: &'a Generics) {
1119 let mut prev_ty_default = None;
1120 for param in &generics.params {
1121 if let GenericParamKind::Type { ref default, .. } = param.kind {
1122 if default.is_some() {
1123 prev_ty_default = Some(param.ident.span);
1124 } else if let Some(span) = prev_ty_default {
1126 .span_err(span, "type parameters with a default must be trailing");
1132 validate_generic_param_order(
1135 generics.params.iter().map(|param| {
1136 let ident = Some(param.ident.to_string());
1137 let (kind, ident) = match ¶m.kind {
1138 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
1139 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
1140 GenericParamKind::Const { ref ty, kw_span: _ } => {
1141 let ty = pprust::ty_to_string(ty);
1142 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1145 (kind, Some(&*param.bounds), param.ident.span, ident)
1150 for predicate in &generics.where_clause.predicates {
1151 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1152 deny_equality_constraints(self, predicate, generics);
1156 visit::walk_generics(self, generics)
1159 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1160 if let GenericParamKind::Lifetime { .. } = param.kind {
1161 self.check_lifetime(param.ident);
1163 visit::walk_generic_param(self, param);
1166 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1168 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1169 if let Some(ctx) = self.bound_context {
1170 let msg = format!("`?const` is not permitted in {}", ctx.description());
1171 self.err_handler().span_err(bound.span(), &msg);
1175 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1177 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1183 visit::walk_param_bound(self, bound)
1186 fn visit_pat(&mut self, pat: &'a Pat) {
1188 PatKind::Lit(ref expr) => {
1189 self.check_expr_within_pat(expr, false);
1191 PatKind::Range(ref start, ref end, _) => {
1192 if let Some(expr) = start {
1193 self.check_expr_within_pat(expr, true);
1195 if let Some(expr) = end {
1196 self.check_expr_within_pat(expr, true);
1202 visit::walk_pat(self, pat)
1205 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1206 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1207 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1208 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1210 visit::walk_where_predicate(self, p);
1213 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1214 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1215 visit::walk_poly_trait_ref(self, t, m);
1218 fn visit_variant_data(&mut self, s: &'a VariantData) {
1219 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1224 enum_definition: &'a EnumDef,
1225 generics: &'a Generics,
1229 self.with_banned_assoc_ty_bound(|this| {
1230 visit::walk_enum_def(this, enum_definition, generics, item_id)
1234 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1235 // Only associated `fn`s can have `self` parameters.
1236 let self_semantic = match fk.ctxt() {
1237 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1238 _ => SelfSemantic::No,
1240 self.check_fn_decl(fk.decl(), self_semantic);
1242 self.check_c_varadic_type(fk);
1244 // Functions cannot both be `const async`
1245 if let Some(FnHeader {
1246 constness: Const::Yes(cspan),
1247 asyncness: Async::Yes { span: aspan, .. },
1253 vec![*cspan, *aspan],
1254 "functions cannot be both `const` and `async`",
1256 .span_label(*cspan, "`const` because of this")
1257 .span_label(*aspan, "`async` because of this")
1258 .span_label(span, "") // Point at the fn header.
1262 // Functions without bodies cannot have patterns.
1263 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1264 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1265 let (code, msg, label) = match ctxt {
1266 FnCtxt::Foreign => (
1268 "patterns aren't allowed in foreign function declarations",
1269 "pattern not allowed in foreign function",
1273 "patterns aren't allowed in functions without bodies",
1274 "pattern not allowed in function without body",
1277 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1278 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1281 .struct_span_err(span, msg)
1282 .span_label(span, label)
1289 visit::walk_fn(self, fk, span);
1292 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1293 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1294 self.check_defaultness(item.span, item.kind.defaultness());
1297 if ctxt == AssocCtxt::Impl {
1299 AssocItemKind::Const(_, _, body) => {
1300 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1302 AssocItemKind::Fn(_, _, _, body) => {
1303 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1305 AssocItemKind::TyAlias(_, _, bounds, body) => {
1306 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1307 self.check_type_no_bounds(bounds, "`impl`s");
1313 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1314 self.invalid_visibility(&item.vis, None);
1315 if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
1316 self.check_trait_fn_not_const(sig.header.constness);
1317 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1321 if let AssocItemKind::Const(..) = item.kind {
1322 self.check_item_named(item.ident, "const");
1325 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1329 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1330 /// like it's setting an associated type, provide an appropriate suggestion.
1331 fn deny_equality_constraints(
1332 this: &mut AstValidator<'_>,
1333 predicate: &WhereEqPredicate,
1334 generics: &Generics,
1336 let mut err = this.err_handler().struct_span_err(
1338 "equality constraints are not yet supported in `where` clauses",
1340 err.span_label(predicate.span, "not supported");
1342 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1343 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1344 if let TyKind::Path(None, path) = &qself.ty.kind {
1345 match &path.segments[..] {
1346 [PathSegment { ident, args: None, .. }] => {
1347 for param in &generics.params {
1348 if param.ident == *ident {
1350 match &full_path.segments[qself.position..] {
1351 [PathSegment { ident, .. }] => {
1352 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1353 let mut assoc_path = full_path.clone();
1354 // Remove `Bar` from `Foo::Bar`.
1355 assoc_path.segments.pop();
1356 let len = assoc_path.segments.len() - 1;
1357 // Build `<Bar = RhsTy>`.
1358 let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
1359 id: rustc_ast::node_id::DUMMY_NODE_ID,
1361 kind: AssocTyConstraintKind::Equality {
1362 ty: predicate.rhs_ty.clone(),
1366 // Add `<Bar = RhsTy>` to `Foo`.
1367 match &mut assoc_path.segments[len].args {
1368 Some(args) => match args.deref_mut() {
1369 GenericArgs::Parenthesized(_) => continue,
1370 GenericArgs::AngleBracketed(args) => {
1371 args.args.push(arg);
1375 *empty_args = AngleBracketedArgs {
1382 err.span_suggestion_verbose(
1385 "if `{}` is an associated type you're trying to set, \
1386 use the associated type binding syntax",
1392 pprust::path_to_string(&assoc_path)
1394 Applicability::MaybeIncorrect,
1407 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1412 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1413 let mut validator = AstValidator {
1416 in_trait_impl: false,
1417 has_proc_macro_decls: false,
1418 outer_impl_trait: None,
1419 bound_context: None,
1420 is_impl_trait_banned: false,
1421 is_assoc_ty_bound_banned: false,
1424 visit::walk_crate(&mut validator, krate);
1426 validator.has_proc_macro_decls