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 /// See [ForbiddenLetReason]
68 forbidden_let_reason: Option<ForbiddenLetReason>,
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_management(
108 forbidden_let_reason: Option<ForbiddenLetReason>,
109 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
111 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
113 self.forbidden_let_reason = old;
116 /// Emits an error banning the `let` expression provided in the given location.
117 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
118 let sess = &self.session;
119 if sess.opts.unstable_features.is_nightly_build() {
120 let err = "`let` expressions are not supported here";
121 let mut diag = sess.struct_span_err(expr.span, err);
122 diag.note("only supported directly in conditions of `if` and `while` expressions");
123 diag.note("as well as when nested within `&&` and parentheses in those conditions");
124 if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
125 diag.span_note(span, "`||` operators are not allowed in let chain expressions");
129 sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
130 .note("variable declaration using `let` is a statement")
138 before_predicates: &[WherePredicate],
139 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
141 if !before_predicates.is_empty() {
142 let mut state = State::new();
143 if !where_clauses.1.0 {
145 state.word_space("where");
147 state.word_space(",");
149 let mut first = true;
150 for p in before_predicates.iter() {
152 state.word_space(",");
155 state.print_where_predicate(p);
157 let suggestion = state.s.eof();
158 self.lint_buffer.buffer_lint_with_diagnostic(
159 DEPRECATED_WHERE_CLAUSE_LOCATION,
162 "where clause not allowed here",
163 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
164 where_clauses.1.1.shrink_to_hi(),
171 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
172 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
174 self.is_assoc_ty_bound_banned = old;
177 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
178 let old = mem::replace(&mut self.outer_impl_trait, outer);
180 self.with_banned_tilde_const(f);
184 self.outer_impl_trait = old;
187 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
188 match constraint.kind {
189 AssocConstraintKind::Equality { .. } => {}
190 AssocConstraintKind::Bound { .. } => {
191 if self.is_assoc_ty_bound_banned {
192 self.err_handler().span_err(
194 "associated type bounds are not allowed within structs, enums, or unions",
199 self.visit_assoc_constraint(constraint);
202 // Mirrors `visit::walk_ty`, but tracks relevant state.
203 fn walk_ty(&mut self, t: &'a Ty) {
205 TyKind::ImplTrait(..) => {
206 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
208 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
209 TyKind::Path(ref qself, ref path) => {
211 // - `Option<impl Trait>`
212 // - `option::Option<impl Trait>`
213 // - `option::Option<T>::Foo<impl Trait>
216 // - `<impl Trait>::Foo`
217 // - `option::Option<impl Trait>::Foo`.
219 // To implement this, we disallow `impl Trait` from `qself`
220 // (for cases like `<impl Trait>::Foo>`)
221 // but we allow `impl Trait` in `GenericArgs`
222 // iff there are no more PathSegments.
223 if let Some(ref qself) = *qself {
224 // `impl Trait` in `qself` is always illegal
225 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
228 // Note that there should be a call to visit_path here,
229 // so if any logic is added to process `Path`s a call to it should be
230 // added both in visit_path and here. This code mirrors visit::walk_path.
231 for (i, segment) in path.segments.iter().enumerate() {
232 // Allow `impl Trait` iff we're on the final path segment
233 if i == path.segments.len() - 1 {
234 self.visit_path_segment(path.span, segment);
236 self.with_banned_impl_trait(|this| {
237 this.visit_path_segment(path.span, segment)
242 _ => visit::walk_ty(self, t),
246 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
247 if let Some(ident) = field.ident {
248 if ident.name == kw::Underscore {
249 self.visit_vis(&field.vis);
250 self.visit_ident(ident);
251 self.visit_ty_common(&field.ty);
252 self.walk_ty(&field.ty);
253 walk_list!(self, visit_attribute, &field.attrs);
257 self.visit_field_def(field);
260 fn err_handler(&self) -> &rustc_errors::Handler {
261 &self.session.diagnostic()
264 fn check_lifetime(&self, ident: Ident) {
265 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
266 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
267 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
271 fn check_label(&self, ident: Ident) {
272 if ident.without_first_quote().is_reserved() {
274 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
278 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
279 if let VisibilityKind::Inherited = vis.kind {
284 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
285 if vis.kind.is_pub() {
286 err.span_label(vis.span, "`pub` not permitted here because it's implied");
288 if let Some(note) = note {
294 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
295 for Param { pat, .. } in &decl.inputs {
297 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
298 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
299 report_err(pat.span, Some(ident), true)
301 _ => report_err(pat.span, None, false),
306 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
307 if let Async::Yes { span, .. } = asyncness {
312 "functions in traits cannot be declared `async`"
314 .span_label(span, "`async` because of this")
315 .note("`async` trait functions are not currently supported")
316 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
321 fn check_trait_fn_not_const(&self, constness: Const) {
322 if let Const::Yes(span) = constness {
327 "functions in traits cannot be declared const"
329 .span_label(span, "functions in traits cannot be const")
334 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
335 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
336 for bound in bounds {
337 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
338 let mut err = self.err_handler().struct_span_err(
340 &format!("`?Trait` is not permitted in {}", where_),
343 let path_str = pprust::path_to_string(&poly.trait_ref.path);
344 err.note(&format!("traits are `?{}` by default", path_str));
351 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
352 // Check only lifetime parameters are present and that the lifetime
353 // parameters that are present have no bounds.
354 let non_lt_param_spans: Vec<_> = params
356 .filter_map(|param| match param.kind {
357 GenericParamKind::Lifetime { .. } => {
358 if !param.bounds.is_empty() {
359 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
361 .span_err(spans, "lifetime bounds cannot be used in this context");
365 _ => Some(param.ident.span),
368 if !non_lt_param_spans.is_empty() {
369 self.err_handler().span_err(
371 "only lifetime parameters can be used in this context",
376 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
377 self.check_decl_num_args(fn_decl);
378 self.check_decl_cvaradic_pos(fn_decl);
379 self.check_decl_attrs(fn_decl);
380 self.check_decl_self_param(fn_decl, self_semantic);
383 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
384 /// Error is fatal to prevent errors during typechecking
385 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
386 let max_num_args: usize = u16::MAX.into();
387 if fn_decl.inputs.len() > max_num_args {
388 let Param { span, .. } = fn_decl.inputs[0];
389 self.err_handler().span_fatal(
391 &format!("function can not have more than {} arguments", max_num_args),
396 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
397 match &*fn_decl.inputs {
398 [Param { ty, span, .. }] => {
399 if let TyKind::CVarArgs = ty.kind {
400 self.err_handler().span_err(
402 "C-variadic function must be declared with at least one named argument",
407 for Param { ty, span, .. } in ps {
408 if let TyKind::CVarArgs = ty.kind {
409 self.err_handler().span_err(
411 "`...` must be the last argument of a C-variadic function",
420 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
424 .flat_map(|i| i.attrs.as_ref())
426 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
427 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
430 if attr.is_doc_comment() {
434 "documentation comments cannot be applied to function parameters",
436 .span_label(attr.span, "doc comments are not allowed here")
439 self.err_handler().span_err(
441 "allow, cfg, cfg_attr, deny, \
442 forbid, and warn are the only allowed built-in attributes in function parameters",
448 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
449 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
454 "`self` parameter is only allowed in associated functions",
456 .span_label(param.span, "not semantically valid as function parameter")
457 .note("associated functions are those in `impl` or `trait` definitions")
463 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
464 if let Defaultness::Default(def_span) = defaultness {
465 let span = self.session.source_map().guess_head_span(span);
467 .struct_span_err(span, "`default` is only allowed on items in trait impls")
468 .span_label(def_span, "`default` because of this")
473 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
475 .struct_span_err(sp, msg)
477 self.session.source_map().end_point(sp),
478 &format!("provide a definition for the {}", ctx),
480 Applicability::HasPlaceholders,
485 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
487 let msg = format!("associated {} in `impl` without body", ctx);
488 self.error_item_without_body(sp, ctx, &msg, sugg);
492 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
493 let span = match bounds {
496 [b0, .., bl] => b0.span().to(bl.span()),
499 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
503 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
504 let cannot_have = |span, descr, remove_descr| {
508 &format!("`type`s inside `extern` blocks cannot have {}", descr),
512 &format!("remove the {}", remove_descr),
514 Applicability::MaybeIncorrect,
516 .span_label(self.current_extern_span(), "`extern` block begins here")
521 if !generics.params.is_empty() {
522 cannot_have(generics.span, "generic parameters", "generic parameters");
525 if !generics.where_clause.predicates.is_empty() {
526 cannot_have(where_span, "`where` clauses", "`where` clause");
530 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
531 let Some(body) = body else {
535 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
536 .span_label(ident.span, "cannot have a body")
537 .span_label(body, "the invalid body")
539 self.current_extern_span(),
541 "`extern` blocks define existing foreign {0}s and {0}s \
542 inside of them cannot have a body",
550 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
551 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
552 let Some(body) = body else {
556 .struct_span_err(ident.span, "incorrect function inside `extern` block")
557 .span_label(ident.span, "cannot have a body")
560 "remove the invalid body",
562 Applicability::MaybeIncorrect,
565 "you might have meant to write a function accessible through FFI, \
566 which can be done by writing `extern fn` outside of the `extern` block",
569 self.current_extern_span(),
570 "`extern` blocks define existing foreign functions and functions \
571 inside of them cannot have a body",
577 fn current_extern_span(&self) -> Span {
578 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
581 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
582 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
583 if header.has_qualifiers() {
585 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
586 .span_label(self.current_extern_span(), "in this `extern` block")
587 .span_suggestion_verbose(
588 span.until(ident.span.shrink_to_lo()),
589 "remove the qualifiers",
591 Applicability::MaybeIncorrect,
597 /// An item in `extern { ... }` cannot use non-ascii identifier.
598 fn check_foreign_item_ascii_only(&self, ident: Ident) {
599 if !ident.as_str().is_ascii() {
604 "items in `extern` blocks cannot use non-ascii identifiers",
606 .span_label(self.current_extern_span(), "in this `extern` block")
608 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
615 /// Reject C-varadic type unless the function is foreign,
616 /// or free and `unsafe extern "C"` semantically.
617 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
618 match (fk.ctxt(), fk.header()) {
619 (Some(FnCtxt::Foreign), _) => return,
620 (Some(FnCtxt::Free), Some(header)) => match header.ext {
621 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
622 if matches!(header.unsafety, Unsafe::Yes(_)) =>
631 for Param { ty, span, .. } in &fk.decl().inputs {
632 if let TyKind::CVarArgs = ty.kind {
636 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
643 fn check_item_named(&self, ident: Ident, kind: &str) {
644 if ident.name != kw::Underscore {
648 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
649 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
653 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
654 if ident.name.as_str().is_ascii() {
657 let head_span = self.session.source_map().guess_head_span(item_span);
662 "`#[no_mangle]` requires ASCII identifier"
667 fn check_mod_file_item_asciionly(&self, ident: Ident) {
668 if ident.name.as_str().is_ascii() {
675 "trying to load file for module `{}` with non-ascii identifier name",
678 .help("consider using `#[path]` attribute to specify filesystem path")
682 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
683 if !generics.params.is_empty() {
688 "auto traits cannot have generic parameters"
690 .span_label(ident_span, "auto trait cannot have generic parameters")
693 "remove the parameters",
695 Applicability::MachineApplicable,
701 fn emit_e0568(&self, span: Span, ident_span: Span) {
706 "auto traits cannot have super traits or lifetime bounds"
708 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
711 "remove the super traits or lifetime bounds",
713 Applicability::MachineApplicable,
718 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
719 if let [.., last] = &bounds[..] {
720 let span = ident_span.shrink_to_hi().to(last.span());
721 self.emit_e0568(span, ident_span);
725 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
726 if !where_clause.predicates.is_empty() {
727 self.emit_e0568(where_clause.span, ident_span);
731 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
732 if !trait_items.is_empty() {
733 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
734 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
739 "auto traits cannot have associated items"
743 "remove these associated items",
745 Applicability::MachineApplicable,
747 .span_label(ident_span, "auto trait cannot have associated items")
752 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
753 // Lifetimes always come first.
754 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
755 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
756 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
760 let args_sugg = data.args.iter().filter_map(|a| match a {
761 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
764 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
766 // Constraints always come last.
767 let constraint_sugg = data.args.iter().filter_map(|a| match a {
768 AngleBracketedArg::Arg(_) => None,
769 AngleBracketedArg::Constraint(c) => {
770 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
775 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
779 /// Enforce generic args coming before constraints in `<...>` of a path segment.
780 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
781 // Early exit in case it's partitioned as it should be.
782 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
785 // Find all generic argument coming after the first constraint...
786 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
787 data.args.iter().partition_map(|arg| match arg {
788 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
789 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
791 let args_len = arg_spans.len();
792 let constraint_len = constraint_spans.len();
793 // ...and then error:
797 "generic arguments must come before the first constraint",
799 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
801 *arg_spans.iter().last().unwrap(),
802 &format!("generic argument{}", pluralize!(args_len)),
804 .span_labels(constraint_spans, "")
805 .span_labels(arg_spans, "")
806 .span_suggestion_verbose(
809 "move the constraint{} after the generic argument{}",
810 pluralize!(constraint_len),
813 self.correct_generic_order_suggestion(&data),
814 Applicability::MachineApplicable,
819 fn visit_ty_common(&mut self, ty: &'a Ty) {
821 TyKind::BareFn(ref bfty) => {
822 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
823 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
828 "patterns aren't allowed in function pointer types"
832 self.check_late_bound_lifetime_defs(&bfty.generic_params);
833 if let Extern::Implicit = bfty.ext {
834 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
835 self.maybe_lint_missing_abi(sig_span, ty.id);
838 TyKind::TraitObject(ref bounds, ..) => {
839 let mut any_lifetime_bounds = false;
840 for bound in bounds {
841 if let GenericBound::Outlives(ref lifetime) = *bound {
842 if any_lifetime_bounds {
847 "only a single explicit lifetime bound is permitted"
852 any_lifetime_bounds = true;
855 self.no_questions_in_bounds(bounds, "trait object types", false);
857 TyKind::ImplTrait(_, ref bounds) => {
858 if self.is_impl_trait_banned {
863 "`impl Trait` is not allowed in path parameters"
868 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
873 "nested `impl Trait` is not allowed"
875 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
876 .span_label(ty.span, "nested `impl Trait` here")
880 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
881 self.err_handler().span_err(ty.span, "at least one trait must be specified");
888 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
889 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
890 // call site which do not have a macro backtrace. See #61963.
891 let is_macro_callsite = self
894 .span_to_snippet(span)
895 .map(|snippet| snippet.starts_with("#["))
897 if !is_macro_callsite {
898 self.lint_buffer.buffer_lint_with_diagnostic(
902 "extern declarations without an explicit ABI are deprecated",
903 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
909 /// Checks that generic parameters are in the correct order,
910 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
911 fn validate_generic_param_order(
912 handler: &rustc_errors::Handler,
913 generics: &[GenericParam],
916 let mut max_param: Option<ParamKindOrd> = None;
917 let mut out_of_order = FxHashMap::default();
918 let mut param_idents = Vec::with_capacity(generics.len());
920 for (idx, param) in generics.iter().enumerate() {
921 let ident = param.ident;
922 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
923 let (ord_kind, ident) = match ¶m.kind {
924 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
925 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
926 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
927 let ty = pprust::ty_to_string(ty);
928 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
931 param_idents.push((kind, ord_kind, bounds, idx, ident));
933 Some(max_param) if max_param > ord_kind => {
934 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
937 Some(_) | None => max_param = Some(ord_kind),
941 if !out_of_order.is_empty() {
942 let mut ordered_params = "<".to_string();
943 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
944 let mut first = true;
945 for (kind, _, bounds, _, ident) in param_idents {
947 ordered_params += ", ";
949 ordered_params += &ident;
951 if !bounds.is_empty() {
952 ordered_params += ": ";
953 ordered_params += &pprust::bounds_to_string(&bounds);
957 GenericParamKind::Type { default: Some(default) } => {
958 ordered_params += " = ";
959 ordered_params += &pprust::ty_to_string(default);
961 GenericParamKind::Type { default: None } => (),
962 GenericParamKind::Lifetime => (),
963 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
964 ordered_params += " = ";
965 ordered_params += &pprust::expr_to_string(&*default.value);
967 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
972 ordered_params += ">";
974 for (param_ord, (max_param, spans)) in &out_of_order {
975 let mut err = handler.struct_span_err(
978 "{} parameters must be declared prior to {} parameters",
979 param_ord, max_param,
984 "reorder the parameters: lifetimes, then consts and types",
985 ordered_params.clone(),
986 Applicability::MachineApplicable,
993 impl<'a> Visitor<'a> for AstValidator<'a> {
994 fn visit_attribute(&mut self, attr: &Attribute) {
995 validate_attr::check_meta(&self.session.parse_sess, attr);
998 fn visit_expr(&mut self, expr: &'a Expr) {
999 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
1001 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
1002 let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
1003 this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
1004 this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
1006 ExprKind::If(cond, then, opt_else) => {
1007 this.visit_block(then);
1008 walk_list!(this, visit_expr, opt_else);
1009 this.with_let_management(None, |this, _| this.visit_expr(cond));
1012 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
1013 this.ban_let_expr(expr, elem);
1015 ExprKind::Match(scrutinee, arms) => {
1016 this.visit_expr(scrutinee);
1018 this.visit_expr(&arm.body);
1019 this.visit_pat(&arm.pat);
1020 walk_list!(this, visit_attribute, &arm.attrs);
1021 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
1022 this.with_let_management(None, |this, _| {
1023 this.visit_expr(guard_expr)
1029 ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1030 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
1033 ExprKind::While(cond, then, opt_label) => {
1034 walk_list!(this, visit_label, opt_label);
1035 this.visit_block(then);
1036 this.with_let_management(None, |this, _| this.visit_expr(cond));
1039 _ => visit::walk_expr(this, expr),
1044 fn visit_ty(&mut self, ty: &'a Ty) {
1045 self.visit_ty_common(ty);
1049 fn visit_label(&mut self, label: &'a Label) {
1050 self.check_label(label.ident);
1051 visit::walk_label(self, label);
1054 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
1055 self.check_lifetime(lifetime.ident);
1056 visit::walk_lifetime(self, lifetime);
1059 fn visit_field_def(&mut self, s: &'a FieldDef) {
1060 visit::walk_field_def(self, s)
1063 fn visit_item(&mut self, item: &'a Item) {
1064 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1065 self.has_proc_macro_decls = true;
1068 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1069 self.check_nomangle_item_asciionly(item.ident, item.span);
1073 ItemKind::Impl(box Impl {
1079 of_trait: Some(ref t),
1083 self.with_in_trait_impl(true, Some(constness), |this| {
1084 this.invalid_visibility(&item.vis, None);
1085 if let TyKind::Err = self_ty.kind {
1089 "`impl Trait for .. {}` is an obsolete syntax",
1091 .help("use `auto trait Trait {}` instead")
1094 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1099 "negative impls cannot be unsafe"
1101 .span_label(sp, "negative because of this")
1102 .span_label(span, "unsafe because of this")
1106 this.visit_vis(&item.vis);
1107 this.visit_ident(item.ident);
1108 if let Const::Yes(_) = constness {
1109 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1111 this.visit_generics(generics);
1113 this.visit_trait_ref(t);
1114 this.visit_ty(self_ty);
1116 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1118 return; // Avoid visiting again.
1120 ItemKind::Impl(box Impl {
1130 let error = |annotation_span, annotation| {
1131 let mut err = self.err_handler().struct_span_err(
1133 &format!("inherent impls cannot be {}", annotation),
1135 err.span_label(annotation_span, &format!("{} because of this", annotation));
1136 err.span_label(self_ty.span, "inherent impl for this type");
1140 self.invalid_visibility(
1142 Some("place qualifiers on individual impl items instead"),
1144 if let Unsafe::Yes(span) = unsafety {
1145 error(span, "unsafe").code(error_code!(E0197)).emit();
1147 if let ImplPolarity::Negative(span) = polarity {
1148 error(span, "negative").emit();
1150 if let Defaultness::Default(def_span) = defaultness {
1151 error(def_span, "`default`")
1152 .note("only trait implementations may be annotated with `default`")
1155 if let Const::Yes(span) = constness {
1156 error(span, "`const`")
1157 .note("only trait implementations may be annotated with `const`")
1161 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1162 self.check_defaultness(item.span, defaultness);
1165 let msg = "free function without a body";
1166 self.error_item_without_body(item.span, "function", msg, " { <body> }");
1168 self.visit_vis(&item.vis);
1169 self.visit_ident(item.ident);
1170 if let Const::Yes(_) = sig.header.constness {
1171 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1173 self.visit_generics(generics);
1175 let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
1176 self.visit_fn(kind, item.span, item.id);
1177 walk_list!(self, visit_attribute, &item.attrs);
1178 return; // Avoid visiting again.
1180 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1181 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1182 self.invalid_visibility(
1184 Some("place qualifiers on individual foreign items instead"),
1186 if let Unsafe::Yes(span) = unsafety {
1187 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1190 self.maybe_lint_missing_abi(item.span, item.id);
1192 visit::walk_item(self, item);
1193 self.extern_mod = old_item;
1194 return; // Avoid visiting again.
1196 ItemKind::Enum(ref def, _) => {
1197 for variant in &def.variants {
1198 self.invalid_visibility(&variant.vis, None);
1199 for field in variant.data.fields() {
1200 self.invalid_visibility(&field.vis, None);
1204 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1205 if is_auto == IsAuto::Yes {
1206 // Auto traits cannot have generics, super traits nor contain items.
1207 self.deny_generic_params(generics, item.ident.span);
1208 self.deny_super_traits(bounds, item.ident.span);
1209 self.deny_where_clause(&generics.where_clause, item.ident.span);
1210 self.deny_items(items, item.ident.span);
1212 self.no_questions_in_bounds(bounds, "supertraits", true);
1214 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1215 // context for the supertraits.
1216 self.visit_vis(&item.vis);
1217 self.visit_ident(item.ident);
1218 self.visit_generics(generics);
1219 self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
1220 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1221 walk_list!(self, visit_attribute, &item.attrs);
1224 ItemKind::Mod(unsafety, ref mod_kind) => {
1225 if let Unsafe::Yes(span) = unsafety {
1226 self.err_handler().span_err(span, "module cannot be declared unsafe");
1228 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1229 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1230 && !self.session.contains_name(&item.attrs, sym::path)
1232 self.check_mod_file_item_asciionly(item.ident);
1235 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1236 // Duplicating the `Visitor` logic allows catching all cases
1237 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1239 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1240 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1241 // it uses `visit_ty_common`, which doesn't contain that specific check.
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);
1254 ItemKind::Union(ref vdata, ref generics) => {
1255 if vdata.fields().is_empty() {
1256 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1259 VariantData::Struct(ref fields, ..) => {
1260 self.visit_vis(&item.vis);
1261 self.visit_ident(item.ident);
1262 self.visit_generics(generics);
1263 self.with_banned_assoc_ty_bound(|this| {
1264 walk_list!(this, visit_struct_field_def, fields);
1266 walk_list!(self, visit_attribute, &item.attrs);
1272 ItemKind::Const(def, .., None) => {
1273 self.check_defaultness(item.span, def);
1274 let msg = "free constant item without body";
1275 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1277 ItemKind::Static(.., None) => {
1278 let msg = "free static item without body";
1279 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1281 ItemKind::TyAlias(box TyAlias {
1288 self.check_defaultness(item.span, defaultness);
1290 let msg = "free type alias without body";
1291 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1293 self.check_type_no_bounds(bounds, "this context");
1294 if where_clauses.1.0 {
1295 let mut err = self.err_handler().struct_span_err(
1297 "where clauses are not allowed after the type for type aliases",
1300 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1308 visit::walk_item(self, item);
1311 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1313 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1314 self.check_defaultness(fi.span, *defaultness);
1315 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1316 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1317 self.check_foreign_item_ascii_only(fi.ident);
1319 ForeignItemKind::TyAlias(box TyAlias {
1327 self.check_defaultness(fi.span, *defaultness);
1328 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1329 self.check_type_no_bounds(bounds, "`extern` blocks");
1330 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1331 self.check_foreign_item_ascii_only(fi.ident);
1333 ForeignItemKind::Static(_, _, body) => {
1334 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1335 self.check_foreign_item_ascii_only(fi.ident);
1337 ForeignItemKind::MacCall(..) => {}
1340 visit::walk_foreign_item(self, fi)
1343 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1344 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1345 match *generic_args {
1346 GenericArgs::AngleBracketed(ref data) => {
1347 self.check_generic_args_before_constraints(data);
1349 for arg in &data.args {
1351 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1352 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1353 // are allowed to contain nested `impl Trait`.
1354 AngleBracketedArg::Constraint(constraint) => {
1355 self.with_impl_trait(None, |this| {
1356 this.visit_assoc_constraint_from_generic_args(constraint);
1362 GenericArgs::Parenthesized(ref data) => {
1363 walk_list!(self, visit_ty, &data.inputs);
1364 if let FnRetTy::Ty(ty) = &data.output {
1365 // `-> Foo` syntax is essentially an associated type binding,
1366 // so it is also allowed to contain nested `impl Trait`.
1367 self.with_impl_trait(None, |this| this.visit_ty(ty));
1373 fn visit_generics(&mut self, generics: &'a Generics) {
1374 let mut prev_param_default = None;
1375 for param in &generics.params {
1377 GenericParamKind::Lifetime => (),
1378 GenericParamKind::Type { default: Some(_), .. }
1379 | GenericParamKind::Const { default: Some(_), .. } => {
1380 prev_param_default = Some(param.ident.span);
1382 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1383 if let Some(span) = prev_param_default {
1384 let mut err = self.err_handler().struct_span_err(
1386 "generic parameters with a default must be trailing",
1395 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1397 for predicate in &generics.where_clause.predicates {
1398 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1399 deny_equality_constraints(self, predicate, generics);
1402 walk_list!(self, visit_generic_param, &generics.params);
1403 for predicate in &generics.where_clause.predicates {
1405 WherePredicate::BoundPredicate(bound_pred) => {
1406 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1407 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1409 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1410 // binder and thus we only allow a single level of quantification. However,
1411 // the syntax of Rust permits quantification in two places in where clauses,
1412 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1413 // defined, then error.
1414 if !bound_pred.bound_generic_params.is_empty() {
1415 for bound in &bound_pred.bounds {
1417 GenericBound::Trait(t, _) => {
1418 if !t.bound_generic_params.is_empty() {
1423 "nested quantification of lifetimes"
1428 GenericBound::Outlives(_) => {}
1435 self.visit_where_predicate(predicate);
1439 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1440 if let GenericParamKind::Lifetime { .. } = param.kind {
1441 self.check_lifetime(param.ident);
1443 visit::walk_generic_param(self, param);
1446 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1448 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1449 if !self.is_tilde_const_allowed {
1451 .struct_span_err(bound.span(), "`~const` is not allowed here")
1452 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1457 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1459 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1465 visit::walk_param_bound(self, bound)
1468 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1469 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1470 visit::walk_poly_trait_ref(self, t, m);
1473 fn visit_variant_data(&mut self, s: &'a VariantData) {
1474 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1479 enum_definition: &'a EnumDef,
1480 generics: &'a Generics,
1484 self.with_banned_assoc_ty_bound(|this| {
1485 visit::walk_enum_def(this, enum_definition, generics, item_id)
1489 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1490 // Only associated `fn`s can have `self` parameters.
1491 let self_semantic = match fk.ctxt() {
1492 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1493 _ => SelfSemantic::No,
1495 self.check_fn_decl(fk.decl(), self_semantic);
1497 self.check_c_varadic_type(fk);
1499 // Functions cannot both be `const async`
1500 if let Some(FnHeader {
1501 constness: Const::Yes(cspan),
1502 asyncness: Async::Yes { span: aspan, .. },
1508 vec![*cspan, *aspan],
1509 "functions cannot be both `const` and `async`",
1511 .span_label(*cspan, "`const` because of this")
1512 .span_label(*aspan, "`async` because of this")
1513 .span_label(span, "") // Point at the fn header.
1520 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
1525 self.maybe_lint_missing_abi(*sig_span, id);
1528 // Functions without bodies cannot have patterns.
1529 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1530 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1531 let (code, msg, label) = match ctxt {
1532 FnCtxt::Foreign => (
1534 "patterns aren't allowed in foreign function declarations",
1535 "pattern not allowed in foreign function",
1539 "patterns aren't allowed in functions without bodies",
1540 "pattern not allowed in function without body",
1543 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1544 if let Some(ident) = ident {
1545 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1546 self.lint_buffer.buffer_lint_with_diagnostic(
1547 PATTERNS_IN_FNS_WITHOUT_BODY,
1556 .struct_span_err(span, msg)
1557 .span_label(span, label)
1564 visit::walk_fn(self, fk, span);
1567 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1568 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1569 self.check_nomangle_item_asciionly(item.ident, item.span);
1572 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1573 self.check_defaultness(item.span, item.kind.defaultness());
1576 if ctxt == AssocCtxt::Impl {
1578 AssocItemKind::Const(_, _, body) => {
1579 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1581 AssocItemKind::Fn(box Fn { body, .. }) => {
1582 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1584 AssocItemKind::TyAlias(box TyAlias {
1587 where_predicates_split,
1592 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1593 self.check_type_no_bounds(bounds, "`impl`s");
1595 self.check_gat_where(
1597 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1606 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1607 self.invalid_visibility(&item.vis, None);
1608 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1609 self.check_trait_fn_not_const(sig.header.constness);
1610 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1614 if let AssocItemKind::Const(..) = item.kind {
1615 self.check_item_named(item.ident, "const");
1619 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1620 if ctxt == AssocCtxt::Trait =>
1622 self.visit_vis(&item.vis);
1623 self.visit_ident(item.ident);
1624 walk_list!(self, visit_attribute, &item.attrs);
1625 self.with_tilde_const_allowed(|this| {
1626 this.visit_generics(generics);
1627 walk_list!(this, visit_param_bound, bounds);
1629 walk_list!(self, visit_ty, ty);
1631 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1632 if self.in_const_trait_impl
1633 || ctxt == AssocCtxt::Trait
1634 || matches!(sig.header.constness, Const::Yes(_)) =>
1636 self.visit_vis(&item.vis);
1637 self.visit_ident(item.ident);
1638 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1640 FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
1641 self.visit_fn(kind, item.span, item.id);
1644 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1649 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1650 /// like it's setting an associated type, provide an appropriate suggestion.
1651 fn deny_equality_constraints(
1652 this: &mut AstValidator<'_>,
1653 predicate: &WhereEqPredicate,
1654 generics: &Generics,
1656 let mut err = this.err_handler().struct_span_err(
1658 "equality constraints are not yet supported in `where` clauses",
1660 err.span_label(predicate.span, "not supported");
1662 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1663 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1664 if let TyKind::Path(None, path) = &qself.ty.kind {
1665 match &path.segments[..] {
1666 [PathSegment { ident, args: None, .. }] => {
1667 for param in &generics.params {
1668 if param.ident == *ident {
1670 match &full_path.segments[qself.position..] {
1671 [PathSegment { ident, args, .. }] => {
1672 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1673 let mut assoc_path = full_path.clone();
1674 // Remove `Bar` from `Foo::Bar`.
1675 assoc_path.segments.pop();
1676 let len = assoc_path.segments.len() - 1;
1677 let gen_args = args.as_ref().map(|p| (**p).clone());
1678 // Build `<Bar = RhsTy>`.
1679 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1680 id: rustc_ast::node_id::DUMMY_NODE_ID,
1683 kind: AssocConstraintKind::Equality {
1684 term: predicate.rhs_ty.clone().into(),
1688 // Add `<Bar = RhsTy>` to `Foo`.
1689 match &mut assoc_path.segments[len].args {
1690 Some(args) => match args.deref_mut() {
1691 GenericArgs::Parenthesized(_) => continue,
1692 GenericArgs::AngleBracketed(args) => {
1693 args.args.push(arg);
1697 *empty_args = AngleBracketedArgs {
1704 err.span_suggestion_verbose(
1707 "if `{}` is an associated type you're trying to set, \
1708 use the associated type binding syntax",
1714 pprust::path_to_string(&assoc_path)
1716 Applicability::MaybeIncorrect,
1728 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1729 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1730 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1731 for param in &generics.params {
1732 if param.ident == potential_param.ident {
1733 for bound in ¶m.bounds {
1734 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1736 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1737 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1738 potential_assoc.ident,
1740 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1741 let (args, span) = match &trait_segment.args {
1742 Some(args) => match args.deref() {
1743 ast::GenericArgs::AngleBracketed(args) => {
1744 let Some(arg) = args.args.last() else {
1748 format!(", {} = {}", assoc, ty),
1749 arg.span().shrink_to_hi(),
1755 format!("<{} = {}>", assoc, ty),
1756 trait_segment.span().shrink_to_hi(),
1759 err.multipart_suggestion(
1761 "if `{}::{}` is an associated type you're trying to set, \
1762 use the associated type binding syntax",
1763 trait_segment.ident, potential_assoc.ident,
1765 vec![(span, args), (predicate.span, String::new())],
1766 Applicability::MaybeIncorrect,
1776 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1781 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1782 let mut validator = AstValidator {
1785 in_trait_impl: false,
1786 in_const_trait_impl: false,
1787 has_proc_macro_decls: false,
1788 outer_impl_trait: None,
1789 is_tilde_const_allowed: false,
1790 is_impl_trait_banned: false,
1791 is_assoc_ty_bound_banned: false,
1792 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1795 visit::walk_crate(&mut validator, krate);
1797 validator.has_proc_macro_decls
1800 /// Used to forbid `let` expressions in certain syntactic locations.
1801 #[derive(Clone, Copy)]
1802 enum ForbiddenLetReason {
1803 /// A let chain with the `||` operator
1804 ForbiddenWithOr(Span),
1805 /// `let` is not valid and the source environment is not important