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, BoundKind, 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, fluent, 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};
32 const MORE_EXTERN: &str =
33 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
35 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
41 struct AstValidator<'a> {
44 /// The span of the `extern` in an `extern { ... }` block, if any.
45 extern_mod: Option<&'a Item>,
47 /// Are we inside a trait impl?
50 in_const_trait_impl: bool,
52 has_proc_macro_decls: bool,
54 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
55 /// Nested `impl Trait` _is_ allowed in associated type position,
56 /// e.g., `impl Iterator<Item = impl Debug>`.
57 outer_impl_trait: Option<Span>,
59 is_tilde_const_allowed: bool,
61 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
62 /// or `Foo::Bar<impl Trait>`
63 is_impl_trait_banned: bool,
65 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
66 /// certain positions.
67 is_assoc_ty_bound_banned: bool,
69 /// See [ForbiddenLetReason]
70 forbidden_let_reason: Option<ForbiddenLetReason>,
72 lint_buffer: &'a mut LintBuffer,
75 impl<'a> AstValidator<'a> {
76 fn with_in_trait_impl(
79 constness: Option<Const>,
80 f: impl FnOnce(&mut Self),
82 let old = mem::replace(&mut self.in_trait_impl, is_in);
84 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
86 self.in_trait_impl = old;
87 self.in_const_trait_impl = old_const;
90 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
91 let old = mem::replace(&mut self.is_impl_trait_banned, true);
93 self.is_impl_trait_banned = old;
96 fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
97 let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
99 self.is_tilde_const_allowed = old;
102 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
103 self.with_tilde_const(true, f)
106 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
107 self.with_tilde_const(false, f)
110 fn with_let_management(
112 forbidden_let_reason: Option<ForbiddenLetReason>,
113 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
115 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
117 self.forbidden_let_reason = old;
120 /// Emits an error banning the `let` expression provided in the given location.
121 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
122 let sess = &self.session;
123 if sess.opts.unstable_features.is_nightly_build() {
124 sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
126 sess.emit_err(ForbiddenLetStable { span: expr.span });
133 before_predicates: &[WherePredicate],
134 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
136 if !before_predicates.is_empty() {
137 let mut state = State::new();
138 if !where_clauses.1.0 {
140 state.word_space("where");
142 state.word_space(",");
144 let mut first = true;
145 for p in before_predicates.iter() {
147 state.word_space(",");
150 state.print_where_predicate(p);
152 let suggestion = state.s.eof();
153 self.lint_buffer.buffer_lint_with_diagnostic(
154 DEPRECATED_WHERE_CLAUSE_LOCATION,
157 fluent::ast_passes::deprecated_where_clause_location,
158 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
159 where_clauses.1.1.shrink_to_hi(),
166 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
167 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
169 self.is_assoc_ty_bound_banned = old;
172 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
173 let old = mem::replace(&mut self.outer_impl_trait, outer);
175 self.with_banned_tilde_const(f);
179 self.outer_impl_trait = old;
182 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
183 match constraint.kind {
184 AssocConstraintKind::Equality { .. } => {}
185 AssocConstraintKind::Bound { .. } => {
186 if self.is_assoc_ty_bound_banned {
187 self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
191 self.visit_assoc_constraint(constraint);
194 // Mirrors `visit::walk_ty`, but tracks relevant state.
195 fn walk_ty(&mut self, t: &'a Ty) {
197 TyKind::ImplTrait(..) => {
198 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
200 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
201 TyKind::Path(ref qself, ref path) => {
203 // - `Option<impl Trait>`
204 // - `option::Option<impl Trait>`
205 // - `option::Option<T>::Foo<impl Trait>
208 // - `<impl Trait>::Foo`
209 // - `option::Option<impl Trait>::Foo`.
211 // To implement this, we disallow `impl Trait` from `qself`
212 // (for cases like `<impl Trait>::Foo>`)
213 // but we allow `impl Trait` in `GenericArgs`
214 // iff there are no more PathSegments.
215 if let Some(ref qself) = *qself {
216 // `impl Trait` in `qself` is always illegal
217 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
220 // Note that there should be a call to visit_path here,
221 // so if any logic is added to process `Path`s a call to it should be
222 // added both in visit_path and here. This code mirrors visit::walk_path.
223 for (i, segment) in path.segments.iter().enumerate() {
224 // Allow `impl Trait` iff we're on the final path segment
225 if i == path.segments.len() - 1 {
226 self.visit_path_segment(segment);
228 self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
232 _ => visit::walk_ty(self, t),
236 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
237 if let Some(ident) = field.ident {
238 if ident.name == kw::Underscore {
239 self.visit_vis(&field.vis);
240 self.visit_ident(ident);
241 self.visit_ty_common(&field.ty);
242 self.walk_ty(&field.ty);
243 walk_list!(self, visit_attribute, &field.attrs);
247 self.visit_field_def(field);
250 fn err_handler(&self) -> &rustc_errors::Handler {
251 &self.session.diagnostic()
254 fn check_lifetime(&self, ident: Ident) {
255 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
256 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
257 self.session.emit_err(KeywordLifetime { span: ident.span });
261 fn check_label(&self, ident: Ident) {
262 if ident.without_first_quote().is_reserved() {
263 self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
267 fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
268 if let VisibilityKind::Inherited = vis.kind {
272 self.session.emit_err(InvalidVisibility {
274 implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
279 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
280 for Param { pat, .. } in &decl.inputs {
282 PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {}
283 PatKind::Ident(BindingAnnotation::MUT, ident, None) => {
284 report_err(pat.span, Some(ident), true)
286 _ => report_err(pat.span, None, false),
291 fn check_trait_fn_not_const(&self, constness: Const) {
292 if let Const::Yes(span) = constness {
293 self.session.emit_err(TraitFnConst { span });
297 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
298 // Check only lifetime parameters are present and that the lifetime
299 // parameters that are present have no bounds.
300 let non_lt_param_spans: Vec<_> = params
302 .filter_map(|param| match param.kind {
303 GenericParamKind::Lifetime { .. } => {
304 if !param.bounds.is_empty() {
305 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
306 self.session.emit_err(ForbiddenLifetimeBound { spans });
310 _ => Some(param.ident.span),
313 if !non_lt_param_spans.is_empty() {
314 self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
318 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
319 self.check_decl_num_args(fn_decl);
320 self.check_decl_cvaradic_pos(fn_decl);
321 self.check_decl_attrs(fn_decl);
322 self.check_decl_self_param(fn_decl, self_semantic);
325 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
326 /// Error is fatal to prevent errors during typechecking
327 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
328 let max_num_args: usize = u16::MAX.into();
329 if fn_decl.inputs.len() > max_num_args {
330 let Param { span, .. } = fn_decl.inputs[0];
331 self.session.emit_fatal(FnParamTooMany { span, max_num_args });
335 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
336 match &*fn_decl.inputs {
337 [Param { ty, span, .. }] => {
338 if let TyKind::CVarArgs = ty.kind {
339 self.session.emit_err(FnParamCVarArgsOnly { span: *span });
343 for Param { ty, span, .. } in ps {
344 if let TyKind::CVarArgs = ty.kind {
345 self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
353 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
357 .flat_map(|i| i.attrs.as_ref())
368 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
371 if attr.is_doc_comment() {
372 self.session.emit_err(FnParamDocComment { span: attr.span });
374 self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
379 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
380 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
382 self.session.emit_err(FnParamForbiddenSelf { span: param.span });
387 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
388 if let Defaultness::Default(def_span) = defaultness {
389 let span = self.session.source_map().guess_head_span(span);
390 self.session.emit_err(ForbiddenDefault { span, def_span });
394 /// If `sp` ends with a semicolon, returns it as a `Span`
395 /// Otherwise, returns `sp.shrink_to_hi()`
396 fn ending_semi_or_hi(&self, sp: Span) -> Span {
397 let source_map = self.session.source_map();
398 let end = source_map.end_point(sp);
400 if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
407 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
408 let span = match bounds {
411 [b0, .., bl] => b0.span().to(bl.span()),
414 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
418 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
419 let cannot_have = |span, descr, remove_descr| {
423 &format!("`type`s inside `extern` blocks cannot have {}", descr),
427 &format!("remove the {}", remove_descr),
429 Applicability::MaybeIncorrect,
431 .span_label(self.current_extern_span(), "`extern` block begins here")
436 if !generics.params.is_empty() {
437 cannot_have(generics.span, "generic parameters", "generic parameters");
440 if !generics.where_clause.predicates.is_empty() {
441 cannot_have(where_span, "`where` clauses", "`where` clause");
445 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
446 let Some(body) = body else {
450 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
451 .span_label(ident.span, "cannot have a body")
452 .span_label(body, "the invalid body")
454 self.current_extern_span(),
456 "`extern` blocks define existing foreign {0}s and {0}s \
457 inside of them cannot have a body",
465 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
466 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
467 let Some(body) = body else {
471 .struct_span_err(ident.span, "incorrect function inside `extern` block")
472 .span_label(ident.span, "cannot have a body")
475 "remove the invalid body",
477 Applicability::MaybeIncorrect,
480 "you might have meant to write a function accessible through FFI, \
481 which can be done by writing `extern fn` outside of the `extern` block",
484 self.current_extern_span(),
485 "`extern` blocks define existing foreign functions and functions \
486 inside of them cannot have a body",
492 fn current_extern_span(&self) -> Span {
493 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
496 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
497 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
498 if header.has_qualifiers() {
500 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
501 .span_label(self.current_extern_span(), "in this `extern` block")
502 .span_suggestion_verbose(
503 span.until(ident.span.shrink_to_lo()),
504 "remove the qualifiers",
506 Applicability::MaybeIncorrect,
512 /// An item in `extern { ... }` cannot use non-ascii identifier.
513 fn check_foreign_item_ascii_only(&self, ident: Ident) {
514 if !ident.as_str().is_ascii() {
519 "items in `extern` blocks cannot use non-ascii identifiers",
521 .span_label(self.current_extern_span(), "in this `extern` block")
523 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
530 /// Reject C-variadic type unless the function is foreign,
531 /// or free and `unsafe extern "C"` semantically.
532 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
533 match (fk.ctxt(), fk.header()) {
534 (Some(FnCtxt::Foreign), _) => return,
535 (Some(FnCtxt::Free), Some(header)) => match header.ext {
536 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
537 | Extern::Implicit(_)
538 if matches!(header.unsafety, Unsafe::Yes(_)) =>
547 for Param { ty, span, .. } in &fk.decl().inputs {
548 if let TyKind::CVarArgs = ty.kind {
552 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
559 fn check_item_named(&self, ident: Ident, kind: &str) {
560 if ident.name != kw::Underscore {
564 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
565 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
569 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
570 if ident.name.as_str().is_ascii() {
573 let head_span = self.session.source_map().guess_head_span(item_span);
578 "`#[no_mangle]` requires ASCII identifier"
583 fn check_mod_file_item_asciionly(&self, ident: Ident) {
584 if ident.name.as_str().is_ascii() {
591 "trying to load file for module `{}` with non-ascii identifier name",
594 .help("consider using `#[path]` attribute to specify filesystem path")
598 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
599 if !generics.params.is_empty() {
604 "auto traits cannot have generic parameters"
606 .span_label(ident_span, "auto trait cannot have generic parameters")
609 "remove the parameters",
611 Applicability::MachineApplicable,
617 fn emit_e0568(&self, span: Span, ident_span: Span) {
622 "auto traits cannot have super traits or lifetime bounds"
624 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
627 "remove the super traits or lifetime bounds",
629 Applicability::MachineApplicable,
634 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
635 if let [.., last] = &bounds[..] {
636 let span = ident_span.shrink_to_hi().to(last.span());
637 self.emit_e0568(span, ident_span);
641 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
642 if !where_clause.predicates.is_empty() {
643 self.emit_e0568(where_clause.span, ident_span);
647 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
648 if !trait_items.is_empty() {
649 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
650 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
655 "auto traits cannot have associated items"
659 "remove these associated items",
661 Applicability::MachineApplicable,
663 .span_label(ident_span, "auto trait cannot have associated items")
668 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
669 // Lifetimes always come first.
670 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
671 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
672 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
676 let args_sugg = data.args.iter().filter_map(|a| match a {
677 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
680 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
682 // Constraints always come last.
683 let constraint_sugg = data.args.iter().filter_map(|a| match a {
684 AngleBracketedArg::Arg(_) => None,
685 AngleBracketedArg::Constraint(c) => {
686 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
691 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
695 /// Enforce generic args coming before constraints in `<...>` of a path segment.
696 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
697 // Early exit in case it's partitioned as it should be.
698 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
701 // Find all generic argument coming after the first constraint...
702 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
703 data.args.iter().partition_map(|arg| match arg {
704 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
705 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
707 let args_len = arg_spans.len();
708 let constraint_len = constraint_spans.len();
709 // ...and then error:
713 "generic arguments must come before the first constraint",
715 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
717 *arg_spans.iter().last().unwrap(),
718 &format!("generic argument{}", pluralize!(args_len)),
720 .span_labels(constraint_spans, "")
721 .span_labels(arg_spans, "")
722 .span_suggestion_verbose(
725 "move the constraint{} after the generic argument{}",
726 pluralize!(constraint_len),
729 self.correct_generic_order_suggestion(&data),
730 Applicability::MachineApplicable,
735 fn visit_ty_common(&mut self, ty: &'a Ty) {
737 TyKind::BareFn(ref bfty) => {
738 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
739 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
744 "patterns aren't allowed in function pointer types"
748 self.check_late_bound_lifetime_defs(&bfty.generic_params);
749 if let Extern::Implicit(_) = bfty.ext {
750 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
751 self.maybe_lint_missing_abi(sig_span, ty.id);
754 TyKind::TraitObject(ref bounds, ..) => {
755 let mut any_lifetime_bounds = false;
756 for bound in bounds {
757 if let GenericBound::Outlives(ref lifetime) = *bound {
758 if any_lifetime_bounds {
763 "only a single explicit lifetime bound is permitted"
768 any_lifetime_bounds = true;
772 TyKind::ImplTrait(_, ref bounds) => {
773 if self.is_impl_trait_banned {
778 "`impl Trait` is not allowed in path parameters"
783 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
788 "nested `impl Trait` is not allowed"
790 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
791 .span_label(ty.span, "nested `impl Trait` here")
795 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
796 self.err_handler().span_err(ty.span, "at least one trait must be specified");
803 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
804 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
805 // call site which do not have a macro backtrace. See #61963.
806 let is_macro_callsite = self
809 .span_to_snippet(span)
810 .map(|snippet| snippet.starts_with("#["))
812 if !is_macro_callsite {
813 self.lint_buffer.buffer_lint_with_diagnostic(
817 "extern declarations without an explicit ABI are deprecated",
818 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
824 /// Checks that generic parameters are in the correct order,
825 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
826 fn validate_generic_param_order(
827 handler: &rustc_errors::Handler,
828 generics: &[GenericParam],
831 let mut max_param: Option<ParamKindOrd> = None;
832 let mut out_of_order = FxHashMap::default();
833 let mut param_idents = Vec::with_capacity(generics.len());
835 for (idx, param) in generics.iter().enumerate() {
836 let ident = param.ident;
837 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
838 let (ord_kind, ident) = match ¶m.kind {
839 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
840 GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()),
841 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
842 let ty = pprust::ty_to_string(ty);
843 (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
846 param_idents.push((kind, ord_kind, bounds, idx, ident));
848 Some(max_param) if max_param > ord_kind => {
849 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
852 Some(_) | None => max_param = Some(ord_kind),
856 if !out_of_order.is_empty() {
857 let mut ordered_params = "<".to_string();
858 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
859 let mut first = true;
860 for (kind, _, bounds, _, ident) in param_idents {
862 ordered_params += ", ";
864 ordered_params += &ident;
866 if !bounds.is_empty() {
867 ordered_params += ": ";
868 ordered_params += &pprust::bounds_to_string(&bounds);
872 GenericParamKind::Type { default: Some(default) } => {
873 ordered_params += " = ";
874 ordered_params += &pprust::ty_to_string(default);
876 GenericParamKind::Type { default: None } => (),
877 GenericParamKind::Lifetime => (),
878 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
879 ordered_params += " = ";
880 ordered_params += &pprust::expr_to_string(&*default.value);
882 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
887 ordered_params += ">";
889 for (param_ord, (max_param, spans)) in &out_of_order {
890 let mut err = handler.struct_span_err(
893 "{} parameters must be declared prior to {} parameters",
894 param_ord, max_param,
899 "reorder the parameters: lifetimes, then consts and types",
901 Applicability::MachineApplicable,
908 impl<'a> Visitor<'a> for AstValidator<'a> {
909 fn visit_attribute(&mut self, attr: &Attribute) {
910 validate_attr::check_meta(&self.session.parse_sess, attr);
913 fn visit_expr(&mut self, expr: &'a Expr) {
914 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
916 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
917 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
918 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
919 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
921 ExprKind::If(cond, then, opt_else) => {
922 this.visit_block(then);
923 walk_list!(this, visit_expr, opt_else);
924 this.with_let_management(None, |this, _| this.visit_expr(cond));
927 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
928 this.ban_let_expr(expr, elem);
930 ExprKind::Match(scrutinee, arms) => {
931 this.visit_expr(scrutinee);
933 this.visit_expr(&arm.body);
934 this.visit_pat(&arm.pat);
935 walk_list!(this, visit_attribute, &arm.attrs);
936 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
937 this.with_let_management(None, |this, _| {
938 this.visit_expr(guard_expr)
944 ExprKind::Paren(local_expr) => {
945 fn has_let_expr(expr: &Expr) -> bool {
947 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
948 ExprKind::Let(..) => true,
952 let local_reason = if has_let_expr(local_expr) {
953 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
958 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
960 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
961 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
964 ExprKind::While(cond, then, opt_label) => {
965 walk_list!(this, visit_label, opt_label);
966 this.visit_block(then);
967 this.with_let_management(None, |this, _| this.visit_expr(cond));
970 _ => visit::walk_expr(this, expr),
975 fn visit_ty(&mut self, ty: &'a Ty) {
976 self.visit_ty_common(ty);
980 fn visit_label(&mut self, label: &'a Label) {
981 self.check_label(label.ident);
982 visit::walk_label(self, label);
985 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
986 self.check_lifetime(lifetime.ident);
987 visit::walk_lifetime(self, lifetime);
990 fn visit_field_def(&mut self, s: &'a FieldDef) {
991 visit::walk_field_def(self, s)
994 fn visit_item(&mut self, item: &'a Item) {
995 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
996 self.has_proc_macro_decls = true;
999 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1000 self.check_nomangle_item_asciionly(item.ident, item.span);
1004 ItemKind::Impl(box Impl {
1010 of_trait: Some(ref t),
1014 self.with_in_trait_impl(true, Some(constness), |this| {
1015 this.invalid_visibility(&item.vis, None);
1016 if let TyKind::Err = self_ty.kind {
1020 "`impl Trait for .. {}` is an obsolete syntax",
1022 .help("use `auto trait Trait {}` instead")
1025 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1030 "negative impls cannot be unsafe"
1032 .span_label(sp, "negative because of this")
1033 .span_label(span, "unsafe because of this")
1037 this.visit_vis(&item.vis);
1038 this.visit_ident(item.ident);
1039 if let Const::Yes(_) = constness {
1040 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1042 this.visit_generics(generics);
1044 this.visit_trait_ref(t);
1045 this.visit_ty(self_ty);
1047 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1049 return; // Avoid visiting again.
1051 ItemKind::Impl(box Impl {
1061 let error = |annotation_span, annotation| {
1062 let mut err = self.err_handler().struct_span_err(
1064 &format!("inherent impls cannot be {}", annotation),
1066 err.span_label(annotation_span, &format!("{} because of this", annotation));
1067 err.span_label(self_ty.span, "inherent impl for this type");
1071 self.invalid_visibility(
1073 Some(InvalidVisibilityNote::IndividualImplItems),
1075 if let Unsafe::Yes(span) = unsafety {
1076 error(span, "unsafe").code(error_code!(E0197)).emit();
1078 if let ImplPolarity::Negative(span) = polarity {
1079 error(span, "negative").emit();
1081 if let Defaultness::Default(def_span) = defaultness {
1082 error(def_span, "`default`")
1083 .note("only trait implementations may be annotated with `default`")
1086 if let Const::Yes(span) = constness {
1087 error(span, "`const`")
1088 .note("only trait implementations may be annotated with `const`")
1092 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1093 self.check_defaultness(item.span, defaultness);
1096 self.session.emit_err(FnWithoutBody {
1098 replace_span: self.ending_semi_or_hi(item.span),
1099 extern_block_suggestion: match sig.header.ext {
1100 Extern::None => None,
1101 Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1103 end_span: item.span.shrink_to_hi(),
1106 Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1108 end_span: item.span.shrink_to_hi(),
1109 abi: Some(abi.symbol_unescaped),
1115 self.visit_vis(&item.vis);
1116 self.visit_ident(item.ident);
1118 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1119 self.visit_fn(kind, item.span, item.id);
1120 walk_list!(self, visit_attribute, &item.attrs);
1121 return; // Avoid visiting again.
1123 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1124 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1125 self.invalid_visibility(
1127 Some(InvalidVisibilityNote::IndividualForeignItems),
1129 if let Unsafe::Yes(span) = unsafety {
1130 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1133 self.maybe_lint_missing_abi(item.span, item.id);
1135 visit::walk_item(self, item);
1136 self.extern_mod = old_item;
1137 return; // Avoid visiting again.
1139 ItemKind::Enum(ref def, _) => {
1140 for variant in &def.variants {
1141 self.invalid_visibility(&variant.vis, None);
1142 for field in variant.data.fields() {
1143 self.invalid_visibility(&field.vis, None);
1147 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1148 if is_auto == IsAuto::Yes {
1149 // Auto traits cannot have generics, super traits nor contain items.
1150 self.deny_generic_params(generics, item.ident.span);
1151 self.deny_super_traits(bounds, item.ident.span);
1152 self.deny_where_clause(&generics.where_clause, item.ident.span);
1153 self.deny_items(items, item.ident.span);
1156 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1157 // context for the supertraits.
1158 self.visit_vis(&item.vis);
1159 self.visit_ident(item.ident);
1160 self.visit_generics(generics);
1161 self.with_tilde_const_allowed(|this| {
1162 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1164 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1165 walk_list!(self, visit_attribute, &item.attrs);
1168 ItemKind::Mod(unsafety, ref mod_kind) => {
1169 if let Unsafe::Yes(span) = unsafety {
1170 self.err_handler().span_err(span, "module cannot be declared unsafe");
1172 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1173 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1174 && !self.session.contains_name(&item.attrs, sym::path)
1176 self.check_mod_file_item_asciionly(item.ident);
1179 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1180 // Duplicating the `Visitor` logic allows catching all cases
1181 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1183 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1184 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1185 // it uses `visit_ty_common`, which doesn't contain that specific check.
1186 VariantData::Struct(ref fields, ..) => {
1187 self.visit_vis(&item.vis);
1188 self.visit_ident(item.ident);
1189 self.visit_generics(generics);
1190 self.with_banned_assoc_ty_bound(|this| {
1191 walk_list!(this, visit_struct_field_def, fields);
1193 walk_list!(self, visit_attribute, &item.attrs);
1198 ItemKind::Union(ref vdata, ref generics) => {
1199 if vdata.fields().is_empty() {
1200 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1203 VariantData::Struct(ref fields, ..) => {
1204 self.visit_vis(&item.vis);
1205 self.visit_ident(item.ident);
1206 self.visit_generics(generics);
1207 self.with_banned_assoc_ty_bound(|this| {
1208 walk_list!(this, visit_struct_field_def, fields);
1210 walk_list!(self, visit_attribute, &item.attrs);
1216 ItemKind::Const(def, .., None) => {
1217 self.check_defaultness(item.span, def);
1218 self.session.emit_err(ConstWithoutBody {
1220 replace_span: self.ending_semi_or_hi(item.span),
1223 ItemKind::Static(.., None) => {
1224 self.session.emit_err(StaticWithoutBody {
1226 replace_span: self.ending_semi_or_hi(item.span),
1229 ItemKind::TyAlias(box TyAlias {
1236 self.check_defaultness(item.span, defaultness);
1238 self.session.emit_err(TyAliasWithoutBody {
1240 replace_span: self.ending_semi_or_hi(item.span),
1243 self.check_type_no_bounds(bounds, "this context");
1244 if where_clauses.1.0 {
1245 let mut err = self.err_handler().struct_span_err(
1247 "where clauses are not allowed after the type for type aliases",
1250 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1258 visit::walk_item(self, item);
1261 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1263 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1264 self.check_defaultness(fi.span, *defaultness);
1265 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1266 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1267 self.check_foreign_item_ascii_only(fi.ident);
1269 ForeignItemKind::TyAlias(box TyAlias {
1277 self.check_defaultness(fi.span, *defaultness);
1278 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1279 self.check_type_no_bounds(bounds, "`extern` blocks");
1280 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1281 self.check_foreign_item_ascii_only(fi.ident);
1283 ForeignItemKind::Static(_, _, body) => {
1284 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1285 self.check_foreign_item_ascii_only(fi.ident);
1287 ForeignItemKind::MacCall(..) => {}
1290 visit::walk_foreign_item(self, fi)
1293 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1294 fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
1295 match *generic_args {
1296 GenericArgs::AngleBracketed(ref data) => {
1297 self.check_generic_args_before_constraints(data);
1299 for arg in &data.args {
1301 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1302 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1303 // are allowed to contain nested `impl Trait`.
1304 AngleBracketedArg::Constraint(constraint) => {
1305 self.with_impl_trait(None, |this| {
1306 this.visit_assoc_constraint_from_generic_args(constraint);
1312 GenericArgs::Parenthesized(ref data) => {
1313 walk_list!(self, visit_ty, &data.inputs);
1314 if let FnRetTy::Ty(ty) = &data.output {
1315 // `-> Foo` syntax is essentially an associated type binding,
1316 // so it is also allowed to contain nested `impl Trait`.
1317 self.with_impl_trait(None, |this| this.visit_ty(ty));
1323 fn visit_generics(&mut self, generics: &'a Generics) {
1324 let mut prev_param_default = None;
1325 for param in &generics.params {
1327 GenericParamKind::Lifetime => (),
1328 GenericParamKind::Type { default: Some(_), .. }
1329 | GenericParamKind::Const { default: Some(_), .. } => {
1330 prev_param_default = Some(param.ident.span);
1332 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1333 if let Some(span) = prev_param_default {
1334 let mut err = self.err_handler().struct_span_err(
1336 "generic parameters with a default must be trailing",
1345 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1347 for predicate in &generics.where_clause.predicates {
1348 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1349 deny_equality_constraints(self, predicate, generics);
1352 walk_list!(self, visit_generic_param, &generics.params);
1353 for predicate in &generics.where_clause.predicates {
1355 WherePredicate::BoundPredicate(bound_pred) => {
1356 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1357 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1359 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1360 // binder and thus we only allow a single level of quantification. However,
1361 // the syntax of Rust permits quantification in two places in where clauses,
1362 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1363 // defined, then error.
1364 if !bound_pred.bound_generic_params.is_empty() {
1365 for bound in &bound_pred.bounds {
1367 GenericBound::Trait(t, _) => {
1368 if !t.bound_generic_params.is_empty() {
1373 "nested quantification of lifetimes"
1378 GenericBound::Outlives(_) => {}
1385 self.visit_where_predicate(predicate);
1389 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1390 if let GenericParamKind::Lifetime { .. } = param.kind {
1391 self.check_lifetime(param.ident);
1393 visit::walk_generic_param(self, param);
1396 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1397 if let GenericBound::Trait(ref poly, modify) = *bound {
1398 match (ctxt, modify) {
1399 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1402 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1403 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1404 err.note(&format!("traits are `?{}` by default", path_str));
1407 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1408 let mut err = self.err_handler().struct_span_err(
1410 "`?Trait` is not permitted in trait object types",
1414 (_, TraitBoundModifier::MaybeConst) => {
1415 if !self.is_tilde_const_allowed {
1417 .struct_span_err(bound.span(), "`~const` is not allowed here")
1418 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1422 (_, TraitBoundModifier::MaybeConstMaybe) => {
1424 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1430 visit::walk_param_bound(self, bound)
1433 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1434 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1435 visit::walk_poly_trait_ref(self, t);
1438 fn visit_variant_data(&mut self, s: &'a VariantData) {
1439 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1442 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1443 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1446 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1447 // Only associated `fn`s can have `self` parameters.
1448 let self_semantic = match fk.ctxt() {
1449 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1450 _ => SelfSemantic::No,
1452 self.check_fn_decl(fk.decl(), self_semantic);
1454 self.check_c_variadic_type(fk);
1456 // Functions cannot both be `const async`
1457 if let Some(FnHeader {
1458 constness: Const::Yes(cspan),
1459 asyncness: Async::Yes { span: aspan, .. },
1465 vec![*cspan, *aspan],
1466 "functions cannot be both `const` and `async`",
1468 .span_label(*cspan, "`const` because of this")
1469 .span_label(*aspan, "`async` because of this")
1470 .span_label(span, "") // Point at the fn header.
1474 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1475 self.check_late_bound_lifetime_defs(generic_params);
1481 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1487 self.maybe_lint_missing_abi(*sig_span, id);
1490 // Functions without bodies cannot have patterns.
1491 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1492 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1493 let (code, msg, label) = match ctxt {
1494 FnCtxt::Foreign => (
1496 "patterns aren't allowed in foreign function declarations",
1497 "pattern not allowed in foreign function",
1501 "patterns aren't allowed in functions without bodies",
1502 "pattern not allowed in function without body",
1505 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1506 if let Some(ident) = ident {
1507 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1508 self.lint_buffer.buffer_lint_with_diagnostic(
1509 PATTERNS_IN_FNS_WITHOUT_BODY,
1518 .struct_span_err(span, msg)
1519 .span_label(span, label)
1526 let tilde_const_allowed =
1527 matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1528 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1530 self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk));
1533 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1534 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1535 self.check_nomangle_item_asciionly(item.ident, item.span);
1538 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1539 self.check_defaultness(item.span, item.kind.defaultness());
1542 if ctxt == AssocCtxt::Impl {
1544 AssocItemKind::Const(_, _, body) => {
1546 self.session.emit_err(AssocConstWithoutBody {
1548 replace_span: self.ending_semi_or_hi(item.span),
1552 AssocItemKind::Fn(box Fn { body, .. }) => {
1554 self.session.emit_err(AssocFnWithoutBody {
1556 replace_span: self.ending_semi_or_hi(item.span),
1560 AssocItemKind::TyAlias(box TyAlias {
1563 where_predicates_split,
1569 self.session.emit_err(AssocTypeWithoutBody {
1571 replace_span: self.ending_semi_or_hi(item.span),
1574 self.check_type_no_bounds(bounds, "`impl`s");
1576 self.check_gat_where(
1578 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1587 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1588 self.invalid_visibility(&item.vis, None);
1589 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1590 self.check_trait_fn_not_const(sig.header.constness);
1594 if let AssocItemKind::Const(..) = item.kind {
1595 self.check_item_named(item.ident, "const");
1599 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1600 if ctxt == AssocCtxt::Trait =>
1602 self.visit_vis(&item.vis);
1603 self.visit_ident(item.ident);
1604 walk_list!(self, visit_attribute, &item.attrs);
1605 self.with_tilde_const_allowed(|this| {
1606 this.visit_generics(generics);
1607 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1609 walk_list!(self, visit_ty, ty);
1611 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1612 if self.in_const_trait_impl
1613 || ctxt == AssocCtxt::Trait
1614 || matches!(sig.header.constness, Const::Yes(_)) =>
1616 self.visit_vis(&item.vis);
1617 self.visit_ident(item.ident);
1618 let kind = FnKind::Fn(
1619 FnCtxt::Assoc(ctxt),
1626 self.visit_fn(kind, item.span, item.id);
1629 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1634 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1635 /// like it's setting an associated type, provide an appropriate suggestion.
1636 fn deny_equality_constraints(
1637 this: &mut AstValidator<'_>,
1638 predicate: &WhereEqPredicate,
1639 generics: &Generics,
1641 let mut err = this.err_handler().struct_span_err(
1643 "equality constraints are not yet supported in `where` clauses",
1645 err.span_label(predicate.span, "not supported");
1647 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1648 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1649 if let TyKind::Path(None, path) = &qself.ty.kind {
1650 match &path.segments[..] {
1651 [PathSegment { ident, args: None, .. }] => {
1652 for param in &generics.params {
1653 if param.ident == *ident {
1655 match &full_path.segments[qself.position..] {
1656 [PathSegment { ident, args, .. }] => {
1657 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1658 let mut assoc_path = full_path.clone();
1659 // Remove `Bar` from `Foo::Bar`.
1660 assoc_path.segments.pop();
1661 let len = assoc_path.segments.len() - 1;
1662 let gen_args = args.as_ref().map(|p| (**p).clone());
1663 // Build `<Bar = RhsTy>`.
1664 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1665 id: rustc_ast::node_id::DUMMY_NODE_ID,
1668 kind: AssocConstraintKind::Equality {
1669 term: predicate.rhs_ty.clone().into(),
1673 // Add `<Bar = RhsTy>` to `Foo`.
1674 match &mut assoc_path.segments[len].args {
1675 Some(args) => match args.deref_mut() {
1676 GenericArgs::Parenthesized(_) => continue,
1677 GenericArgs::AngleBracketed(args) => {
1678 args.args.push(arg);
1682 *empty_args = AngleBracketedArgs {
1689 err.span_suggestion_verbose(
1692 "if `{}` is an associated type you're trying to set, \
1693 use the associated type binding syntax",
1699 pprust::path_to_string(&assoc_path)
1701 Applicability::MaybeIncorrect,
1713 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1714 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1715 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1716 for param in &generics.params {
1717 if param.ident == potential_param.ident {
1718 for bound in ¶m.bounds {
1719 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1721 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1722 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1723 potential_assoc.ident,
1725 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1726 let (args, span) = match &trait_segment.args {
1727 Some(args) => match args.deref() {
1728 ast::GenericArgs::AngleBracketed(args) => {
1729 let Some(arg) = args.args.last() else {
1733 format!(", {} = {}", assoc, ty),
1734 arg.span().shrink_to_hi(),
1740 format!("<{} = {}>", assoc, ty),
1741 trait_segment.span().shrink_to_hi(),
1744 err.multipart_suggestion(
1746 "if `{}::{}` is an associated type you're trying to set, \
1747 use the associated type binding syntax",
1748 trait_segment.ident, potential_assoc.ident,
1750 vec![(span, args), (predicate.span, String::new())],
1751 Applicability::MaybeIncorrect,
1761 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1766 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1767 let mut validator = AstValidator {
1770 in_trait_impl: false,
1771 in_const_trait_impl: false,
1772 has_proc_macro_decls: false,
1773 outer_impl_trait: None,
1774 is_tilde_const_allowed: false,
1775 is_impl_trait_banned: false,
1776 is_assoc_ty_bound_banned: false,
1777 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1780 visit::walk_crate(&mut validator, krate);
1782 validator.has_proc_macro_decls
1785 /// Used to forbid `let` expressions in certain syntactic locations.
1786 #[derive(Clone, Copy)]
1787 pub(crate) enum ForbiddenLetReason {
1788 /// `let` is not valid and the source environment is not important
1790 /// A let chain with the `||` operator
1791 NotSupportedOr(Span),
1792 /// A let chain with invalid parentheses
1794 /// For example, `let 1 = 1 && (expr && expr)` is allowed
1795 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1796 NotSupportedParentheses(Span),