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};
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 deny_generic_params(&self, generics: &Generics, ident_span: Span) {
576 if !generics.params.is_empty() {
581 "auto traits cannot have generic parameters"
583 .span_label(ident_span, "auto trait cannot have generic parameters")
586 "remove the parameters",
588 Applicability::MachineApplicable,
594 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
595 if let [first @ last] | [first, .., last] = &bounds[..] {
596 let span = first.span().to(last.span());
597 struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
598 .span_label(ident_span, "auto trait cannot have super traits")
601 "remove the super traits",
603 Applicability::MachineApplicable,
609 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
610 if !trait_items.is_empty() {
611 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
616 "auto traits cannot have methods or associated items"
618 .span_label(ident_span, "auto trait cannot have items")
623 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
624 // Lifetimes always come first.
625 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
626 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
627 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
631 let args_sugg = data.args.iter().filter_map(|a| match a {
632 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
635 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
637 // Constraints always come last.
638 let constraint_sugg = data.args.iter().filter_map(|a| match a {
639 AngleBracketedArg::Arg(_) => None,
640 AngleBracketedArg::Constraint(c) => {
641 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
646 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
650 /// Enforce generic args coming before constraints in `<...>` of a path segment.
651 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
652 // Early exit in case it's partitioned as it should be.
653 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
656 // Find all generic argument coming after the first constraint...
657 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
658 data.args.iter().partition_map(|arg| match arg {
659 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
660 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
662 let args_len = arg_spans.len();
663 let constraint_len = constraint_spans.len();
664 // ...and then error:
668 "generic arguments must come before the first constraint",
670 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
672 *arg_spans.iter().last().unwrap(),
673 &format!("generic argument{}", pluralize!(args_len)),
675 .span_labels(constraint_spans, "")
676 .span_labels(arg_spans, "")
677 .span_suggestion_verbose(
680 "move the constraint{} after the generic argument{}",
681 pluralize!(constraint_len),
684 self.correct_generic_order_suggestion(&data),
685 Applicability::MachineApplicable,
691 /// Checks that generic parameters are in the correct order,
692 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
693 fn validate_generic_param_order<'a>(
695 handler: &rustc_errors::Handler,
696 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
699 let mut max_param: Option<ParamKindOrd> = None;
700 let mut out_of_order = FxHashMap::default();
701 let mut param_idents = vec![];
703 for (kind, bounds, span, ident) in generics {
704 if let Some(ident) = ident {
705 param_idents.push((kind, bounds, param_idents.len(), ident));
707 let max_param = &mut max_param;
709 Some(max_param) if *max_param > kind => {
710 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
713 Some(_) | None => *max_param = Some(kind),
717 let mut ordered_params = "<".to_string();
718 if !out_of_order.is_empty() {
719 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
720 let mut first = true;
721 for (_, bounds, _, ident) in param_idents {
723 ordered_params += ", ";
725 ordered_params += &ident;
726 if let Some(bounds) = bounds {
727 if !bounds.is_empty() {
728 ordered_params += ": ";
729 ordered_params += &pprust::bounds_to_string(&bounds);
735 ordered_params += ">";
737 for (param_ord, (max_param, spans)) in &out_of_order {
739 handler.struct_span_err(
742 "{} parameters must be declared prior to {} parameters",
743 param_ord, max_param,
749 "reorder the parameters: lifetimes, then types{}",
750 if sess.features_untracked().const_generics { ", then consts" } else { "" },
752 ordered_params.clone(),
753 Applicability::MachineApplicable,
759 impl<'a> Visitor<'a> for AstValidator<'a> {
760 fn visit_attribute(&mut self, attr: &Attribute) {
761 validate_attr::check_meta(&self.session.parse_sess, attr);
764 fn visit_expr(&mut self, expr: &'a Expr) {
766 ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => {
771 "llvm_asm! is unsupported on this target"
778 visit::walk_expr(self, expr);
781 fn visit_ty(&mut self, ty: &'a Ty) {
783 TyKind::BareFn(ref bfty) => {
784 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
785 Self::check_decl_no_pat(&bfty.decl, |span, _| {
790 "patterns aren't allowed in function pointer types"
794 self.check_late_bound_lifetime_defs(&bfty.generic_params);
796 TyKind::TraitObject(ref bounds, ..) => {
797 let mut any_lifetime_bounds = false;
798 for bound in bounds {
799 if let GenericBound::Outlives(ref lifetime) = *bound {
800 if any_lifetime_bounds {
805 "only a single explicit lifetime bound is permitted"
810 any_lifetime_bounds = true;
813 self.no_questions_in_bounds(bounds, "trait object types", false);
815 TyKind::ImplTrait(_, ref bounds) => {
816 if self.is_impl_trait_banned {
821 "`impl Trait` is not allowed in path parameters"
826 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
831 "nested `impl Trait` is not allowed"
833 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
834 .span_label(ty.span, "nested `impl Trait` here")
840 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
842 self.err_handler().span_err(ty.span, "at least one trait must be specified");
854 fn visit_label(&mut self, label: &'a Label) {
855 self.check_label(label.ident);
856 visit::walk_label(self, label);
859 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
860 self.check_lifetime(lifetime.ident);
861 visit::walk_lifetime(self, lifetime);
864 fn visit_item(&mut self, item: &'a Item) {
865 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
866 self.has_proc_macro_decls = true;
876 of_trait: Some(ref t),
880 self.with_in_trait_impl(true, |this| {
881 this.invalid_visibility(&item.vis, None);
882 if let TyKind::Err = self_ty.kind {
886 "`impl Trait for .. {}` is an obsolete syntax",
888 .help("use `auto trait Trait {}` instead")
891 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
896 "negative impls cannot be unsafe"
898 .span_label(sp, "negative because of this")
899 .span_label(span, "unsafe because of this")
903 visit::walk_item(this, item);
905 return; // Avoid visiting again.
917 let error = |annotation_span, annotation| {
918 let mut err = self.err_handler().struct_span_err(
920 &format!("inherent impls cannot be {}", annotation),
922 err.span_label(annotation_span, &format!("{} because of this", annotation));
923 err.span_label(self_ty.span, "inherent impl for this type");
927 self.invalid_visibility(
929 Some("place qualifiers on individual impl items instead"),
931 if let Unsafe::Yes(span) = unsafety {
932 error(span, "unsafe").code(error_code!(E0197)).emit();
934 if let ImplPolarity::Negative(span) = polarity {
935 error(span, "negative").emit();
937 if let Defaultness::Default(def_span) = defaultness {
938 error(def_span, "`default`")
939 .note("only trait implementations may be annotated with `default`")
942 if let Const::Yes(span) = constness {
943 error(span, "`const`")
944 .note("only trait implementations may be annotated with `const`")
948 ItemKind::Fn(def, _, _, ref body) => {
949 self.check_defaultness(item.span, def);
952 let msg = "free function without a body";
953 self.error_item_without_body(item.span, "function", msg, " { <body> }");
956 ItemKind::ForeignMod(_) => {
957 let old_item = mem::replace(&mut self.extern_mod, Some(item));
958 self.invalid_visibility(
960 Some("place qualifiers on individual foreign items instead"),
962 visit::walk_item(self, item);
963 self.extern_mod = old_item;
964 return; // Avoid visiting again.
966 ItemKind::Enum(ref def, _) => {
967 for variant in &def.variants {
968 self.invalid_visibility(&variant.vis, None);
969 for field in variant.data.fields() {
970 self.invalid_visibility(&field.vis, None);
974 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
975 if is_auto == IsAuto::Yes {
976 // Auto traits cannot have generics, super traits nor contain items.
977 self.deny_generic_params(generics, item.ident.span);
978 self.deny_super_traits(bounds, item.ident.span);
979 self.deny_items(trait_items, item.ident.span);
981 self.no_questions_in_bounds(bounds, "supertraits", true);
983 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
984 // context for the supertraits.
985 self.visit_vis(&item.vis);
986 self.visit_ident(item.ident);
987 self.visit_generics(generics);
988 self.with_bound_context(BoundContext::TraitBounds, |this| {
989 walk_list!(this, visit_param_bound, bounds);
991 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
992 walk_list!(self, visit_attribute, &item.attrs);
995 ItemKind::Mod(_) => {
996 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
997 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
999 ItemKind::Union(ref vdata, _) => {
1000 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
1002 .span_err(item.span, "tuple and unit unions are not permitted");
1004 if vdata.fields().is_empty() {
1005 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1008 ItemKind::Const(def, .., None) => {
1009 self.check_defaultness(item.span, def);
1010 let msg = "free constant item without body";
1011 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1013 ItemKind::Static(.., None) => {
1014 let msg = "free static item without body";
1015 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1017 ItemKind::TyAlias(def, _, ref bounds, ref body) => {
1018 self.check_defaultness(item.span, def);
1020 let msg = "free type alias without body";
1021 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1023 self.check_type_no_bounds(bounds, "this context");
1028 visit::walk_item(self, item)
1031 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1033 ForeignItemKind::Fn(def, sig, _, body) => {
1034 self.check_defaultness(fi.span, *def);
1035 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1036 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1038 ForeignItemKind::TyAlias(def, generics, bounds, body) => {
1039 self.check_defaultness(fi.span, *def);
1040 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1041 self.check_type_no_bounds(bounds, "`extern` blocks");
1042 self.check_foreign_ty_genericless(generics);
1044 ForeignItemKind::Static(_, _, body) => {
1045 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1047 ForeignItemKind::MacCall(..) => {}
1050 visit::walk_foreign_item(self, fi)
1053 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1054 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1055 match *generic_args {
1056 GenericArgs::AngleBracketed(ref data) => {
1057 self.check_generic_args_before_constraints(data);
1059 for arg in &data.args {
1061 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1062 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1063 // are allowed to contain nested `impl Trait`.
1064 AngleBracketedArg::Constraint(constraint) => {
1065 self.with_impl_trait(None, |this| {
1066 this.visit_assoc_ty_constraint_from_generic_args(constraint);
1072 GenericArgs::Parenthesized(ref data) => {
1073 walk_list!(self, visit_ty, &data.inputs);
1074 if let FnRetTy::Ty(ty) = &data.output {
1075 // `-> Foo` syntax is essentially an associated type binding,
1076 // so it is also allowed to contain nested `impl Trait`.
1077 self.with_impl_trait(None, |this| this.visit_ty(ty));
1083 fn visit_generics(&mut self, generics: &'a Generics) {
1084 let mut prev_ty_default = None;
1085 for param in &generics.params {
1086 if let GenericParamKind::Type { ref default, .. } = param.kind {
1087 if default.is_some() {
1088 prev_ty_default = Some(param.ident.span);
1089 } else if let Some(span) = prev_ty_default {
1091 .span_err(span, "type parameters with a default must be trailing");
1097 validate_generic_param_order(
1100 generics.params.iter().map(|param| {
1101 let ident = Some(param.ident.to_string());
1102 let (kind, ident) = match ¶m.kind {
1103 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1104 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1105 GenericParamKind::Const { ref ty } => {
1106 let ty = pprust::ty_to_string(ty);
1107 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1110 (kind, Some(&*param.bounds), param.ident.span, ident)
1115 for predicate in &generics.where_clause.predicates {
1116 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1117 deny_equality_constraints(self, predicate, generics);
1121 visit::walk_generics(self, generics)
1124 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1125 if let GenericParamKind::Lifetime { .. } = param.kind {
1126 self.check_lifetime(param.ident);
1128 visit::walk_generic_param(self, param);
1131 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1133 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1134 if let Some(ctx) = self.bound_context {
1135 let msg = format!("`?const` is not permitted in {}", ctx.description());
1136 self.err_handler().span_err(bound.span(), &msg);
1140 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1142 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1148 visit::walk_param_bound(self, bound)
1151 fn visit_pat(&mut self, pat: &'a Pat) {
1153 PatKind::Lit(ref expr) => {
1154 self.check_expr_within_pat(expr, false);
1156 PatKind::Range(ref start, ref end, _) => {
1157 if let Some(expr) = start {
1158 self.check_expr_within_pat(expr, true);
1160 if let Some(expr) = end {
1161 self.check_expr_within_pat(expr, true);
1167 visit::walk_pat(self, pat)
1170 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1171 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1172 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1173 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1175 visit::walk_where_predicate(self, p);
1178 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1179 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1180 visit::walk_poly_trait_ref(self, t, m);
1183 fn visit_variant_data(&mut self, s: &'a VariantData) {
1184 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1189 enum_definition: &'a EnumDef,
1190 generics: &'a Generics,
1194 self.with_banned_assoc_ty_bound(|this| {
1195 visit::walk_enum_def(this, enum_definition, generics, item_id)
1199 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1200 // Only associated `fn`s can have `self` parameters.
1201 let self_semantic = match fk.ctxt() {
1202 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1203 _ => SelfSemantic::No,
1205 self.check_fn_decl(fk.decl(), self_semantic);
1207 self.check_c_varadic_type(fk);
1209 // Functions cannot both be `const async`
1210 if let Some(FnHeader {
1211 constness: Const::Yes(cspan),
1212 asyncness: Async::Yes { span: aspan, .. },
1218 vec![*cspan, *aspan],
1219 "functions cannot be both `const` and `async`",
1221 .span_label(*cspan, "`const` because of this")
1222 .span_label(*aspan, "`async` because of this")
1223 .span_label(span, "") // Point at the fn header.
1227 // Functions without bodies cannot have patterns.
1228 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1229 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1230 let (code, msg, label) = match ctxt {
1231 FnCtxt::Foreign => (
1233 "patterns aren't allowed in foreign function declarations",
1234 "pattern not allowed in foreign function",
1238 "patterns aren't allowed in functions without bodies",
1239 "pattern not allowed in function without body",
1242 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1243 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1246 .struct_span_err(span, msg)
1247 .span_label(span, label)
1254 visit::walk_fn(self, fk, span);
1257 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1258 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1259 self.check_defaultness(item.span, item.kind.defaultness());
1262 if ctxt == AssocCtxt::Impl {
1264 AssocItemKind::Const(_, _, body) => {
1265 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1267 AssocItemKind::Fn(_, _, _, body) => {
1268 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1270 AssocItemKind::TyAlias(_, _, bounds, body) => {
1271 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1272 self.check_type_no_bounds(bounds, "`impl`s");
1278 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1279 self.invalid_visibility(&item.vis, None);
1280 if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
1281 self.check_trait_fn_not_const(sig.header.constness);
1282 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1286 if let AssocItemKind::Const(..) = item.kind {
1287 self.check_item_named(item.ident, "const");
1290 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1294 fn deny_equality_constraints(
1295 this: &mut AstValidator<'_>,
1296 predicate: &WhereEqPredicate,
1297 generics: &Generics,
1299 let mut err = this.err_handler().struct_span_err(
1301 "equality constraints are not yet supported in `where` clauses",
1303 err.span_label(predicate.span, "not supported");
1305 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1306 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1307 if let TyKind::Path(None, path) = &qself.ty.kind {
1308 match &path.segments[..] {
1309 [PathSegment { ident, args: None, .. }] => {
1310 for param in &generics.params {
1311 if param.ident == *ident {
1313 match &full_path.segments[qself.position..] {
1314 [PathSegment { ident, .. }] => {
1315 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1316 let mut assoc_path = full_path.clone();
1317 // Remove `Bar` from `Foo::Bar`.
1318 assoc_path.segments.pop();
1319 let len = assoc_path.segments.len() - 1;
1320 // Build `<Bar = RhsTy>`.
1321 let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
1322 id: rustc_ast::node_id::DUMMY_NODE_ID,
1324 kind: AssocTyConstraintKind::Equality {
1325 ty: predicate.rhs_ty.clone(),
1329 // Add `<Bar = RhsTy>` to `Foo`.
1330 match &mut assoc_path.segments[len].args {
1331 Some(args) => match args.deref_mut() {
1332 GenericArgs::Parenthesized(_) => continue,
1333 GenericArgs::AngleBracketed(args) => {
1334 args.args.push(arg);
1338 *empty_args = AngleBracketedArgs {
1345 err.span_suggestion_verbose(
1348 "if `{}` is an associated type you're trying to set, \
1349 use the associated type binding syntax",
1355 pprust::path_to_string(&assoc_path)
1357 Applicability::MaybeIncorrect,
1370 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1375 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1376 let mut validator = AstValidator {
1379 in_trait_impl: false,
1380 has_proc_macro_decls: false,
1381 outer_impl_trait: None,
1382 bound_context: None,
1383 is_impl_trait_banned: false,
1384 is_assoc_ty_bound_banned: false,
1387 visit::walk_crate(&mut validator, krate);
1389 validator.has_proc_macro_decls