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::ptr::P;
11 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
12 use rustc_ast::walk_list;
14 use rustc_ast_pretty::pprust;
15 use rustc_data_structures::fx::FxHashMap;
16 use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
17 use rustc_parse::validate_attr;
18 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
19 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
20 use rustc_session::Session;
21 use rustc_span::symbol::{kw, sym, Ident};
24 use std::ops::DerefMut;
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 TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
179 self.with_banned_assoc_ty_bound(|this| {
180 walk_list!(this, visit_struct_field_def, fields)
183 _ => visit::walk_ty(self, t),
187 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
188 if let Some(ident) = field.ident {
189 if ident.name == kw::Underscore {
190 self.check_anonymous_field(field);
191 self.visit_vis(&field.vis);
192 self.visit_ident(ident);
193 self.visit_ty_common(&field.ty);
194 self.walk_ty(&field.ty);
195 walk_list!(self, visit_attribute, &field.attrs);
199 self.visit_field_def(field);
202 fn err_handler(&self) -> &rustc_errors::Handler {
203 &self.session.diagnostic()
206 fn check_lifetime(&self, ident: Ident) {
207 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
208 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
209 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
213 fn check_label(&self, ident: Ident) {
214 if ident.without_first_quote().is_reserved() {
216 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
220 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
221 if let VisibilityKind::Inherited = vis.kind {
226 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
227 if vis.kind.is_pub() {
228 err.span_label(vis.span, "`pub` not permitted here because it's implied");
230 if let Some(note) = note {
236 fn check_anonymous_field(&self, field: &FieldDef) {
237 let FieldDef { ty, .. } = field;
239 TyKind::AnonymousStruct(..) | TyKind::AnonymousUnion(..) => {
240 // We already checked for `kw::Underscore` before calling this function,
243 TyKind::Path(..) => {
244 // If the anonymous field contains a Path as type, we can't determine
245 // if the path is a valid struct or union, so skip the check
248 let msg = "unnamed fields can only have struct or union types";
249 let label = "not a struct or union";
251 .struct_span_err(field.span, msg)
252 .span_label(ty.span, label)
258 fn deny_anonymous_struct(&self, ty: &Ty) {
260 TyKind::AnonymousStruct(..) => {
264 "anonymous structs are not allowed outside of unnamed struct or union fields",
266 .span_label(ty.span, "anonymous struct declared here")
269 TyKind::AnonymousUnion(..) => {
273 "anonymous unions are not allowed outside of unnamed struct or union fields",
275 .span_label(ty.span, "anonymous union declared here")
282 fn deny_anonymous_field(&self, field: &FieldDef) {
283 if let Some(ident) = field.ident {
284 if ident.name == kw::Underscore {
288 "anonymous fields are not allowed outside of structs or unions",
290 .span_label(ident.span, "anonymous field declared here")
296 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
297 for Param { pat, .. } in &decl.inputs {
299 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
300 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
301 report_err(pat.span, Some(ident), true)
303 _ => report_err(pat.span, None, false),
308 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
309 if let Async::Yes { span, .. } = asyncness {
314 "functions in traits cannot be declared `async`"
316 .span_label(span, "`async` because of this")
317 .note("`async` trait functions are not currently supported")
318 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
323 fn check_trait_fn_not_const(&self, constness: Const) {
324 if let Const::Yes(span) = constness {
329 "functions in traits cannot be declared const"
331 .span_label(span, "functions in traits cannot be const")
336 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
337 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
338 for bound in bounds {
339 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
340 let mut err = self.err_handler().struct_span_err(
342 &format!("`?Trait` is not permitted in {}", where_),
345 let path_str = pprust::path_to_string(&poly.trait_ref.path);
346 err.note(&format!("traits are `?{}` by default", path_str));
353 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
354 /// or paths for ranges.
356 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
357 // That means making this work:
359 // ```rust,ignore (FIXME)
368 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
370 ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
371 ExprKind::Path(..) if allow_paths => {}
372 ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
373 _ => self.err_handler().span_err(
375 "arbitrary expressions aren't allowed \
381 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
382 // Check only lifetime parameters are present and that the lifetime
383 // parameters that are present have no bounds.
384 let non_lt_param_spans: Vec<_> = params
386 .filter_map(|param| match param.kind {
387 GenericParamKind::Lifetime { .. } => {
388 if !param.bounds.is_empty() {
389 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
391 .span_err(spans, "lifetime bounds cannot be used in this context");
395 _ => Some(param.ident.span),
398 if !non_lt_param_spans.is_empty() {
399 self.err_handler().span_err(
401 "only lifetime parameters can be used in this context",
406 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
407 self.check_decl_cvaradic_pos(fn_decl);
408 self.check_decl_attrs(fn_decl);
409 self.check_decl_self_param(fn_decl, self_semantic);
412 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
413 match &*fn_decl.inputs {
414 [Param { ty, span, .. }] => {
415 if let TyKind::CVarArgs = ty.kind {
416 self.err_handler().span_err(
418 "C-variadic function must be declared with at least one named argument",
423 for Param { ty, span, .. } in ps {
424 if let TyKind::CVarArgs = ty.kind {
425 self.err_handler().span_err(
427 "`...` must be the last argument of a C-variadic function",
436 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
440 .flat_map(|i| i.attrs.as_ref())
442 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
443 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
446 if attr.is_doc_comment() {
450 "documentation comments cannot be applied to function parameters",
452 .span_label(attr.span, "doc comments are not allowed here")
455 self.err_handler().span_err(
457 "allow, cfg, cfg_attr, deny, \
458 forbid, and warn are the only allowed built-in attributes in function parameters",
464 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
465 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
470 "`self` parameter is only allowed in associated functions",
472 .span_label(param.span, "not semantically valid as function parameter")
473 .note("associated functions are those in `impl` or `trait` definitions")
479 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
480 if let Defaultness::Default(def_span) = defaultness {
481 let span = self.session.source_map().guess_head_span(span);
483 .struct_span_err(span, "`default` is only allowed on items in trait impls")
484 .span_label(def_span, "`default` because of this")
489 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
491 .struct_span_err(sp, msg)
493 self.session.source_map().end_point(sp),
494 &format!("provide a definition for the {}", ctx),
496 Applicability::HasPlaceholders,
501 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
503 let msg = format!("associated {} in `impl` without body", ctx);
504 self.error_item_without_body(sp, ctx, &msg, sugg);
508 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
509 let span = match bounds {
512 [b0, .., bl] => b0.span().to(bl.span()),
515 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
519 fn check_foreign_ty_genericless(&self, generics: &Generics) {
520 let cannot_have = |span, descr, remove_descr| {
524 &format!("`type`s inside `extern` blocks cannot have {}", descr),
528 &format!("remove the {}", remove_descr),
530 Applicability::MaybeIncorrect,
532 .span_label(self.current_extern_span(), "`extern` block begins here")
537 if !generics.params.is_empty() {
538 cannot_have(generics.span, "generic parameters", "generic parameters");
541 if !generics.where_clause.predicates.is_empty() {
542 cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
546 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
547 let body = match body {
552 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
553 .span_label(ident.span, "cannot have a body")
554 .span_label(body, "the invalid body")
556 self.current_extern_span(),
558 "`extern` blocks define existing foreign {0}s and {0}s \
559 inside of them cannot have a body",
567 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
568 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
569 let body = match body {
574 .struct_span_err(ident.span, "incorrect function inside `extern` block")
575 .span_label(ident.span, "cannot have a body")
578 "remove the invalid body",
580 Applicability::MaybeIncorrect,
583 "you might have meant to write a function accessible through FFI, \
584 which can be done by writing `extern fn` outside of the `extern` block",
587 self.current_extern_span(),
588 "`extern` blocks define existing foreign functions and functions \
589 inside of them cannot have a body",
595 fn current_extern_span(&self) -> Span {
596 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
599 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
600 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
601 if header.has_qualifiers() {
603 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
604 .span_label(self.current_extern_span(), "in this `extern` block")
605 .span_suggestion_verbose(
606 span.until(ident.span.shrink_to_lo()),
607 "remove the qualifiers",
609 Applicability::MaybeIncorrect,
615 /// An item in `extern { ... }` cannot use non-ascii identifier.
616 fn check_foreign_item_ascii_only(&self, ident: Ident) {
617 let symbol_str = ident.as_str();
618 if !symbol_str.is_ascii() {
623 "items in `extern` blocks cannot use non-ascii identifiers",
625 .span_label(self.current_extern_span(), "in this `extern` block")
627 "This limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
634 /// Reject C-varadic type unless the function is foreign,
635 /// or free and `unsafe extern "C"` semantically.
636 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
637 match (fk.ctxt(), fk.header()) {
638 (Some(FnCtxt::Foreign), _) => return,
639 (Some(FnCtxt::Free), Some(header)) => match header.ext {
640 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
641 if matches!(header.unsafety, Unsafe::Yes(_)) =>
650 for Param { ty, span, .. } in &fk.decl().inputs {
651 if let TyKind::CVarArgs = ty.kind {
655 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
662 fn check_item_named(&self, ident: Ident, kind: &str) {
663 if ident.name != kw::Underscore {
667 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
668 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
672 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
673 if ident.name.as_str().is_ascii() {
676 let head_span = self.session.source_map().guess_head_span(item_span);
681 "`#[no_mangle]` requires ASCII identifier"
686 fn check_mod_file_item_asciionly(&self, ident: Ident) {
687 if ident.name.as_str().is_ascii() {
694 "trying to load file for module `{}` with non-ascii identifier name",
697 .help("consider using `#[path]` attribute to specify filesystem path")
701 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
702 if !generics.params.is_empty() {
707 "auto traits cannot have generic parameters"
709 .span_label(ident_span, "auto trait cannot have generic parameters")
712 "remove the parameters",
714 Applicability::MachineApplicable,
720 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
721 if let [first @ last] | [first, .., last] = &bounds[..] {
722 let span = first.span().to(last.span());
723 struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
724 .span_label(ident_span, "auto trait cannot have super traits")
727 "remove the super traits",
729 Applicability::MachineApplicable,
735 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
736 if !trait_items.is_empty() {
737 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
742 "auto traits cannot have methods or associated items"
744 .span_label(ident_span, "auto trait cannot have items")
749 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
750 // Lifetimes always come first.
751 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
752 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
753 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
757 let args_sugg = data.args.iter().filter_map(|a| match a {
758 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
761 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
763 // Constraints always come last.
764 let constraint_sugg = data.args.iter().filter_map(|a| match a {
765 AngleBracketedArg::Arg(_) => None,
766 AngleBracketedArg::Constraint(c) => {
767 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
772 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
776 /// Enforce generic args coming before constraints in `<...>` of a path segment.
777 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
778 // Early exit in case it's partitioned as it should be.
779 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
782 // Find all generic argument coming after the first constraint...
783 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
784 data.args.iter().partition_map(|arg| match arg {
785 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
786 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
788 let args_len = arg_spans.len();
789 let constraint_len = constraint_spans.len();
790 // ...and then error:
794 "generic arguments must come before the first constraint",
796 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
798 *arg_spans.iter().last().unwrap(),
799 &format!("generic argument{}", pluralize!(args_len)),
801 .span_labels(constraint_spans, "")
802 .span_labels(arg_spans, "")
803 .span_suggestion_verbose(
806 "move the constraint{} after the generic argument{}",
807 pluralize!(constraint_len),
810 self.correct_generic_order_suggestion(&data),
811 Applicability::MachineApplicable,
816 fn visit_ty_common(&mut self, ty: &'a Ty) {
818 TyKind::BareFn(ref bfty) => {
819 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
820 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
825 "patterns aren't allowed in function pointer types"
829 self.check_late_bound_lifetime_defs(&bfty.generic_params);
831 TyKind::TraitObject(ref bounds, ..) => {
832 let mut any_lifetime_bounds = false;
833 for bound in bounds {
834 if let GenericBound::Outlives(ref lifetime) = *bound {
835 if any_lifetime_bounds {
840 "only a single explicit lifetime bound is permitted"
845 any_lifetime_bounds = true;
848 self.no_questions_in_bounds(bounds, "trait object types", false);
850 TyKind::ImplTrait(_, ref bounds) => {
851 if self.is_impl_trait_banned {
856 "`impl Trait` is not allowed in path parameters"
861 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
866 "nested `impl Trait` is not allowed"
868 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
869 .span_label(ty.span, "nested `impl Trait` here")
873 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
874 self.err_handler().span_err(ty.span, "at least one trait must be specified");
882 /// Checks that generic parameters are in the correct order,
883 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
884 fn validate_generic_param_order(
886 handler: &rustc_errors::Handler,
887 generics: &[GenericParam],
890 let mut max_param: Option<ParamKindOrd> = None;
891 let mut out_of_order = FxHashMap::default();
892 let mut param_idents = Vec::with_capacity(generics.len());
894 for (idx, param) in generics.iter().enumerate() {
895 let ident = param.ident;
896 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
897 let (ord_kind, ident) = match ¶m.kind {
898 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
899 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
900 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
901 let ty = pprust::ty_to_string(ty);
902 let unordered = sess.features_untracked().unordered_const_ty_params();
903 (ParamKindOrd::Const { unordered }, format!("const {}: {}", ident, ty))
906 param_idents.push((kind, ord_kind, bounds, idx, ident));
908 Some(max_param) if max_param > ord_kind => {
909 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
912 Some(_) | None => max_param = Some(ord_kind),
916 if !out_of_order.is_empty() {
917 let mut ordered_params = "<".to_string();
918 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
919 let mut first = true;
920 for (kind, _, bounds, _, ident) in param_idents {
922 ordered_params += ", ";
924 ordered_params += &ident;
926 if !bounds.is_empty() {
927 ordered_params += ": ";
928 ordered_params += &pprust::bounds_to_string(&bounds);
932 GenericParamKind::Type { default: Some(default) } => {
933 ordered_params += " = ";
934 ordered_params += &pprust::ty_to_string(default);
936 GenericParamKind::Type { default: None } => (),
937 GenericParamKind::Lifetime => (),
938 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
939 ordered_params += " = ";
940 ordered_params += &pprust::expr_to_string(&*default.value);
942 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
947 ordered_params += ">";
949 for (param_ord, (max_param, spans)) in &out_of_order {
950 let mut err = handler.struct_span_err(
953 "{} parameters must be declared prior to {} parameters",
954 param_ord, max_param,
960 "reorder the parameters: lifetimes, {}",
961 if sess.features_untracked().unordered_const_ty_params() {
962 "then consts and types"
964 "then types, then consts"
967 ordered_params.clone(),
968 Applicability::MachineApplicable,
975 impl<'a> Visitor<'a> for AstValidator<'a> {
976 fn visit_attribute(&mut self, attr: &Attribute) {
977 validate_attr::check_meta(&self.session.parse_sess, attr);
980 fn visit_expr(&mut self, expr: &'a Expr) {
982 ExprKind::LlvmInlineAsm(..) if !self.session.target.allow_asm => {
987 "llvm_asm! is unsupported on this target"
994 visit::walk_expr(self, expr);
997 fn visit_ty(&mut self, ty: &'a Ty) {
998 self.visit_ty_common(ty);
999 self.deny_anonymous_struct(ty);
1003 fn visit_label(&mut self, label: &'a Label) {
1004 self.check_label(label.ident);
1005 visit::walk_label(self, label);
1008 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
1009 self.check_lifetime(lifetime.ident);
1010 visit::walk_lifetime(self, lifetime);
1013 fn visit_field_def(&mut self, s: &'a FieldDef) {
1014 self.deny_anonymous_field(s);
1015 visit::walk_field_def(self, s)
1018 fn visit_item(&mut self, item: &'a Item) {
1019 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1020 self.has_proc_macro_decls = true;
1023 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1024 self.check_nomangle_item_asciionly(item.ident, item.span);
1028 ItemKind::Impl(box ImplKind {
1034 of_trait: Some(ref t),
1038 self.with_in_trait_impl(true, |this| {
1039 this.invalid_visibility(&item.vis, None);
1040 if let TyKind::Err = self_ty.kind {
1044 "`impl Trait for .. {}` is an obsolete syntax",
1046 .help("use `auto trait Trait {}` instead")
1049 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1054 "negative impls cannot be unsafe"
1056 .span_label(sp, "negative because of this")
1057 .span_label(span, "unsafe because of this")
1061 visit::walk_item(this, item);
1063 return; // Avoid visiting again.
1065 ItemKind::Impl(box ImplKind {
1075 let error = |annotation_span, annotation| {
1076 let mut err = self.err_handler().struct_span_err(
1078 &format!("inherent impls cannot be {}", annotation),
1080 err.span_label(annotation_span, &format!("{} because of this", annotation));
1081 err.span_label(self_ty.span, "inherent impl for this type");
1085 self.invalid_visibility(
1087 Some("place qualifiers on individual impl items instead"),
1089 if let Unsafe::Yes(span) = unsafety {
1090 error(span, "unsafe").code(error_code!(E0197)).emit();
1092 if let ImplPolarity::Negative(span) = polarity {
1093 error(span, "negative").emit();
1095 if let Defaultness::Default(def_span) = defaultness {
1096 error(def_span, "`default`")
1097 .note("only trait implementations may be annotated with `default`")
1100 if let Const::Yes(span) = constness {
1101 error(span, "`const`")
1102 .note("only trait implementations may be annotated with `const`")
1106 ItemKind::Fn(box FnKind(def, _, _, ref body)) => {
1107 self.check_defaultness(item.span, def);
1110 let msg = "free function without a body";
1111 self.error_item_without_body(item.span, "function", msg, " { <body> }");
1114 ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => {
1115 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1116 self.invalid_visibility(
1118 Some("place qualifiers on individual foreign items instead"),
1120 if let Unsafe::Yes(span) = unsafety {
1121 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1123 visit::walk_item(self, item);
1124 self.extern_mod = old_item;
1125 return; // Avoid visiting again.
1127 ItemKind::Enum(ref def, _) => {
1128 for variant in &def.variants {
1129 self.invalid_visibility(&variant.vis, None);
1130 for field in variant.data.fields() {
1131 self.invalid_visibility(&field.vis, None);
1135 ItemKind::Trait(box TraitKind(
1142 if is_auto == IsAuto::Yes {
1143 // Auto traits cannot have generics, super traits nor contain items.
1144 self.deny_generic_params(generics, item.ident.span);
1145 self.deny_super_traits(bounds, item.ident.span);
1146 self.deny_items(trait_items, item.ident.span);
1148 self.no_questions_in_bounds(bounds, "supertraits", true);
1150 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1151 // context for the supertraits.
1152 self.visit_vis(&item.vis);
1153 self.visit_ident(item.ident);
1154 self.visit_generics(generics);
1155 self.with_bound_context(BoundContext::TraitBounds, |this| {
1156 walk_list!(this, visit_param_bound, bounds);
1158 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
1159 walk_list!(self, visit_attribute, &item.attrs);
1162 ItemKind::Mod(unsafety, ref mod_kind) => {
1163 if let Unsafe::Yes(span) = unsafety {
1164 self.err_handler().span_err(span, "module cannot be declared unsafe");
1166 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1167 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1168 && !self.session.contains_name(&item.attrs, sym::path)
1170 self.check_mod_file_item_asciionly(item.ident);
1173 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1174 // Duplicating the `Visitor` logic allows catching all cases
1175 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1177 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1178 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1179 // it uses `visit_ty_common`, which doesn't contain that specific check.
1180 VariantData::Struct(ref fields, ..) => {
1181 self.visit_vis(&item.vis);
1182 self.visit_ident(item.ident);
1183 self.visit_generics(generics);
1184 self.with_banned_assoc_ty_bound(|this| {
1185 walk_list!(this, visit_struct_field_def, fields);
1187 walk_list!(self, visit_attribute, &item.attrs);
1192 ItemKind::Union(ref vdata, ref generics) => {
1193 if vdata.fields().is_empty() {
1194 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1197 VariantData::Struct(ref fields, ..) => {
1198 self.visit_vis(&item.vis);
1199 self.visit_ident(item.ident);
1200 self.visit_generics(generics);
1201 self.with_banned_assoc_ty_bound(|this| {
1202 walk_list!(this, visit_struct_field_def, fields);
1204 walk_list!(self, visit_attribute, &item.attrs);
1210 ItemKind::Const(def, .., None) => {
1211 self.check_defaultness(item.span, def);
1212 let msg = "free constant item without body";
1213 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1215 ItemKind::Static(.., None) => {
1216 let msg = "free static item without body";
1217 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1219 ItemKind::TyAlias(box TyAliasKind(def, _, ref bounds, ref body)) => {
1220 self.check_defaultness(item.span, def);
1222 let msg = "free type alias without body";
1223 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1225 self.check_type_no_bounds(bounds, "this context");
1230 visit::walk_item(self, item)
1233 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1235 ForeignItemKind::Fn(box FnKind(def, sig, _, body)) => {
1236 self.check_defaultness(fi.span, *def);
1237 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1238 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1239 self.check_foreign_item_ascii_only(fi.ident);
1241 ForeignItemKind::TyAlias(box TyAliasKind(def, generics, bounds, body)) => {
1242 self.check_defaultness(fi.span, *def);
1243 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1244 self.check_type_no_bounds(bounds, "`extern` blocks");
1245 self.check_foreign_ty_genericless(generics);
1246 self.check_foreign_item_ascii_only(fi.ident);
1248 ForeignItemKind::Static(_, _, body) => {
1249 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1250 self.check_foreign_item_ascii_only(fi.ident);
1252 ForeignItemKind::MacCall(..) => {}
1255 visit::walk_foreign_item(self, fi)
1258 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1259 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1260 match *generic_args {
1261 GenericArgs::AngleBracketed(ref data) => {
1262 self.check_generic_args_before_constraints(data);
1264 for arg in &data.args {
1266 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1267 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1268 // are allowed to contain nested `impl Trait`.
1269 AngleBracketedArg::Constraint(constraint) => {
1270 self.with_impl_trait(None, |this| {
1271 this.visit_assoc_ty_constraint_from_generic_args(constraint);
1277 GenericArgs::Parenthesized(ref data) => {
1278 walk_list!(self, visit_ty, &data.inputs);
1279 if let FnRetTy::Ty(ty) = &data.output {
1280 // `-> Foo` syntax is essentially an associated type binding,
1281 // so it is also allowed to contain nested `impl Trait`.
1282 self.with_impl_trait(None, |this| this.visit_ty(ty));
1288 fn visit_generics(&mut self, generics: &'a Generics) {
1289 let cg_defaults = self.session.features_untracked().const_generics_defaults;
1291 let mut prev_param_default = None;
1292 for param in &generics.params {
1294 GenericParamKind::Lifetime => (),
1295 GenericParamKind::Type { default: Some(_), .. }
1296 | GenericParamKind::Const { default: Some(_), .. } => {
1297 prev_param_default = Some(param.ident.span);
1299 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1300 if let Some(span) = prev_param_default {
1301 let mut err = self.err_handler().struct_span_err(
1303 "generic parameters with a default must be trailing",
1305 if matches!(param.kind, GenericParamKind::Const { .. }) && !cg_defaults {
1307 "using type defaults and const parameters \
1308 in the same parameter list is currently not permitted",
1318 validate_generic_param_order(
1325 for predicate in &generics.where_clause.predicates {
1326 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1327 deny_equality_constraints(self, predicate, generics);
1330 walk_list!(self, visit_generic_param, &generics.params);
1331 for predicate in &generics.where_clause.predicates {
1333 WherePredicate::BoundPredicate(bound_pred) => {
1334 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1335 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1337 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1338 // binder and thus we only allow a single level of quantification. However,
1339 // the syntax of Rust permits quantification in two places in where clauses,
1340 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1341 // defined, then error.
1342 if !bound_pred.bound_generic_params.is_empty() {
1343 for bound in &bound_pred.bounds {
1345 GenericBound::Trait(t, _) => {
1346 if !t.bound_generic_params.is_empty() {
1351 "nested quantification of lifetimes"
1356 GenericBound::Outlives(_) => {}
1363 self.visit_where_predicate(predicate);
1367 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1368 if let GenericParamKind::Lifetime { .. } = param.kind {
1369 self.check_lifetime(param.ident);
1371 visit::walk_generic_param(self, param);
1374 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1376 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1377 if let Some(ctx) = self.bound_context {
1378 let msg = format!("`?const` is not permitted in {}", ctx.description());
1379 self.err_handler().span_err(bound.span(), &msg);
1383 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1385 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1391 visit::walk_param_bound(self, bound)
1394 fn visit_pat(&mut self, pat: &'a Pat) {
1396 PatKind::Lit(expr) => {
1397 self.check_expr_within_pat(expr, false);
1399 PatKind::Range(start, end, _) => {
1400 if let Some(expr) = start {
1401 self.check_expr_within_pat(expr, true);
1403 if let Some(expr) = end {
1404 self.check_expr_within_pat(expr, true);
1410 visit::walk_pat(self, pat)
1413 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1414 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1415 visit::walk_poly_trait_ref(self, t, m);
1418 fn visit_variant_data(&mut self, s: &'a VariantData) {
1419 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1424 enum_definition: &'a EnumDef,
1425 generics: &'a Generics,
1429 self.with_banned_assoc_ty_bound(|this| {
1430 visit::walk_enum_def(this, enum_definition, generics, item_id)
1434 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1435 // Only associated `fn`s can have `self` parameters.
1436 let self_semantic = match fk.ctxt() {
1437 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1438 _ => SelfSemantic::No,
1440 self.check_fn_decl(fk.decl(), self_semantic);
1442 self.check_c_varadic_type(fk);
1444 // Functions cannot both be `const async`
1445 if let Some(FnHeader {
1446 constness: Const::Yes(cspan),
1447 asyncness: Async::Yes { span: aspan, .. },
1453 vec![*cspan, *aspan],
1454 "functions cannot be both `const` and `async`",
1456 .span_label(*cspan, "`const` because of this")
1457 .span_label(*aspan, "`async` because of this")
1458 .span_label(span, "") // Point at the fn header.
1462 // Functions without bodies cannot have patterns.
1463 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1464 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1465 let (code, msg, label) = match ctxt {
1466 FnCtxt::Foreign => (
1468 "patterns aren't allowed in foreign function declarations",
1469 "pattern not allowed in foreign function",
1473 "patterns aren't allowed in functions without bodies",
1474 "pattern not allowed in function without body",
1477 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1478 if let Some(ident) = ident {
1479 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1480 self.lint_buffer.buffer_lint_with_diagnostic(
1481 PATTERNS_IN_FNS_WITHOUT_BODY,
1490 .struct_span_err(span, msg)
1491 .span_label(span, label)
1498 visit::walk_fn(self, fk, span);
1501 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1502 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1503 self.check_defaultness(item.span, item.kind.defaultness());
1506 if ctxt == AssocCtxt::Impl {
1508 AssocItemKind::Const(_, _, body) => {
1509 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1511 AssocItemKind::Fn(box FnKind(_, _, _, body)) => {
1512 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1514 AssocItemKind::TyAlias(box TyAliasKind(_, _, bounds, body)) => {
1515 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1516 self.check_type_no_bounds(bounds, "`impl`s");
1522 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1523 self.invalid_visibility(&item.vis, None);
1524 if let AssocItemKind::Fn(box FnKind(_, sig, _, _)) = &item.kind {
1525 self.check_trait_fn_not_const(sig.header.constness);
1526 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1530 if let AssocItemKind::Const(..) = item.kind {
1531 self.check_item_named(item.ident, "const");
1534 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1538 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1539 /// like it's setting an associated type, provide an appropriate suggestion.
1540 fn deny_equality_constraints(
1541 this: &mut AstValidator<'_>,
1542 predicate: &WhereEqPredicate,
1543 generics: &Generics,
1545 let mut err = this.err_handler().struct_span_err(
1547 "equality constraints are not yet supported in `where` clauses",
1549 err.span_label(predicate.span, "not supported");
1551 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1552 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1553 if let TyKind::Path(None, path) = &qself.ty.kind {
1554 match &path.segments[..] {
1555 [PathSegment { ident, args: None, .. }] => {
1556 for param in &generics.params {
1557 if param.ident == *ident {
1559 match &full_path.segments[qself.position..] {
1560 [PathSegment { ident, args, .. }] => {
1561 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1562 let mut assoc_path = full_path.clone();
1563 // Remove `Bar` from `Foo::Bar`.
1564 assoc_path.segments.pop();
1565 let len = assoc_path.segments.len() - 1;
1566 let gen_args = args.as_ref().map(|p| (**p).clone());
1567 // Build `<Bar = RhsTy>`.
1568 let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
1569 id: rustc_ast::node_id::DUMMY_NODE_ID,
1572 kind: AssocTyConstraintKind::Equality {
1573 ty: predicate.rhs_ty.clone(),
1577 // Add `<Bar = RhsTy>` to `Foo`.
1578 match &mut assoc_path.segments[len].args {
1579 Some(args) => match args.deref_mut() {
1580 GenericArgs::Parenthesized(_) => continue,
1581 GenericArgs::AngleBracketed(args) => {
1582 args.args.push(arg);
1586 *empty_args = AngleBracketedArgs {
1593 err.span_suggestion_verbose(
1596 "if `{}` is an associated type you're trying to set, \
1597 use the associated type binding syntax",
1603 pprust::path_to_string(&assoc_path)
1605 Applicability::MaybeIncorrect,
1618 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1623 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1624 let mut validator = AstValidator {
1627 in_trait_impl: false,
1628 has_proc_macro_decls: false,
1629 outer_impl_trait: None,
1630 bound_context: None,
1631 is_impl_trait_banned: false,
1632 is_assoc_ty_bound_banned: false,
1635 visit::walk_crate(&mut validator, krate);
1637 validator.has_proc_macro_decls