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::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY};
19 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
20 use rustc_session::Session;
21 use rustc_span::source_map::Spanned;
22 use rustc_span::symbol::{kw, sym, Ident};
24 use rustc_target::spec::abi;
26 use std::ops::{Deref, 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 struct AstValidator<'a> {
40 /// The span of the `extern` in an `extern { ... }` block, if any.
41 extern_mod: Option<&'a Item>,
43 /// Are we inside a trait impl?
46 in_const_trait_impl: bool,
48 has_proc_macro_decls: bool,
50 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
51 /// Nested `impl Trait` _is_ allowed in associated type position,
52 /// e.g., `impl Iterator<Item = impl Debug>`.
53 outer_impl_trait: Option<Span>,
55 is_tilde_const_allowed: bool,
57 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
58 /// or `Foo::Bar<impl Trait>`
59 is_impl_trait_banned: bool,
61 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
62 /// certain positions.
63 is_assoc_ty_bound_banned: bool,
65 /// Used to allow `let` expressions in certain syntactic locations.
68 lint_buffer: &'a mut LintBuffer,
71 impl<'a> AstValidator<'a> {
72 fn with_in_trait_impl(
75 constness: Option<Const>,
76 f: impl FnOnce(&mut Self),
78 let old = mem::replace(&mut self.in_trait_impl, is_in);
80 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
82 self.in_trait_impl = old;
83 self.in_const_trait_impl = old_const;
86 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
87 let old = mem::replace(&mut self.is_impl_trait_banned, true);
89 self.is_impl_trait_banned = old;
92 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
93 let old = mem::replace(&mut self.is_tilde_const_allowed, true);
95 self.is_tilde_const_allowed = old;
98 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
99 let old = mem::replace(&mut self.is_tilde_const_allowed, false);
101 self.is_tilde_const_allowed = old;
104 fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
105 let old = mem::replace(&mut self.is_let_allowed, allowed);
107 self.is_let_allowed = old;
110 /// Emits an error banning the `let` expression provided in the given location.
111 fn ban_let_expr(&self, expr: &'a Expr) {
112 let sess = &self.session;
113 if sess.opts.unstable_features.is_nightly_build() {
114 sess.struct_span_err(expr.span, "`let` expressions are not supported here")
115 .note("only supported directly in conditions of `if`- and `while`-expressions")
116 .note("as well as when nested within `&&` and parentheses in those conditions")
119 sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
120 .note("variable declaration using `let` is a statement")
127 before_predicates: &[WherePredicate],
128 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
130 let sess = &self.session;
131 if !before_predicates.is_empty() {
132 let mut state = State::new();
133 if !where_clauses.1.0 {
135 state.word_space("where");
137 state.word_space(",");
139 let mut first = true;
140 for p in before_predicates.iter() {
142 state.word_space(",");
145 state.print_where_predicate(p);
147 let suggestion = state.s.eof();
148 sess.struct_span_err(where_clauses.0.1, "where clause not allowed here")
150 where_clauses.1.1.shrink_to_hi(),
153 Applicability::MachineApplicable,
159 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
160 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
162 self.is_assoc_ty_bound_banned = old;
165 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
166 let old = mem::replace(&mut self.outer_impl_trait, outer);
168 self.with_banned_tilde_const(f);
172 self.outer_impl_trait = old;
175 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
176 match constraint.kind {
177 AssocConstraintKind::Equality { .. } => {}
178 AssocConstraintKind::Bound { .. } => {
179 if self.is_assoc_ty_bound_banned {
180 self.err_handler().span_err(
182 "associated type bounds are not allowed within structs, enums, or unions",
187 self.visit_assoc_constraint(constraint);
190 // Mirrors `visit::walk_ty`, but tracks relevant state.
191 fn walk_ty(&mut self, t: &'a Ty) {
193 TyKind::ImplTrait(..) => {
194 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
196 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
197 TyKind::Path(ref qself, ref path) => {
199 // - `Option<impl Trait>`
200 // - `option::Option<impl Trait>`
201 // - `option::Option<T>::Foo<impl Trait>
204 // - `<impl Trait>::Foo`
205 // - `option::Option<impl Trait>::Foo`.
207 // To implement this, we disallow `impl Trait` from `qself`
208 // (for cases like `<impl Trait>::Foo>`)
209 // but we allow `impl Trait` in `GenericArgs`
210 // iff there are no more PathSegments.
211 if let Some(ref qself) = *qself {
212 // `impl Trait` in `qself` is always illegal
213 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
216 // Note that there should be a call to visit_path here,
217 // so if any logic is added to process `Path`s a call to it should be
218 // added both in visit_path and here. This code mirrors visit::walk_path.
219 for (i, segment) in path.segments.iter().enumerate() {
220 // Allow `impl Trait` iff we're on the final path segment
221 if i == path.segments.len() - 1 {
222 self.visit_path_segment(path.span, segment);
224 self.with_banned_impl_trait(|this| {
225 this.visit_path_segment(path.span, segment)
230 _ => visit::walk_ty(self, t),
234 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
235 if let Some(ident) = field.ident {
236 if ident.name == kw::Underscore {
237 self.visit_vis(&field.vis);
238 self.visit_ident(ident);
239 self.visit_ty_common(&field.ty);
240 self.walk_ty(&field.ty);
241 walk_list!(self, visit_attribute, &field.attrs);
245 self.visit_field_def(field);
248 fn err_handler(&self) -> &rustc_errors::Handler {
249 &self.session.diagnostic()
252 fn check_lifetime(&self, ident: Ident) {
253 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
254 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
255 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
259 fn check_label(&self, ident: Ident) {
260 if ident.without_first_quote().is_reserved() {
262 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
266 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
267 if let VisibilityKind::Inherited = vis.kind {
272 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
273 if vis.kind.is_pub() {
274 err.span_label(vis.span, "`pub` not permitted here because it's implied");
276 if let Some(note) = note {
282 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
283 for Param { pat, .. } in &decl.inputs {
285 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
286 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
287 report_err(pat.span, Some(ident), true)
289 _ => report_err(pat.span, None, false),
294 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
295 if let Async::Yes { span, .. } = asyncness {
300 "functions in traits cannot be declared `async`"
302 .span_label(span, "`async` because of this")
303 .note("`async` trait functions are not currently supported")
304 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
309 fn check_trait_fn_not_const(&self, constness: Const) {
310 if let Const::Yes(span) = constness {
315 "functions in traits cannot be declared const"
317 .span_label(span, "functions in traits cannot be const")
322 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
323 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
324 for bound in bounds {
325 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
326 let mut err = self.err_handler().struct_span_err(
328 &format!("`?Trait` is not permitted in {}", where_),
331 let path_str = pprust::path_to_string(&poly.trait_ref.path);
332 err.note(&format!("traits are `?{}` by default", path_str));
339 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
340 // Check only lifetime parameters are present and that the lifetime
341 // parameters that are present have no bounds.
342 let non_lt_param_spans: Vec<_> = params
344 .filter_map(|param| match param.kind {
345 GenericParamKind::Lifetime { .. } => {
346 if !param.bounds.is_empty() {
347 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
349 .span_err(spans, "lifetime bounds cannot be used in this context");
353 _ => Some(param.ident.span),
356 if !non_lt_param_spans.is_empty() {
357 self.err_handler().span_err(
359 "only lifetime parameters can be used in this context",
364 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
365 self.check_decl_num_args(fn_decl);
366 self.check_decl_cvaradic_pos(fn_decl);
367 self.check_decl_attrs(fn_decl);
368 self.check_decl_self_param(fn_decl, self_semantic);
371 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
372 /// Error is fatal to prevent errors during typechecking
373 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
374 let max_num_args: usize = u16::MAX.into();
375 if fn_decl.inputs.len() > max_num_args {
376 let Param { span, .. } = fn_decl.inputs[0];
377 self.err_handler().span_fatal(
379 &format!("function can not have more than {} arguments", max_num_args),
384 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
385 match &*fn_decl.inputs {
386 [Param { ty, span, .. }] => {
387 if let TyKind::CVarArgs = ty.kind {
388 self.err_handler().span_err(
390 "C-variadic function must be declared with at least one named argument",
395 for Param { ty, span, .. } in ps {
396 if let TyKind::CVarArgs = ty.kind {
397 self.err_handler().span_err(
399 "`...` must be the last argument of a C-variadic function",
408 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
412 .flat_map(|i| i.attrs.as_ref())
414 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
415 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
418 if attr.is_doc_comment() {
422 "documentation comments cannot be applied to function parameters",
424 .span_label(attr.span, "doc comments are not allowed here")
427 self.err_handler().span_err(
429 "allow, cfg, cfg_attr, deny, \
430 forbid, and warn are the only allowed built-in attributes in function parameters",
436 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
437 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
442 "`self` parameter is only allowed in associated functions",
444 .span_label(param.span, "not semantically valid as function parameter")
445 .note("associated functions are those in `impl` or `trait` definitions")
451 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
452 if let Defaultness::Default(def_span) = defaultness {
453 let span = self.session.source_map().guess_head_span(span);
455 .struct_span_err(span, "`default` is only allowed on items in trait impls")
456 .span_label(def_span, "`default` because of this")
461 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
463 .struct_span_err(sp, msg)
465 self.session.source_map().end_point(sp),
466 &format!("provide a definition for the {}", ctx),
468 Applicability::HasPlaceholders,
473 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
475 let msg = format!("associated {} in `impl` without body", ctx);
476 self.error_item_without_body(sp, ctx, &msg, sugg);
480 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
481 let span = match bounds {
484 [b0, .., bl] => b0.span().to(bl.span()),
487 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
491 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
492 let cannot_have = |span, descr, remove_descr| {
496 &format!("`type`s inside `extern` blocks cannot have {}", descr),
500 &format!("remove the {}", remove_descr),
502 Applicability::MaybeIncorrect,
504 .span_label(self.current_extern_span(), "`extern` block begins here")
509 if !generics.params.is_empty() {
510 cannot_have(generics.span, "generic parameters", "generic parameters");
513 if !generics.where_clause.predicates.is_empty() {
514 cannot_have(where_span, "`where` clauses", "`where` clause");
518 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
519 let Some(body) = body else {
523 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
524 .span_label(ident.span, "cannot have a body")
525 .span_label(body, "the invalid body")
527 self.current_extern_span(),
529 "`extern` blocks define existing foreign {0}s and {0}s \
530 inside of them cannot have a body",
538 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
539 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
540 let Some(body) = body else {
544 .struct_span_err(ident.span, "incorrect function inside `extern` block")
545 .span_label(ident.span, "cannot have a body")
548 "remove the invalid body",
550 Applicability::MaybeIncorrect,
553 "you might have meant to write a function accessible through FFI, \
554 which can be done by writing `extern fn` outside of the `extern` block",
557 self.current_extern_span(),
558 "`extern` blocks define existing foreign functions and functions \
559 inside of them cannot have a body",
565 fn current_extern_span(&self) -> Span {
566 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
569 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
570 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
571 if header.has_qualifiers() {
573 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
574 .span_label(self.current_extern_span(), "in this `extern` block")
575 .span_suggestion_verbose(
576 span.until(ident.span.shrink_to_lo()),
577 "remove the qualifiers",
579 Applicability::MaybeIncorrect,
585 /// An item in `extern { ... }` cannot use non-ascii identifier.
586 fn check_foreign_item_ascii_only(&self, ident: Ident) {
587 if !ident.as_str().is_ascii() {
592 "items in `extern` blocks cannot use non-ascii identifiers",
594 .span_label(self.current_extern_span(), "in this `extern` block")
596 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
603 /// Reject C-varadic type unless the function is foreign,
604 /// or free and `unsafe extern "C"` semantically.
605 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
606 match (fk.ctxt(), fk.header()) {
607 (Some(FnCtxt::Foreign), _) => return,
608 (Some(FnCtxt::Free), Some(header)) => match header.ext {
609 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
610 if matches!(header.unsafety, Unsafe::Yes(_)) =>
619 for Param { ty, span, .. } in &fk.decl().inputs {
620 if let TyKind::CVarArgs = ty.kind {
624 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
631 fn check_item_named(&self, ident: Ident, kind: &str) {
632 if ident.name != kw::Underscore {
636 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
637 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
641 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
642 if ident.name.as_str().is_ascii() {
645 let head_span = self.session.source_map().guess_head_span(item_span);
650 "`#[no_mangle]` requires ASCII identifier"
655 fn check_mod_file_item_asciionly(&self, ident: Ident) {
656 if ident.name.as_str().is_ascii() {
663 "trying to load file for module `{}` with non-ascii identifier name",
666 .help("consider using `#[path]` attribute to specify filesystem path")
670 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
671 if !generics.params.is_empty() {
676 "auto traits cannot have generic parameters"
678 .span_label(ident_span, "auto trait cannot have generic parameters")
681 "remove the parameters",
683 Applicability::MachineApplicable,
689 fn emit_e0568(&self, span: Span, ident_span: Span) {
694 "auto traits cannot have super traits or lifetime bounds"
696 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
699 "remove the super traits or lifetime bounds",
701 Applicability::MachineApplicable,
706 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
707 if let [.., last] = &bounds[..] {
708 let span = ident_span.shrink_to_hi().to(last.span());
709 self.emit_e0568(span, ident_span);
713 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
714 if !where_clause.predicates.is_empty() {
715 self.emit_e0568(where_clause.span, ident_span);
719 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
720 if !trait_items.is_empty() {
721 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
722 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
727 "auto traits cannot have associated items"
731 "remove these associated items",
733 Applicability::MachineApplicable,
735 .span_label(ident_span, "auto trait cannot have associated items")
740 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
741 // Lifetimes always come first.
742 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
743 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
744 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
748 let args_sugg = data.args.iter().filter_map(|a| match a {
749 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
752 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
754 // Constraints always come last.
755 let constraint_sugg = data.args.iter().filter_map(|a| match a {
756 AngleBracketedArg::Arg(_) => None,
757 AngleBracketedArg::Constraint(c) => {
758 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
763 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
767 /// Enforce generic args coming before constraints in `<...>` of a path segment.
768 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
769 // Early exit in case it's partitioned as it should be.
770 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
773 // Find all generic argument coming after the first constraint...
774 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
775 data.args.iter().partition_map(|arg| match arg {
776 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
777 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
779 let args_len = arg_spans.len();
780 let constraint_len = constraint_spans.len();
781 // ...and then error:
785 "generic arguments must come before the first constraint",
787 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
789 *arg_spans.iter().last().unwrap(),
790 &format!("generic argument{}", pluralize!(args_len)),
792 .span_labels(constraint_spans, "")
793 .span_labels(arg_spans, "")
794 .span_suggestion_verbose(
797 "move the constraint{} after the generic argument{}",
798 pluralize!(constraint_len),
801 self.correct_generic_order_suggestion(&data),
802 Applicability::MachineApplicable,
807 fn visit_ty_common(&mut self, ty: &'a Ty) {
809 TyKind::BareFn(ref bfty) => {
810 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
811 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
816 "patterns aren't allowed in function pointer types"
820 self.check_late_bound_lifetime_defs(&bfty.generic_params);
821 if let Extern::Implicit = bfty.ext {
822 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
823 self.maybe_lint_missing_abi(sig_span, ty.id);
826 TyKind::TraitObject(ref bounds, ..) => {
827 let mut any_lifetime_bounds = false;
828 for bound in bounds {
829 if let GenericBound::Outlives(ref lifetime) = *bound {
830 if any_lifetime_bounds {
835 "only a single explicit lifetime bound is permitted"
840 any_lifetime_bounds = true;
843 self.no_questions_in_bounds(bounds, "trait object types", false);
845 TyKind::ImplTrait(_, ref bounds) => {
846 if self.is_impl_trait_banned {
851 "`impl Trait` is not allowed in path parameters"
856 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
861 "nested `impl Trait` is not allowed"
863 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
864 .span_label(ty.span, "nested `impl Trait` here")
868 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
869 self.err_handler().span_err(ty.span, "at least one trait must be specified");
876 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
877 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
878 // call site which do not have a macro backtrace. See #61963.
879 let is_macro_callsite = self
882 .span_to_snippet(span)
883 .map(|snippet| snippet.starts_with("#["))
885 if !is_macro_callsite {
886 self.lint_buffer.buffer_lint_with_diagnostic(
890 "extern declarations without an explicit ABI are deprecated",
891 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
897 /// Checks that generic parameters are in the correct order,
898 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
899 fn validate_generic_param_order(
900 handler: &rustc_errors::Handler,
901 generics: &[GenericParam],
904 let mut max_param: Option<ParamKindOrd> = None;
905 let mut out_of_order = FxHashMap::default();
906 let mut param_idents = Vec::with_capacity(generics.len());
908 for (idx, param) in generics.iter().enumerate() {
909 let ident = param.ident;
910 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
911 let (ord_kind, ident) = match ¶m.kind {
912 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
913 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
914 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
915 let ty = pprust::ty_to_string(ty);
916 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
919 param_idents.push((kind, ord_kind, bounds, idx, ident));
921 Some(max_param) if max_param > ord_kind => {
922 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
925 Some(_) | None => max_param = Some(ord_kind),
929 if !out_of_order.is_empty() {
930 let mut ordered_params = "<".to_string();
931 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
932 let mut first = true;
933 for (kind, _, bounds, _, ident) in param_idents {
935 ordered_params += ", ";
937 ordered_params += &ident;
939 if !bounds.is_empty() {
940 ordered_params += ": ";
941 ordered_params += &pprust::bounds_to_string(&bounds);
945 GenericParamKind::Type { default: Some(default) } => {
946 ordered_params += " = ";
947 ordered_params += &pprust::ty_to_string(default);
949 GenericParamKind::Type { default: None } => (),
950 GenericParamKind::Lifetime => (),
951 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
952 ordered_params += " = ";
953 ordered_params += &pprust::expr_to_string(&*default.value);
955 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
960 ordered_params += ">";
962 for (param_ord, (max_param, spans)) in &out_of_order {
963 let mut err = handler.struct_span_err(
966 "{} parameters must be declared prior to {} parameters",
967 param_ord, max_param,
972 "reorder the parameters: lifetimes, then consts and types",
973 ordered_params.clone(),
974 Applicability::MachineApplicable,
981 impl<'a> Visitor<'a> for AstValidator<'a> {
982 fn visit_attribute(&mut self, attr: &Attribute) {
983 validate_attr::check_meta(&self.session.parse_sess, attr);
986 fn visit_expr(&mut self, expr: &'a Expr) {
987 self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
988 ExprKind::If(cond, then, opt_else) => {
989 this.visit_block(then);
990 walk_list!(this, visit_expr, opt_else);
991 this.with_let_allowed(true, |this, _| this.visit_expr(cond));
994 ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
995 ExprKind::Match(expr, arms) => {
996 this.visit_expr(expr);
998 this.visit_expr(&arm.body);
999 this.visit_pat(&arm.pat);
1000 walk_list!(this, visit_attribute, &arm.attrs);
1001 if let Some(ref guard) = arm.guard {
1002 if let ExprKind::Let(_, ref expr, _) = guard.kind {
1003 this.with_let_allowed(true, |this, _| this.visit_expr(expr));
1009 ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1010 this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
1013 ExprKind::While(cond, then, opt_label) => {
1014 walk_list!(this, visit_label, opt_label);
1015 this.visit_block(then);
1016 this.with_let_allowed(true, |this, _| this.visit_expr(cond));
1019 _ => visit::walk_expr(this, expr),
1023 fn visit_ty(&mut self, ty: &'a Ty) {
1024 self.visit_ty_common(ty);
1028 fn visit_label(&mut self, label: &'a Label) {
1029 self.check_label(label.ident);
1030 visit::walk_label(self, label);
1033 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
1034 self.check_lifetime(lifetime.ident);
1035 visit::walk_lifetime(self, lifetime);
1038 fn visit_field_def(&mut self, s: &'a FieldDef) {
1039 visit::walk_field_def(self, s)
1042 fn visit_item(&mut self, item: &'a Item) {
1043 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1044 self.has_proc_macro_decls = true;
1047 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1048 self.check_nomangle_item_asciionly(item.ident, item.span);
1052 ItemKind::Impl(box Impl {
1058 of_trait: Some(ref t),
1062 self.with_in_trait_impl(true, Some(constness), |this| {
1063 this.invalid_visibility(&item.vis, None);
1064 if let TyKind::Err = self_ty.kind {
1068 "`impl Trait for .. {}` is an obsolete syntax",
1070 .help("use `auto trait Trait {}` instead")
1073 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1078 "negative impls cannot be unsafe"
1080 .span_label(sp, "negative because of this")
1081 .span_label(span, "unsafe because of this")
1085 this.visit_vis(&item.vis);
1086 this.visit_ident(item.ident);
1087 if let Const::Yes(_) = constness {
1088 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1090 this.visit_generics(generics);
1092 this.visit_trait_ref(t);
1093 this.visit_ty(self_ty);
1095 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1097 return; // Avoid visiting again.
1099 ItemKind::Impl(box Impl {
1109 let error = |annotation_span, annotation| {
1110 let mut err = self.err_handler().struct_span_err(
1112 &format!("inherent impls cannot be {}", annotation),
1114 err.span_label(annotation_span, &format!("{} because of this", annotation));
1115 err.span_label(self_ty.span, "inherent impl for this type");
1119 self.invalid_visibility(
1121 Some("place qualifiers on individual impl items instead"),
1123 if let Unsafe::Yes(span) = unsafety {
1124 error(span, "unsafe").code(error_code!(E0197)).emit();
1126 if let ImplPolarity::Negative(span) = polarity {
1127 error(span, "negative").emit();
1129 if let Defaultness::Default(def_span) = defaultness {
1130 error(def_span, "`default`")
1131 .note("only trait implementations may be annotated with `default`")
1134 if let Const::Yes(span) = constness {
1135 error(span, "`const`")
1136 .note("only trait implementations may be annotated with `const`")
1140 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1141 self.check_defaultness(item.span, defaultness);
1144 let msg = "free function without a body";
1145 self.error_item_without_body(item.span, "function", msg, " { <body> }");
1147 self.visit_vis(&item.vis);
1148 self.visit_ident(item.ident);
1149 if let Const::Yes(_) = sig.header.constness {
1150 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1152 self.visit_generics(generics);
1154 let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
1155 self.visit_fn(kind, item.span, item.id);
1156 walk_list!(self, visit_attribute, &item.attrs);
1157 return; // Avoid visiting again.
1159 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1160 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1161 self.invalid_visibility(
1163 Some("place qualifiers on individual foreign items instead"),
1165 if let Unsafe::Yes(span) = unsafety {
1166 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1169 self.maybe_lint_missing_abi(item.span, item.id);
1171 visit::walk_item(self, item);
1172 self.extern_mod = old_item;
1173 return; // Avoid visiting again.
1175 ItemKind::Enum(ref def, _) => {
1176 for variant in &def.variants {
1177 self.invalid_visibility(&variant.vis, None);
1178 for field in variant.data.fields() {
1179 self.invalid_visibility(&field.vis, None);
1183 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1184 if is_auto == IsAuto::Yes {
1185 // Auto traits cannot have generics, super traits nor contain items.
1186 self.deny_generic_params(generics, item.ident.span);
1187 self.deny_super_traits(bounds, item.ident.span);
1188 self.deny_where_clause(&generics.where_clause, item.ident.span);
1189 self.deny_items(items, item.ident.span);
1191 self.no_questions_in_bounds(bounds, "supertraits", true);
1193 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1194 // context for the supertraits.
1195 self.visit_vis(&item.vis);
1196 self.visit_ident(item.ident);
1197 self.visit_generics(generics);
1198 self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
1199 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1200 walk_list!(self, visit_attribute, &item.attrs);
1203 ItemKind::Mod(unsafety, ref mod_kind) => {
1204 if let Unsafe::Yes(span) = unsafety {
1205 self.err_handler().span_err(span, "module cannot be declared unsafe");
1207 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1208 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1209 && !self.session.contains_name(&item.attrs, sym::path)
1211 self.check_mod_file_item_asciionly(item.ident);
1214 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1215 // Duplicating the `Visitor` logic allows catching all cases
1216 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1218 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1219 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1220 // it uses `visit_ty_common`, which doesn't contain that specific check.
1221 VariantData::Struct(ref fields, ..) => {
1222 self.visit_vis(&item.vis);
1223 self.visit_ident(item.ident);
1224 self.visit_generics(generics);
1225 self.with_banned_assoc_ty_bound(|this| {
1226 walk_list!(this, visit_struct_field_def, fields);
1228 walk_list!(self, visit_attribute, &item.attrs);
1233 ItemKind::Union(ref vdata, ref generics) => {
1234 if vdata.fields().is_empty() {
1235 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1238 VariantData::Struct(ref fields, ..) => {
1239 self.visit_vis(&item.vis);
1240 self.visit_ident(item.ident);
1241 self.visit_generics(generics);
1242 self.with_banned_assoc_ty_bound(|this| {
1243 walk_list!(this, visit_struct_field_def, fields);
1245 walk_list!(self, visit_attribute, &item.attrs);
1251 ItemKind::Const(def, .., None) => {
1252 self.check_defaultness(item.span, def);
1253 let msg = "free constant item without body";
1254 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1256 ItemKind::Static(.., None) => {
1257 let msg = "free static item without body";
1258 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1260 ItemKind::TyAlias(box TyAlias {
1267 self.check_defaultness(item.span, defaultness);
1269 let msg = "free type alias without body";
1270 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1272 self.check_type_no_bounds(bounds, "this context");
1273 if where_clauses.1.0 {
1274 self.err_handler().span_err(
1276 "where clauses are not allowed after the type for type aliases",
1283 visit::walk_item(self, item);
1286 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1288 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1289 self.check_defaultness(fi.span, *defaultness);
1290 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1291 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1292 self.check_foreign_item_ascii_only(fi.ident);
1294 ForeignItemKind::TyAlias(box TyAlias {
1302 self.check_defaultness(fi.span, *defaultness);
1303 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1304 self.check_type_no_bounds(bounds, "`extern` blocks");
1305 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1306 self.check_foreign_item_ascii_only(fi.ident);
1308 ForeignItemKind::Static(_, _, body) => {
1309 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1310 self.check_foreign_item_ascii_only(fi.ident);
1312 ForeignItemKind::MacCall(..) => {}
1315 visit::walk_foreign_item(self, fi)
1318 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1319 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1320 match *generic_args {
1321 GenericArgs::AngleBracketed(ref data) => {
1322 self.check_generic_args_before_constraints(data);
1324 for arg in &data.args {
1326 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1327 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1328 // are allowed to contain nested `impl Trait`.
1329 AngleBracketedArg::Constraint(constraint) => {
1330 self.with_impl_trait(None, |this| {
1331 this.visit_assoc_constraint_from_generic_args(constraint);
1337 GenericArgs::Parenthesized(ref data) => {
1338 walk_list!(self, visit_ty, &data.inputs);
1339 if let FnRetTy::Ty(ty) = &data.output {
1340 // `-> Foo` syntax is essentially an associated type binding,
1341 // so it is also allowed to contain nested `impl Trait`.
1342 self.with_impl_trait(None, |this| this.visit_ty(ty));
1348 fn visit_generics(&mut self, generics: &'a Generics) {
1349 let mut prev_param_default = None;
1350 for param in &generics.params {
1352 GenericParamKind::Lifetime => (),
1353 GenericParamKind::Type { default: Some(_), .. }
1354 | GenericParamKind::Const { default: Some(_), .. } => {
1355 prev_param_default = Some(param.ident.span);
1357 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1358 if let Some(span) = prev_param_default {
1359 let mut err = self.err_handler().struct_span_err(
1361 "generic parameters with a default must be trailing",
1370 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1372 for predicate in &generics.where_clause.predicates {
1373 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1374 deny_equality_constraints(self, predicate, generics);
1377 walk_list!(self, visit_generic_param, &generics.params);
1378 for predicate in &generics.where_clause.predicates {
1380 WherePredicate::BoundPredicate(bound_pred) => {
1381 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1382 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1384 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1385 // binder and thus we only allow a single level of quantification. However,
1386 // the syntax of Rust permits quantification in two places in where clauses,
1387 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1388 // defined, then error.
1389 if !bound_pred.bound_generic_params.is_empty() {
1390 for bound in &bound_pred.bounds {
1392 GenericBound::Trait(t, _) => {
1393 if !t.bound_generic_params.is_empty() {
1398 "nested quantification of lifetimes"
1403 GenericBound::Outlives(_) => {}
1410 self.visit_where_predicate(predicate);
1414 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1415 if let GenericParamKind::Lifetime { .. } = param.kind {
1416 self.check_lifetime(param.ident);
1418 visit::walk_generic_param(self, param);
1421 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1423 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1424 if !self.is_tilde_const_allowed {
1426 .struct_span_err(bound.span(), "`~const` is not allowed here")
1427 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1432 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1434 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1440 visit::walk_param_bound(self, bound)
1443 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1444 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1445 visit::walk_poly_trait_ref(self, t, m);
1448 fn visit_variant_data(&mut self, s: &'a VariantData) {
1449 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1454 enum_definition: &'a EnumDef,
1455 generics: &'a Generics,
1459 self.with_banned_assoc_ty_bound(|this| {
1460 visit::walk_enum_def(this, enum_definition, generics, item_id)
1464 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1465 // Only associated `fn`s can have `self` parameters.
1466 let self_semantic = match fk.ctxt() {
1467 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1468 _ => SelfSemantic::No,
1470 self.check_fn_decl(fk.decl(), self_semantic);
1472 self.check_c_varadic_type(fk);
1474 // Functions cannot both be `const async`
1475 if let Some(FnHeader {
1476 constness: Const::Yes(cspan),
1477 asyncness: Async::Yes { span: aspan, .. },
1483 vec![*cspan, *aspan],
1484 "functions cannot be both `const` and `async`",
1486 .span_label(*cspan, "`const` because of this")
1487 .span_label(*aspan, "`async` because of this")
1488 .span_label(span, "") // Point at the fn header.
1495 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
1500 self.maybe_lint_missing_abi(*sig_span, id);
1503 // Functions without bodies cannot have patterns.
1504 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1505 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1506 let (code, msg, label) = match ctxt {
1507 FnCtxt::Foreign => (
1509 "patterns aren't allowed in foreign function declarations",
1510 "pattern not allowed in foreign function",
1514 "patterns aren't allowed in functions without bodies",
1515 "pattern not allowed in function without body",
1518 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1519 if let Some(ident) = ident {
1520 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1521 self.lint_buffer.buffer_lint_with_diagnostic(
1522 PATTERNS_IN_FNS_WITHOUT_BODY,
1531 .struct_span_err(span, msg)
1532 .span_label(span, label)
1539 visit::walk_fn(self, fk, span);
1542 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1543 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1544 self.check_nomangle_item_asciionly(item.ident, item.span);
1547 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1548 self.check_defaultness(item.span, item.kind.defaultness());
1551 if ctxt == AssocCtxt::Impl {
1553 AssocItemKind::Const(_, _, body) => {
1554 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1556 AssocItemKind::Fn(box Fn { body, .. }) => {
1557 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1559 AssocItemKind::TyAlias(box TyAlias {
1562 where_predicates_split,
1567 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1568 self.check_type_no_bounds(bounds, "`impl`s");
1570 self.check_gat_where(
1571 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1580 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1581 self.invalid_visibility(&item.vis, None);
1582 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1583 self.check_trait_fn_not_const(sig.header.constness);
1584 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1588 if let AssocItemKind::Const(..) = item.kind {
1589 self.check_item_named(item.ident, "const");
1593 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1594 if ctxt == AssocCtxt::Trait =>
1596 self.visit_vis(&item.vis);
1597 self.visit_ident(item.ident);
1598 walk_list!(self, visit_attribute, &item.attrs);
1599 self.with_tilde_const_allowed(|this| {
1600 this.visit_generics(generics);
1601 walk_list!(this, visit_param_bound, bounds);
1603 walk_list!(self, visit_ty, ty);
1605 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1606 if self.in_const_trait_impl
1607 || ctxt == AssocCtxt::Trait
1608 || matches!(sig.header.constness, Const::Yes(_)) =>
1610 self.visit_vis(&item.vis);
1611 self.visit_ident(item.ident);
1612 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1614 FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
1615 self.visit_fn(kind, item.span, item.id);
1618 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1623 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1624 /// like it's setting an associated type, provide an appropriate suggestion.
1625 fn deny_equality_constraints(
1626 this: &mut AstValidator<'_>,
1627 predicate: &WhereEqPredicate,
1628 generics: &Generics,
1630 let mut err = this.err_handler().struct_span_err(
1632 "equality constraints are not yet supported in `where` clauses",
1634 err.span_label(predicate.span, "not supported");
1636 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1637 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1638 if let TyKind::Path(None, path) = &qself.ty.kind {
1639 match &path.segments[..] {
1640 [PathSegment { ident, args: None, .. }] => {
1641 for param in &generics.params {
1642 if param.ident == *ident {
1644 match &full_path.segments[qself.position..] {
1645 [PathSegment { ident, args, .. }] => {
1646 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1647 let mut assoc_path = full_path.clone();
1648 // Remove `Bar` from `Foo::Bar`.
1649 assoc_path.segments.pop();
1650 let len = assoc_path.segments.len() - 1;
1651 let gen_args = args.as_ref().map(|p| (**p).clone());
1652 // Build `<Bar = RhsTy>`.
1653 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1654 id: rustc_ast::node_id::DUMMY_NODE_ID,
1657 kind: AssocConstraintKind::Equality {
1658 term: predicate.rhs_ty.clone().into(),
1662 // Add `<Bar = RhsTy>` to `Foo`.
1663 match &mut assoc_path.segments[len].args {
1664 Some(args) => match args.deref_mut() {
1665 GenericArgs::Parenthesized(_) => continue,
1666 GenericArgs::AngleBracketed(args) => {
1667 args.args.push(arg);
1671 *empty_args = AngleBracketedArgs {
1678 err.span_suggestion_verbose(
1681 "if `{}` is an associated type you're trying to set, \
1682 use the associated type binding syntax",
1688 pprust::path_to_string(&assoc_path)
1690 Applicability::MaybeIncorrect,
1702 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1703 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1704 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1705 for param in &generics.params {
1706 if param.ident == potential_param.ident {
1707 for bound in ¶m.bounds {
1708 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1710 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1711 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1712 potential_assoc.ident,
1714 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1715 let (args, span) = match &trait_segment.args {
1716 Some(args) => match args.deref() {
1717 ast::GenericArgs::AngleBracketed(args) => {
1718 let Some(arg) = args.args.last() else {
1722 format!(", {} = {}", assoc, ty),
1723 arg.span().shrink_to_hi(),
1729 format!("<{} = {}>", assoc, ty),
1730 trait_segment.span().shrink_to_hi(),
1733 err.multipart_suggestion(
1735 "if `{}::{}` is an associated type you're trying to set, \
1736 use the associated type binding syntax",
1737 trait_segment.ident, potential_assoc.ident,
1739 vec![(span, args), (predicate.span, String::new())],
1740 Applicability::MaybeIncorrect,
1750 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1755 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1756 let mut validator = AstValidator {
1759 in_trait_impl: false,
1760 in_const_trait_impl: false,
1761 has_proc_macro_decls: false,
1762 outer_impl_trait: None,
1763 is_tilde_const_allowed: false,
1764 is_impl_trait_banned: false,
1765 is_assoc_ty_bound_banned: false,
1766 is_let_allowed: false,
1769 visit::walk_crate(&mut validator, krate);
1771 validator.has_proc_macro_decls