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::{self, State};
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::{
19 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
21 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
22 use rustc_session::Session;
23 use rustc_span::source_map::Spanned;
24 use rustc_span::symbol::{kw, sym, Ident};
26 use rustc_target::spec::abi;
28 use std::ops::{Deref, DerefMut};
30 const MORE_EXTERN: &str =
31 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
33 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
39 struct AstValidator<'a> {
42 /// The span of the `extern` in an `extern { ... }` block, if any.
43 extern_mod: Option<&'a Item>,
45 /// Are we inside a trait impl?
48 in_const_trait_impl: bool,
50 has_proc_macro_decls: bool,
52 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
53 /// Nested `impl Trait` _is_ allowed in associated type position,
54 /// e.g., `impl Iterator<Item = impl Debug>`.
55 outer_impl_trait: Option<Span>,
57 is_tilde_const_allowed: bool,
59 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
60 /// or `Foo::Bar<impl Trait>`
61 is_impl_trait_banned: bool,
63 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
64 /// certain positions.
65 is_assoc_ty_bound_banned: bool,
67 /// Used to allow `let` expressions in certain syntactic locations.
70 lint_buffer: &'a mut LintBuffer,
73 impl<'a> AstValidator<'a> {
74 fn with_in_trait_impl(
77 constness: Option<Const>,
78 f: impl FnOnce(&mut Self),
80 let old = mem::replace(&mut self.in_trait_impl, is_in);
82 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
84 self.in_trait_impl = old;
85 self.in_const_trait_impl = old_const;
88 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
89 let old = mem::replace(&mut self.is_impl_trait_banned, true);
91 self.is_impl_trait_banned = old;
94 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
95 let old = mem::replace(&mut self.is_tilde_const_allowed, true);
97 self.is_tilde_const_allowed = old;
100 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
101 let old = mem::replace(&mut self.is_tilde_const_allowed, false);
103 self.is_tilde_const_allowed = old;
106 fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
107 let old = mem::replace(&mut self.is_let_allowed, allowed);
109 self.is_let_allowed = old;
112 /// Emits an error banning the `let` expression provided in the given location.
113 fn ban_let_expr(&self, expr: &'a Expr) {
114 let sess = &self.session;
115 if sess.opts.unstable_features.is_nightly_build() {
116 sess.struct_span_err(expr.span, "`let` expressions are not supported here")
117 .note("only supported directly in conditions of `if`- and `while`-expressions")
118 .note("as well as when nested within `&&` and parentheses in those conditions")
121 sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
122 .note("variable declaration using `let` is a statement")
130 before_predicates: &[WherePredicate],
131 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
133 if !before_predicates.is_empty() {
134 let mut state = State::new();
135 if !where_clauses.1.0 {
137 state.word_space("where");
139 state.word_space(",");
141 let mut first = true;
142 for p in before_predicates.iter() {
144 state.word_space(",");
147 state.print_where_predicate(p);
149 let suggestion = state.s.eof();
150 self.lint_buffer.buffer_lint_with_diagnostic(
151 DEPRECATED_WHERE_CLAUSE_LOCATION,
154 "where clause not allowed here",
155 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
156 where_clauses.1.1.shrink_to_hi(),
163 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
164 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
166 self.is_assoc_ty_bound_banned = old;
169 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
170 let old = mem::replace(&mut self.outer_impl_trait, outer);
172 self.with_banned_tilde_const(f);
176 self.outer_impl_trait = old;
179 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
180 match constraint.kind {
181 AssocConstraintKind::Equality { .. } => {}
182 AssocConstraintKind::Bound { .. } => {
183 if self.is_assoc_ty_bound_banned {
184 self.err_handler().span_err(
186 "associated type bounds are not allowed within structs, enums, or unions",
191 self.visit_assoc_constraint(constraint);
194 // Mirrors `visit::walk_ty`, but tracks relevant state.
195 fn walk_ty(&mut self, t: &'a Ty) {
197 TyKind::ImplTrait(..) => {
198 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
200 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
201 TyKind::Path(ref qself, ref path) => {
203 // - `Option<impl Trait>`
204 // - `option::Option<impl Trait>`
205 // - `option::Option<T>::Foo<impl Trait>
208 // - `<impl Trait>::Foo`
209 // - `option::Option<impl Trait>::Foo`.
211 // To implement this, we disallow `impl Trait` from `qself`
212 // (for cases like `<impl Trait>::Foo>`)
213 // but we allow `impl Trait` in `GenericArgs`
214 // iff there are no more PathSegments.
215 if let Some(ref qself) = *qself {
216 // `impl Trait` in `qself` is always illegal
217 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
220 // Note that there should be a call to visit_path here,
221 // so if any logic is added to process `Path`s a call to it should be
222 // added both in visit_path and here. This code mirrors visit::walk_path.
223 for (i, segment) in path.segments.iter().enumerate() {
224 // Allow `impl Trait` iff we're on the final path segment
225 if i == path.segments.len() - 1 {
226 self.visit_path_segment(path.span, segment);
228 self.with_banned_impl_trait(|this| {
229 this.visit_path_segment(path.span, segment)
234 _ => visit::walk_ty(self, t),
238 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
239 if let Some(ident) = field.ident {
240 if ident.name == kw::Underscore {
241 self.visit_vis(&field.vis);
242 self.visit_ident(ident);
243 self.visit_ty_common(&field.ty);
244 self.walk_ty(&field.ty);
245 walk_list!(self, visit_attribute, &field.attrs);
249 self.visit_field_def(field);
252 fn err_handler(&self) -> &rustc_errors::Handler {
253 &self.session.diagnostic()
256 fn check_lifetime(&self, ident: Ident) {
257 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
258 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
259 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
263 fn check_label(&self, ident: Ident) {
264 if ident.without_first_quote().is_reserved() {
266 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
270 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
271 if let VisibilityKind::Inherited = vis.kind {
276 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
277 if vis.kind.is_pub() {
278 err.span_label(vis.span, "`pub` not permitted here because it's implied");
280 if let Some(note) = note {
286 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
287 for Param { pat, .. } in &decl.inputs {
289 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
290 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
291 report_err(pat.span, Some(ident), true)
293 _ => report_err(pat.span, None, false),
298 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
299 if let Async::Yes { span, .. } = asyncness {
304 "functions in traits cannot be declared `async`"
306 .span_label(span, "`async` because of this")
307 .note("`async` trait functions are not currently supported")
308 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
313 fn check_trait_fn_not_const(&self, constness: Const) {
314 if let Const::Yes(span) = constness {
319 "functions in traits cannot be declared const"
321 .span_label(span, "functions in traits cannot be const")
326 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
327 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
328 for bound in bounds {
329 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
330 let mut err = self.err_handler().struct_span_err(
332 &format!("`?Trait` is not permitted in {}", where_),
335 let path_str = pprust::path_to_string(&poly.trait_ref.path);
336 err.note(&format!("traits are `?{}` by default", path_str));
343 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
344 // Check only lifetime parameters are present and that the lifetime
345 // parameters that are present have no bounds.
346 let non_lt_param_spans: Vec<_> = params
348 .filter_map(|param| match param.kind {
349 GenericParamKind::Lifetime { .. } => {
350 if !param.bounds.is_empty() {
351 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
353 .span_err(spans, "lifetime bounds cannot be used in this context");
357 _ => Some(param.ident.span),
360 if !non_lt_param_spans.is_empty() {
361 self.err_handler().span_err(
363 "only lifetime parameters can be used in this context",
368 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
369 self.check_decl_num_args(fn_decl);
370 self.check_decl_cvaradic_pos(fn_decl);
371 self.check_decl_attrs(fn_decl);
372 self.check_decl_self_param(fn_decl, self_semantic);
375 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
376 /// Error is fatal to prevent errors during typechecking
377 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
378 let max_num_args: usize = u16::MAX.into();
379 if fn_decl.inputs.len() > max_num_args {
380 let Param { span, .. } = fn_decl.inputs[0];
381 self.err_handler().span_fatal(
383 &format!("function can not have more than {} arguments", max_num_args),
388 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
389 match &*fn_decl.inputs {
390 [Param { ty, span, .. }] => {
391 if let TyKind::CVarArgs = ty.kind {
392 self.err_handler().span_err(
394 "C-variadic function must be declared with at least one named argument",
399 for Param { ty, span, .. } in ps {
400 if let TyKind::CVarArgs = ty.kind {
401 self.err_handler().span_err(
403 "`...` must be the last argument of a C-variadic function",
412 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
416 .flat_map(|i| i.attrs.as_ref())
418 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
419 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
422 if attr.is_doc_comment() {
426 "documentation comments cannot be applied to function parameters",
428 .span_label(attr.span, "doc comments are not allowed here")
431 self.err_handler().span_err(
433 "allow, cfg, cfg_attr, deny, \
434 forbid, and warn are the only allowed built-in attributes in function parameters",
440 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
441 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
446 "`self` parameter is only allowed in associated functions",
448 .span_label(param.span, "not semantically valid as function parameter")
449 .note("associated functions are those in `impl` or `trait` definitions")
455 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
456 if let Defaultness::Default(def_span) = defaultness {
457 let span = self.session.source_map().guess_head_span(span);
459 .struct_span_err(span, "`default` is only allowed on items in trait impls")
460 .span_label(def_span, "`default` because of this")
465 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
467 .struct_span_err(sp, msg)
469 self.session.source_map().end_point(sp),
470 &format!("provide a definition for the {}", ctx),
472 Applicability::HasPlaceholders,
477 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
479 let msg = format!("associated {} in `impl` without body", ctx);
480 self.error_item_without_body(sp, ctx, &msg, sugg);
484 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
485 let span = match bounds {
488 [b0, .., bl] => b0.span().to(bl.span()),
491 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
495 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
496 let cannot_have = |span, descr, remove_descr| {
500 &format!("`type`s inside `extern` blocks cannot have {}", descr),
504 &format!("remove the {}", remove_descr),
506 Applicability::MaybeIncorrect,
508 .span_label(self.current_extern_span(), "`extern` block begins here")
513 if !generics.params.is_empty() {
514 cannot_have(generics.span, "generic parameters", "generic parameters");
517 if !generics.where_clause.predicates.is_empty() {
518 cannot_have(where_span, "`where` clauses", "`where` clause");
522 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
523 let Some(body) = body else {
527 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
528 .span_label(ident.span, "cannot have a body")
529 .span_label(body, "the invalid body")
531 self.current_extern_span(),
533 "`extern` blocks define existing foreign {0}s and {0}s \
534 inside of them cannot have a body",
542 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
543 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
544 let Some(body) = body else {
548 .struct_span_err(ident.span, "incorrect function inside `extern` block")
549 .span_label(ident.span, "cannot have a body")
552 "remove the invalid body",
554 Applicability::MaybeIncorrect,
557 "you might have meant to write a function accessible through FFI, \
558 which can be done by writing `extern fn` outside of the `extern` block",
561 self.current_extern_span(),
562 "`extern` blocks define existing foreign functions and functions \
563 inside of them cannot have a body",
569 fn current_extern_span(&self) -> Span {
570 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
573 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
574 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
575 if header.has_qualifiers() {
577 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
578 .span_label(self.current_extern_span(), "in this `extern` block")
579 .span_suggestion_verbose(
580 span.until(ident.span.shrink_to_lo()),
581 "remove the qualifiers",
583 Applicability::MaybeIncorrect,
589 /// An item in `extern { ... }` cannot use non-ascii identifier.
590 fn check_foreign_item_ascii_only(&self, ident: Ident) {
591 if !ident.as_str().is_ascii() {
596 "items in `extern` blocks cannot use non-ascii identifiers",
598 .span_label(self.current_extern_span(), "in this `extern` block")
600 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
607 /// Reject C-varadic type unless the function is foreign,
608 /// or free and `unsafe extern "C"` semantically.
609 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
610 match (fk.ctxt(), fk.header()) {
611 (Some(FnCtxt::Foreign), _) => return,
612 (Some(FnCtxt::Free), Some(header)) => match header.ext {
613 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
614 if matches!(header.unsafety, Unsafe::Yes(_)) =>
623 for Param { ty, span, .. } in &fk.decl().inputs {
624 if let TyKind::CVarArgs = ty.kind {
628 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
635 fn check_item_named(&self, ident: Ident, kind: &str) {
636 if ident.name != kw::Underscore {
640 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
641 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
645 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
646 if ident.name.as_str().is_ascii() {
649 let head_span = self.session.source_map().guess_head_span(item_span);
654 "`#[no_mangle]` requires ASCII identifier"
659 fn check_mod_file_item_asciionly(&self, ident: Ident) {
660 if ident.name.as_str().is_ascii() {
667 "trying to load file for module `{}` with non-ascii identifier name",
670 .help("consider using `#[path]` attribute to specify filesystem path")
674 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
675 if !generics.params.is_empty() {
680 "auto traits cannot have generic parameters"
682 .span_label(ident_span, "auto trait cannot have generic parameters")
685 "remove the parameters",
687 Applicability::MachineApplicable,
693 fn emit_e0568(&self, span: Span, ident_span: Span) {
698 "auto traits cannot have super traits or lifetime bounds"
700 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
703 "remove the super traits or lifetime bounds",
705 Applicability::MachineApplicable,
710 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
711 if let [.., last] = &bounds[..] {
712 let span = ident_span.shrink_to_hi().to(last.span());
713 self.emit_e0568(span, ident_span);
717 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
718 if !where_clause.predicates.is_empty() {
719 self.emit_e0568(where_clause.span, ident_span);
723 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
724 if !trait_items.is_empty() {
725 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
726 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
731 "auto traits cannot have associated items"
735 "remove these associated items",
737 Applicability::MachineApplicable,
739 .span_label(ident_span, "auto trait cannot have associated items")
744 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
745 // Lifetimes always come first.
746 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
747 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
748 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
752 let args_sugg = data.args.iter().filter_map(|a| match a {
753 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
756 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
758 // Constraints always come last.
759 let constraint_sugg = data.args.iter().filter_map(|a| match a {
760 AngleBracketedArg::Arg(_) => None,
761 AngleBracketedArg::Constraint(c) => {
762 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
767 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
771 /// Enforce generic args coming before constraints in `<...>` of a path segment.
772 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
773 // Early exit in case it's partitioned as it should be.
774 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
777 // Find all generic argument coming after the first constraint...
778 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
779 data.args.iter().partition_map(|arg| match arg {
780 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
781 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
783 let args_len = arg_spans.len();
784 let constraint_len = constraint_spans.len();
785 // ...and then error:
789 "generic arguments must come before the first constraint",
791 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
793 *arg_spans.iter().last().unwrap(),
794 &format!("generic argument{}", pluralize!(args_len)),
796 .span_labels(constraint_spans, "")
797 .span_labels(arg_spans, "")
798 .span_suggestion_verbose(
801 "move the constraint{} after the generic argument{}",
802 pluralize!(constraint_len),
805 self.correct_generic_order_suggestion(&data),
806 Applicability::MachineApplicable,
811 fn visit_ty_common(&mut self, ty: &'a Ty) {
813 TyKind::BareFn(ref bfty) => {
814 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
815 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
820 "patterns aren't allowed in function pointer types"
824 self.check_late_bound_lifetime_defs(&bfty.generic_params);
825 if let Extern::Implicit = bfty.ext {
826 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
827 self.maybe_lint_missing_abi(sig_span, ty.id);
830 TyKind::TraitObject(ref bounds, ..) => {
831 let mut any_lifetime_bounds = false;
832 for bound in bounds {
833 if let GenericBound::Outlives(ref lifetime) = *bound {
834 if any_lifetime_bounds {
839 "only a single explicit lifetime bound is permitted"
844 any_lifetime_bounds = true;
847 self.no_questions_in_bounds(bounds, "trait object types", false);
849 TyKind::ImplTrait(_, ref bounds) => {
850 if self.is_impl_trait_banned {
855 "`impl Trait` is not allowed in path parameters"
860 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
865 "nested `impl Trait` is not allowed"
867 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
868 .span_label(ty.span, "nested `impl Trait` here")
872 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
873 self.err_handler().span_err(ty.span, "at least one trait must be specified");
880 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
881 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
882 // call site which do not have a macro backtrace. See #61963.
883 let is_macro_callsite = self
886 .span_to_snippet(span)
887 .map(|snippet| snippet.starts_with("#["))
889 if !is_macro_callsite {
890 self.lint_buffer.buffer_lint_with_diagnostic(
894 "extern declarations without an explicit ABI are deprecated",
895 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
901 /// Checks that generic parameters are in the correct order,
902 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
903 fn validate_generic_param_order(
904 handler: &rustc_errors::Handler,
905 generics: &[GenericParam],
908 let mut max_param: Option<ParamKindOrd> = None;
909 let mut out_of_order = FxHashMap::default();
910 let mut param_idents = Vec::with_capacity(generics.len());
912 for (idx, param) in generics.iter().enumerate() {
913 let ident = param.ident;
914 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
915 let (ord_kind, ident) = match ¶m.kind {
916 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
917 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
918 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
919 let ty = pprust::ty_to_string(ty);
920 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
923 param_idents.push((kind, ord_kind, bounds, idx, ident));
925 Some(max_param) if max_param > ord_kind => {
926 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
929 Some(_) | None => max_param = Some(ord_kind),
933 if !out_of_order.is_empty() {
934 let mut ordered_params = "<".to_string();
935 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
936 let mut first = true;
937 for (kind, _, bounds, _, ident) in param_idents {
939 ordered_params += ", ";
941 ordered_params += &ident;
943 if !bounds.is_empty() {
944 ordered_params += ": ";
945 ordered_params += &pprust::bounds_to_string(&bounds);
949 GenericParamKind::Type { default: Some(default) } => {
950 ordered_params += " = ";
951 ordered_params += &pprust::ty_to_string(default);
953 GenericParamKind::Type { default: None } => (),
954 GenericParamKind::Lifetime => (),
955 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
956 ordered_params += " = ";
957 ordered_params += &pprust::expr_to_string(&*default.value);
959 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
964 ordered_params += ">";
966 for (param_ord, (max_param, spans)) in &out_of_order {
967 let mut err = handler.struct_span_err(
970 "{} parameters must be declared prior to {} parameters",
971 param_ord, max_param,
976 "reorder the parameters: lifetimes, then consts and types",
977 ordered_params.clone(),
978 Applicability::MachineApplicable,
985 impl<'a> Visitor<'a> for AstValidator<'a> {
986 fn visit_attribute(&mut self, attr: &Attribute) {
987 validate_attr::check_meta(&self.session.parse_sess, attr);
990 fn visit_expr(&mut self, expr: &'a Expr) {
991 self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
992 ExprKind::If(cond, then, opt_else) => {
993 this.visit_block(then);
994 walk_list!(this, visit_expr, opt_else);
995 this.with_let_allowed(true, |this, _| this.visit_expr(cond));
998 ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
999 ExprKind::Match(expr, arms) => {
1000 this.visit_expr(expr);
1002 this.visit_expr(&arm.body);
1003 this.visit_pat(&arm.pat);
1004 walk_list!(this, visit_attribute, &arm.attrs);
1005 if let Some(ref guard) = arm.guard {
1006 if let ExprKind::Let(_, ref expr, _) = guard.kind {
1007 this.with_let_allowed(true, |this, _| this.visit_expr(expr));
1013 ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1014 this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
1017 ExprKind::While(cond, then, opt_label) => {
1018 walk_list!(this, visit_label, opt_label);
1019 this.visit_block(then);
1020 this.with_let_allowed(true, |this, _| this.visit_expr(cond));
1023 _ => visit::walk_expr(this, expr),
1027 fn visit_ty(&mut self, ty: &'a Ty) {
1028 self.visit_ty_common(ty);
1032 fn visit_label(&mut self, label: &'a Label) {
1033 self.check_label(label.ident);
1034 visit::walk_label(self, label);
1037 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
1038 self.check_lifetime(lifetime.ident);
1039 visit::walk_lifetime(self, lifetime);
1042 fn visit_field_def(&mut self, s: &'a FieldDef) {
1043 visit::walk_field_def(self, s)
1046 fn visit_item(&mut self, item: &'a Item) {
1047 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1048 self.has_proc_macro_decls = true;
1051 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1052 self.check_nomangle_item_asciionly(item.ident, item.span);
1056 ItemKind::Impl(box Impl {
1062 of_trait: Some(ref t),
1066 self.with_in_trait_impl(true, Some(constness), |this| {
1067 this.invalid_visibility(&item.vis, None);
1068 if let TyKind::Err = self_ty.kind {
1072 "`impl Trait for .. {}` is an obsolete syntax",
1074 .help("use `auto trait Trait {}` instead")
1077 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1082 "negative impls cannot be unsafe"
1084 .span_label(sp, "negative because of this")
1085 .span_label(span, "unsafe because of this")
1089 this.visit_vis(&item.vis);
1090 this.visit_ident(item.ident);
1091 if let Const::Yes(_) = constness {
1092 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1094 this.visit_generics(generics);
1096 this.visit_trait_ref(t);
1097 this.visit_ty(self_ty);
1099 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1101 return; // Avoid visiting again.
1103 ItemKind::Impl(box Impl {
1113 let error = |annotation_span, annotation| {
1114 let mut err = self.err_handler().struct_span_err(
1116 &format!("inherent impls cannot be {}", annotation),
1118 err.span_label(annotation_span, &format!("{} because of this", annotation));
1119 err.span_label(self_ty.span, "inherent impl for this type");
1123 self.invalid_visibility(
1125 Some("place qualifiers on individual impl items instead"),
1127 if let Unsafe::Yes(span) = unsafety {
1128 error(span, "unsafe").code(error_code!(E0197)).emit();
1130 if let ImplPolarity::Negative(span) = polarity {
1131 error(span, "negative").emit();
1133 if let Defaultness::Default(def_span) = defaultness {
1134 error(def_span, "`default`")
1135 .note("only trait implementations may be annotated with `default`")
1138 if let Const::Yes(span) = constness {
1139 error(span, "`const`")
1140 .note("only trait implementations may be annotated with `const`")
1144 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1145 self.check_defaultness(item.span, defaultness);
1148 let msg = "free function without a body";
1149 self.error_item_without_body(item.span, "function", msg, " { <body> }");
1151 self.visit_vis(&item.vis);
1152 self.visit_ident(item.ident);
1153 if let Const::Yes(_) = sig.header.constness {
1154 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1156 self.visit_generics(generics);
1158 let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
1159 self.visit_fn(kind, item.span, item.id);
1160 walk_list!(self, visit_attribute, &item.attrs);
1161 return; // Avoid visiting again.
1163 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1164 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1165 self.invalid_visibility(
1167 Some("place qualifiers on individual foreign items instead"),
1169 if let Unsafe::Yes(span) = unsafety {
1170 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1173 self.maybe_lint_missing_abi(item.span, item.id);
1175 visit::walk_item(self, item);
1176 self.extern_mod = old_item;
1177 return; // Avoid visiting again.
1179 ItemKind::Enum(ref def, _) => {
1180 for variant in &def.variants {
1181 self.invalid_visibility(&variant.vis, None);
1182 for field in variant.data.fields() {
1183 self.invalid_visibility(&field.vis, None);
1187 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1188 if is_auto == IsAuto::Yes {
1189 // Auto traits cannot have generics, super traits nor contain items.
1190 self.deny_generic_params(generics, item.ident.span);
1191 self.deny_super_traits(bounds, item.ident.span);
1192 self.deny_where_clause(&generics.where_clause, item.ident.span);
1193 self.deny_items(items, item.ident.span);
1195 self.no_questions_in_bounds(bounds, "supertraits", true);
1197 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1198 // context for the supertraits.
1199 self.visit_vis(&item.vis);
1200 self.visit_ident(item.ident);
1201 self.visit_generics(generics);
1202 self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
1203 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1204 walk_list!(self, visit_attribute, &item.attrs);
1207 ItemKind::Mod(unsafety, ref mod_kind) => {
1208 if let Unsafe::Yes(span) = unsafety {
1209 self.err_handler().span_err(span, "module cannot be declared unsafe");
1211 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1212 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1213 && !self.session.contains_name(&item.attrs, sym::path)
1215 self.check_mod_file_item_asciionly(item.ident);
1218 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1219 // Duplicating the `Visitor` logic allows catching all cases
1220 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1222 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1223 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1224 // it uses `visit_ty_common`, which doesn't contain that specific check.
1225 VariantData::Struct(ref fields, ..) => {
1226 self.visit_vis(&item.vis);
1227 self.visit_ident(item.ident);
1228 self.visit_generics(generics);
1229 self.with_banned_assoc_ty_bound(|this| {
1230 walk_list!(this, visit_struct_field_def, fields);
1232 walk_list!(self, visit_attribute, &item.attrs);
1237 ItemKind::Union(ref vdata, ref generics) => {
1238 if vdata.fields().is_empty() {
1239 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1242 VariantData::Struct(ref fields, ..) => {
1243 self.visit_vis(&item.vis);
1244 self.visit_ident(item.ident);
1245 self.visit_generics(generics);
1246 self.with_banned_assoc_ty_bound(|this| {
1247 walk_list!(this, visit_struct_field_def, fields);
1249 walk_list!(self, visit_attribute, &item.attrs);
1255 ItemKind::Const(def, .., None) => {
1256 self.check_defaultness(item.span, def);
1257 let msg = "free constant item without body";
1258 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1260 ItemKind::Static(.., None) => {
1261 let msg = "free static item without body";
1262 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1264 ItemKind::TyAlias(box TyAlias {
1271 self.check_defaultness(item.span, defaultness);
1273 let msg = "free type alias without body";
1274 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1276 self.check_type_no_bounds(bounds, "this context");
1277 if where_clauses.1.0 {
1278 let mut err = self.err_handler().struct_span_err(
1280 "where clauses are not allowed after the type for type aliases",
1283 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1291 visit::walk_item(self, item);
1294 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1296 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1297 self.check_defaultness(fi.span, *defaultness);
1298 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1299 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1300 self.check_foreign_item_ascii_only(fi.ident);
1302 ForeignItemKind::TyAlias(box TyAlias {
1310 self.check_defaultness(fi.span, *defaultness);
1311 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1312 self.check_type_no_bounds(bounds, "`extern` blocks");
1313 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1314 self.check_foreign_item_ascii_only(fi.ident);
1316 ForeignItemKind::Static(_, _, body) => {
1317 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1318 self.check_foreign_item_ascii_only(fi.ident);
1320 ForeignItemKind::MacCall(..) => {}
1323 visit::walk_foreign_item(self, fi)
1326 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1327 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1328 match *generic_args {
1329 GenericArgs::AngleBracketed(ref data) => {
1330 self.check_generic_args_before_constraints(data);
1332 for arg in &data.args {
1334 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1335 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1336 // are allowed to contain nested `impl Trait`.
1337 AngleBracketedArg::Constraint(constraint) => {
1338 self.with_impl_trait(None, |this| {
1339 this.visit_assoc_constraint_from_generic_args(constraint);
1345 GenericArgs::Parenthesized(ref data) => {
1346 walk_list!(self, visit_ty, &data.inputs);
1347 if let FnRetTy::Ty(ty) = &data.output {
1348 // `-> Foo` syntax is essentially an associated type binding,
1349 // so it is also allowed to contain nested `impl Trait`.
1350 self.with_impl_trait(None, |this| this.visit_ty(ty));
1356 fn visit_generics(&mut self, generics: &'a Generics) {
1357 let mut prev_param_default = None;
1358 for param in &generics.params {
1360 GenericParamKind::Lifetime => (),
1361 GenericParamKind::Type { default: Some(_), .. }
1362 | GenericParamKind::Const { default: Some(_), .. } => {
1363 prev_param_default = Some(param.ident.span);
1365 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1366 if let Some(span) = prev_param_default {
1367 let mut err = self.err_handler().struct_span_err(
1369 "generic parameters with a default must be trailing",
1378 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1380 for predicate in &generics.where_clause.predicates {
1381 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1382 deny_equality_constraints(self, predicate, generics);
1385 walk_list!(self, visit_generic_param, &generics.params);
1386 for predicate in &generics.where_clause.predicates {
1388 WherePredicate::BoundPredicate(bound_pred) => {
1389 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1390 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1392 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1393 // binder and thus we only allow a single level of quantification. However,
1394 // the syntax of Rust permits quantification in two places in where clauses,
1395 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1396 // defined, then error.
1397 if !bound_pred.bound_generic_params.is_empty() {
1398 for bound in &bound_pred.bounds {
1400 GenericBound::Trait(t, _) => {
1401 if !t.bound_generic_params.is_empty() {
1406 "nested quantification of lifetimes"
1411 GenericBound::Outlives(_) => {}
1418 self.visit_where_predicate(predicate);
1422 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1423 if let GenericParamKind::Lifetime { .. } = param.kind {
1424 self.check_lifetime(param.ident);
1426 visit::walk_generic_param(self, param);
1429 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1431 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1432 if !self.is_tilde_const_allowed {
1434 .struct_span_err(bound.span(), "`~const` is not allowed here")
1435 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1440 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1442 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1448 visit::walk_param_bound(self, bound)
1451 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1452 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1453 visit::walk_poly_trait_ref(self, t, m);
1456 fn visit_variant_data(&mut self, s: &'a VariantData) {
1457 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1462 enum_definition: &'a EnumDef,
1463 generics: &'a Generics,
1467 self.with_banned_assoc_ty_bound(|this| {
1468 visit::walk_enum_def(this, enum_definition, generics, item_id)
1472 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1473 // Only associated `fn`s can have `self` parameters.
1474 let self_semantic = match fk.ctxt() {
1475 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1476 _ => SelfSemantic::No,
1478 self.check_fn_decl(fk.decl(), self_semantic);
1480 self.check_c_varadic_type(fk);
1482 // Functions cannot both be `const async`
1483 if let Some(FnHeader {
1484 constness: Const::Yes(cspan),
1485 asyncness: Async::Yes { span: aspan, .. },
1491 vec![*cspan, *aspan],
1492 "functions cannot be both `const` and `async`",
1494 .span_label(*cspan, "`const` because of this")
1495 .span_label(*aspan, "`async` because of this")
1496 .span_label(span, "") // Point at the fn header.
1503 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
1508 self.maybe_lint_missing_abi(*sig_span, id);
1511 // Functions without bodies cannot have patterns.
1512 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1513 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1514 let (code, msg, label) = match ctxt {
1515 FnCtxt::Foreign => (
1517 "patterns aren't allowed in foreign function declarations",
1518 "pattern not allowed in foreign function",
1522 "patterns aren't allowed in functions without bodies",
1523 "pattern not allowed in function without body",
1526 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1527 if let Some(ident) = ident {
1528 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1529 self.lint_buffer.buffer_lint_with_diagnostic(
1530 PATTERNS_IN_FNS_WITHOUT_BODY,
1539 .struct_span_err(span, msg)
1540 .span_label(span, label)
1547 visit::walk_fn(self, fk, span);
1550 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1551 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1552 self.check_nomangle_item_asciionly(item.ident, item.span);
1555 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1556 self.check_defaultness(item.span, item.kind.defaultness());
1559 if ctxt == AssocCtxt::Impl {
1561 AssocItemKind::Const(_, _, body) => {
1562 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1564 AssocItemKind::Fn(box Fn { body, .. }) => {
1565 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1567 AssocItemKind::TyAlias(box TyAlias {
1570 where_predicates_split,
1575 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1576 self.check_type_no_bounds(bounds, "`impl`s");
1578 self.check_gat_where(
1580 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1589 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1590 self.invalid_visibility(&item.vis, None);
1591 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1592 self.check_trait_fn_not_const(sig.header.constness);
1593 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1597 if let AssocItemKind::Const(..) = item.kind {
1598 self.check_item_named(item.ident, "const");
1602 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1603 if ctxt == AssocCtxt::Trait =>
1605 self.visit_vis(&item.vis);
1606 self.visit_ident(item.ident);
1607 walk_list!(self, visit_attribute, &item.attrs);
1608 self.with_tilde_const_allowed(|this| {
1609 this.visit_generics(generics);
1610 walk_list!(this, visit_param_bound, bounds);
1612 walk_list!(self, visit_ty, ty);
1614 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1615 if self.in_const_trait_impl
1616 || ctxt == AssocCtxt::Trait
1617 || matches!(sig.header.constness, Const::Yes(_)) =>
1619 self.visit_vis(&item.vis);
1620 self.visit_ident(item.ident);
1621 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1623 FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
1624 self.visit_fn(kind, item.span, item.id);
1627 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1632 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1633 /// like it's setting an associated type, provide an appropriate suggestion.
1634 fn deny_equality_constraints(
1635 this: &mut AstValidator<'_>,
1636 predicate: &WhereEqPredicate,
1637 generics: &Generics,
1639 let mut err = this.err_handler().struct_span_err(
1641 "equality constraints are not yet supported in `where` clauses",
1643 err.span_label(predicate.span, "not supported");
1645 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1646 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1647 if let TyKind::Path(None, path) = &qself.ty.kind {
1648 match &path.segments[..] {
1649 [PathSegment { ident, args: None, .. }] => {
1650 for param in &generics.params {
1651 if param.ident == *ident {
1653 match &full_path.segments[qself.position..] {
1654 [PathSegment { ident, args, .. }] => {
1655 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1656 let mut assoc_path = full_path.clone();
1657 // Remove `Bar` from `Foo::Bar`.
1658 assoc_path.segments.pop();
1659 let len = assoc_path.segments.len() - 1;
1660 let gen_args = args.as_ref().map(|p| (**p).clone());
1661 // Build `<Bar = RhsTy>`.
1662 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1663 id: rustc_ast::node_id::DUMMY_NODE_ID,
1666 kind: AssocConstraintKind::Equality {
1667 term: predicate.rhs_ty.clone().into(),
1671 // Add `<Bar = RhsTy>` to `Foo`.
1672 match &mut assoc_path.segments[len].args {
1673 Some(args) => match args.deref_mut() {
1674 GenericArgs::Parenthesized(_) => continue,
1675 GenericArgs::AngleBracketed(args) => {
1676 args.args.push(arg);
1680 *empty_args = AngleBracketedArgs {
1687 err.span_suggestion_verbose(
1690 "if `{}` is an associated type you're trying to set, \
1691 use the associated type binding syntax",
1697 pprust::path_to_string(&assoc_path)
1699 Applicability::MaybeIncorrect,
1711 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1712 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1713 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1714 for param in &generics.params {
1715 if param.ident == potential_param.ident {
1716 for bound in ¶m.bounds {
1717 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1719 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1720 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1721 potential_assoc.ident,
1723 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1724 let (args, span) = match &trait_segment.args {
1725 Some(args) => match args.deref() {
1726 ast::GenericArgs::AngleBracketed(args) => {
1727 let Some(arg) = args.args.last() else {
1731 format!(", {} = {}", assoc, ty),
1732 arg.span().shrink_to_hi(),
1738 format!("<{} = {}>", assoc, ty),
1739 trait_segment.span().shrink_to_hi(),
1742 err.multipart_suggestion(
1744 "if `{}::{}` is an associated type you're trying to set, \
1745 use the associated type binding syntax",
1746 trait_segment.ident, potential_assoc.ident,
1748 vec![(span, args), (predicate.span, String::new())],
1749 Applicability::MaybeIncorrect,
1759 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1764 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1765 let mut validator = AstValidator {
1768 in_trait_impl: false,
1769 in_const_trait_impl: false,
1770 has_proc_macro_decls: false,
1771 outer_impl_trait: None,
1772 is_tilde_const_allowed: false,
1773 is_impl_trait_banned: false,
1774 is_assoc_ty_bound_banned: false,
1775 is_let_allowed: false,
1778 visit::walk_crate(&mut validator, krate);
1780 validator.has_proc_macro_decls