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_macros::Subdiagnostic;
18 use rustc_parse::validate_attr;
19 use rustc_session::lint::builtin::{
20 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
22 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
23 use rustc_session::Session;
24 use rustc_span::source_map::Spanned;
25 use rustc_span::symbol::{kw, sym, Ident};
27 use rustc_target::spec::abi;
29 use std::ops::{Deref, DerefMut};
33 const MORE_EXTERN: &str =
34 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
36 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
42 /// What is the context that prevents using `~const`?
43 enum DisallowTildeConstContext<'a> {
49 struct AstValidator<'a> {
52 /// The span of the `extern` in an `extern { ... }` block, if any.
53 extern_mod: Option<&'a Item>,
55 /// Are we inside a trait impl?
58 in_const_trait_impl: bool,
60 has_proc_macro_decls: bool,
62 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
63 /// Nested `impl Trait` _is_ allowed in associated type position,
64 /// e.g., `impl Iterator<Item = impl Debug>`.
65 outer_impl_trait: Option<Span>,
67 disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
69 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
70 /// or `Foo::Bar<impl Trait>`
71 is_impl_trait_banned: bool,
73 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
74 /// certain positions.
75 is_assoc_ty_bound_banned: bool,
77 /// See [ForbiddenLetReason]
78 forbidden_let_reason: Option<ForbiddenLetReason>,
80 lint_buffer: &'a mut LintBuffer,
83 impl<'a> AstValidator<'a> {
84 fn with_in_trait_impl(
87 constness: Option<Const>,
88 f: impl FnOnce(&mut Self),
90 let old = mem::replace(&mut self.in_trait_impl, is_in);
92 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
94 self.in_trait_impl = old;
95 self.in_const_trait_impl = old_const;
98 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
99 let old = mem::replace(&mut self.is_impl_trait_banned, true);
101 self.is_impl_trait_banned = old;
106 disallowed: Option<DisallowTildeConstContext<'a>>,
107 f: impl FnOnce(&mut Self),
109 let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
111 self.disallow_tilde_const = old;
114 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
115 self.with_tilde_const(None, f)
118 fn with_banned_tilde_const(
120 ctx: DisallowTildeConstContext<'a>,
121 f: impl FnOnce(&mut Self),
123 self.with_tilde_const(Some(ctx), f)
126 fn with_let_management(
128 forbidden_let_reason: Option<ForbiddenLetReason>,
129 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
131 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
133 self.forbidden_let_reason = old;
136 /// Emits an error banning the `let` expression provided in the given location.
137 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
138 let sess = &self.session;
139 if sess.opts.unstable_features.is_nightly_build() {
140 sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
142 sess.emit_err(ForbiddenLetStable { span: expr.span });
149 before_predicates: &[WherePredicate],
150 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
152 if !before_predicates.is_empty() {
153 let mut state = State::new();
154 if !where_clauses.1.0 {
156 state.word_space("where");
158 state.word_space(",");
160 let mut first = true;
161 for p in before_predicates.iter() {
163 state.word_space(",");
166 state.print_where_predicate(p);
168 let suggestion = state.s.eof();
169 self.lint_buffer.buffer_lint_with_diagnostic(
170 DEPRECATED_WHERE_CLAUSE_LOCATION,
173 fluent::ast_passes_deprecated_where_clause_location,
174 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
175 where_clauses.1.1.shrink_to_hi(),
182 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
183 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
185 self.is_assoc_ty_bound_banned = old;
188 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
189 let old = mem::replace(&mut self.outer_impl_trait, outer);
191 self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
195 self.outer_impl_trait = old;
198 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
199 match constraint.kind {
200 AssocConstraintKind::Equality { .. } => {}
201 AssocConstraintKind::Bound { .. } => {
202 if self.is_assoc_ty_bound_banned {
203 self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
207 self.visit_assoc_constraint(constraint);
210 // Mirrors `visit::walk_ty`, but tracks relevant state.
211 fn walk_ty(&mut self, t: &'a Ty) {
213 TyKind::ImplTrait(..) => {
214 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
216 TyKind::TraitObject(..) => self
217 .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
218 visit::walk_ty(this, t)
220 TyKind::Path(ref qself, ref path) => {
222 // - `Option<impl Trait>`
223 // - `option::Option<impl Trait>`
224 // - `option::Option<T>::Foo<impl Trait>
227 // - `<impl Trait>::Foo`
228 // - `option::Option<impl Trait>::Foo`.
230 // To implement this, we disallow `impl Trait` from `qself`
231 // (for cases like `<impl Trait>::Foo>`)
232 // but we allow `impl Trait` in `GenericArgs`
233 // iff there are no more PathSegments.
234 if let Some(ref qself) = *qself {
235 // `impl Trait` in `qself` is always illegal
236 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
239 // Note that there should be a call to visit_path here,
240 // so if any logic is added to process `Path`s a call to it should be
241 // added both in visit_path and here. This code mirrors visit::walk_path.
242 for (i, segment) in path.segments.iter().enumerate() {
243 // Allow `impl Trait` iff we're on the final path segment
244 if i == path.segments.len() - 1 {
245 self.visit_path_segment(segment);
247 self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
251 _ => visit::walk_ty(self, t),
255 fn err_handler(&self) -> &rustc_errors::Handler {
256 &self.session.diagnostic()
259 fn check_lifetime(&self, ident: Ident) {
260 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
261 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
262 self.session.emit_err(KeywordLifetime { span: ident.span });
266 fn check_label(&self, ident: Ident) {
267 if ident.without_first_quote().is_reserved() {
268 self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
272 fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
273 if let VisibilityKind::Inherited = vis.kind {
277 self.session.emit_err(InvalidVisibility {
279 implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
284 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
285 for Param { pat, .. } in &decl.inputs {
287 PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {}
288 PatKind::Ident(BindingAnnotation::MUT, ident, None) => {
289 report_err(pat.span, Some(ident), true)
291 _ => report_err(pat.span, None, false),
296 fn check_trait_fn_not_const(&self, constness: Const) {
297 if let Const::Yes(span) = constness {
298 self.session.emit_err(TraitFnConst { span });
302 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
303 // Check only lifetime parameters are present and that the lifetime
304 // parameters that are present have no bounds.
305 let non_lt_param_spans: Vec<_> = params
307 .filter_map(|param| match param.kind {
308 GenericParamKind::Lifetime { .. } => {
309 if !param.bounds.is_empty() {
310 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
311 self.session.emit_err(ForbiddenLifetimeBound { spans });
315 _ => Some(param.ident.span),
318 if !non_lt_param_spans.is_empty() {
319 self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
323 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
324 self.check_decl_num_args(fn_decl);
325 self.check_decl_cvaradic_pos(fn_decl);
326 self.check_decl_attrs(fn_decl);
327 self.check_decl_self_param(fn_decl, self_semantic);
330 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
331 /// Error is fatal to prevent errors during typechecking
332 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
333 let max_num_args: usize = u16::MAX.into();
334 if fn_decl.inputs.len() > max_num_args {
335 let Param { span, .. } = fn_decl.inputs[0];
336 self.session.emit_fatal(FnParamTooMany { span, max_num_args });
340 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
341 match &*fn_decl.inputs {
342 [Param { ty, span, .. }] => {
343 if let TyKind::CVarArgs = ty.kind {
344 self.session.emit_err(FnParamCVarArgsOnly { span: *span });
348 for Param { ty, span, .. } in ps {
349 if let TyKind::CVarArgs = ty.kind {
350 self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
358 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
362 .flat_map(|i| i.attrs.as_ref())
373 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
376 if attr.is_doc_comment() {
377 self.session.emit_err(FnParamDocComment { span: attr.span });
379 self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
384 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
385 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
387 self.session.emit_err(FnParamForbiddenSelf { span: param.span });
392 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
393 if let Defaultness::Default(def_span) = defaultness {
394 let span = self.session.source_map().guess_head_span(span);
395 self.session.emit_err(ForbiddenDefault { span, def_span });
399 /// If `sp` ends with a semicolon, returns it as a `Span`
400 /// Otherwise, returns `sp.shrink_to_hi()`
401 fn ending_semi_or_hi(&self, sp: Span) -> Span {
402 let source_map = self.session.source_map();
403 let end = source_map.end_point(sp);
405 if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
412 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
413 let span = match bounds {
416 [b0, .., bl] => b0.span().to(bl.span()),
419 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
423 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
424 let cannot_have = |span, descr, remove_descr| {
428 &format!("`type`s inside `extern` blocks cannot have {}", descr),
432 &format!("remove the {}", remove_descr),
434 Applicability::MaybeIncorrect,
436 .span_label(self.current_extern_span(), "`extern` block begins here")
441 if !generics.params.is_empty() {
442 cannot_have(generics.span, "generic parameters", "generic parameters");
445 if !generics.where_clause.predicates.is_empty() {
446 cannot_have(where_span, "`where` clauses", "`where` clause");
450 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
451 let Some(body) = body else {
455 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
456 .span_label(ident.span, "cannot have a body")
457 .span_label(body, "the invalid body")
459 self.current_extern_span(),
461 "`extern` blocks define existing foreign {0}s and {0}s \
462 inside of them cannot have a body",
470 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
471 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
472 let Some(body) = body else {
476 .struct_span_err(ident.span, "incorrect function inside `extern` block")
477 .span_label(ident.span, "cannot have a body")
480 "remove the invalid body",
482 Applicability::MaybeIncorrect,
485 "you might have meant to write a function accessible through FFI, \
486 which can be done by writing `extern fn` outside of the `extern` block",
489 self.current_extern_span(),
490 "`extern` blocks define existing foreign functions and functions \
491 inside of them cannot have a body",
497 fn current_extern_span(&self) -> Span {
498 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
501 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
502 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
503 if header.has_qualifiers() {
505 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
506 .span_label(self.current_extern_span(), "in this `extern` block")
507 .span_suggestion_verbose(
508 span.until(ident.span.shrink_to_lo()),
509 "remove the qualifiers",
511 Applicability::MaybeIncorrect,
517 /// An item in `extern { ... }` cannot use non-ascii identifier.
518 fn check_foreign_item_ascii_only(&self, ident: Ident) {
519 if !ident.as_str().is_ascii() {
524 "items in `extern` blocks cannot use non-ascii identifiers",
526 .span_label(self.current_extern_span(), "in this `extern` block")
528 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
535 /// Reject C-variadic type unless the function is foreign,
536 /// or free and `unsafe extern "C"` semantically.
537 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
538 match (fk.ctxt(), fk.header()) {
539 (Some(FnCtxt::Foreign), _) => return,
540 (Some(FnCtxt::Free), Some(header)) => match header.ext {
541 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
542 | Extern::Implicit(_)
543 if matches!(header.unsafety, Unsafe::Yes(_)) =>
552 for Param { ty, span, .. } in &fk.decl().inputs {
553 if let TyKind::CVarArgs = ty.kind {
557 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
564 fn check_item_named(&self, ident: Ident, kind: &str) {
565 if ident.name != kw::Underscore {
569 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
570 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
574 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
575 if ident.name.as_str().is_ascii() {
578 let head_span = self.session.source_map().guess_head_span(item_span);
583 "`#[no_mangle]` requires ASCII identifier"
588 fn check_mod_file_item_asciionly(&self, ident: Ident) {
589 if ident.name.as_str().is_ascii() {
596 "trying to load file for module `{}` with non-ascii identifier name",
599 .help("consider using `#[path]` attribute to specify filesystem path")
603 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
604 if !generics.params.is_empty() {
609 "auto traits cannot have generic parameters"
611 .span_label(ident_span, "auto trait cannot have generic parameters")
614 "remove the parameters",
616 Applicability::MachineApplicable,
622 fn emit_e0568(&self, span: Span, ident_span: Span) {
627 "auto traits cannot have super traits or lifetime bounds"
629 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
632 "remove the super traits or lifetime bounds",
634 Applicability::MachineApplicable,
639 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
640 if let [.., last] = &bounds[..] {
641 let span = ident_span.shrink_to_hi().to(last.span());
642 self.emit_e0568(span, ident_span);
646 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
647 if !where_clause.predicates.is_empty() {
648 self.emit_e0568(where_clause.span, ident_span);
652 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
653 if !trait_items.is_empty() {
654 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
655 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
660 "auto traits cannot have associated items"
664 "remove these associated items",
666 Applicability::MachineApplicable,
668 .span_label(ident_span, "auto trait cannot have associated items")
673 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
674 // Lifetimes always come first.
675 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
676 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
677 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
681 let args_sugg = data.args.iter().filter_map(|a| match a {
682 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
685 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
687 // Constraints always come last.
688 let constraint_sugg = data.args.iter().filter_map(|a| match a {
689 AngleBracketedArg::Arg(_) => None,
690 AngleBracketedArg::Constraint(c) => {
691 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
696 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
700 /// Enforce generic args coming before constraints in `<...>` of a path segment.
701 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
702 // Early exit in case it's partitioned as it should be.
703 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
706 // Find all generic argument coming after the first constraint...
707 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
708 data.args.iter().partition_map(|arg| match arg {
709 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
710 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
712 let args_len = arg_spans.len();
713 let constraint_len = constraint_spans.len();
714 // ...and then error:
718 "generic arguments must come before the first constraint",
720 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
722 *arg_spans.iter().last().unwrap(),
723 &format!("generic argument{}", pluralize!(args_len)),
725 .span_labels(constraint_spans, "")
726 .span_labels(arg_spans, "")
727 .span_suggestion_verbose(
730 "move the constraint{} after the generic argument{}",
731 pluralize!(constraint_len),
734 self.correct_generic_order_suggestion(&data),
735 Applicability::MachineApplicable,
740 fn visit_ty_common(&mut self, ty: &'a Ty) {
742 TyKind::BareFn(ref bfty) => {
743 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
744 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
749 "patterns aren't allowed in function pointer types"
753 self.check_late_bound_lifetime_defs(&bfty.generic_params);
754 if let Extern::Implicit(_) = bfty.ext {
755 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
756 self.maybe_lint_missing_abi(sig_span, ty.id);
759 TyKind::TraitObject(ref bounds, ..) => {
760 let mut any_lifetime_bounds = false;
761 for bound in bounds {
762 if let GenericBound::Outlives(ref lifetime) = *bound {
763 if any_lifetime_bounds {
768 "only a single explicit lifetime bound is permitted"
773 any_lifetime_bounds = true;
777 TyKind::ImplTrait(_, ref bounds) => {
778 if self.is_impl_trait_banned {
783 "`impl Trait` is not allowed in path parameters"
788 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
793 "nested `impl Trait` is not allowed"
795 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
796 .span_label(ty.span, "nested `impl Trait` here")
800 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
801 self.err_handler().span_err(ty.span, "at least one trait must be specified");
808 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
809 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
810 // call site which do not have a macro backtrace. See #61963.
811 let is_macro_callsite = self
814 .span_to_snippet(span)
815 .map(|snippet| snippet.starts_with("#["))
817 if !is_macro_callsite {
818 self.lint_buffer.buffer_lint_with_diagnostic(
822 "extern declarations without an explicit ABI are deprecated",
823 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
829 /// Checks that generic parameters are in the correct order,
830 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
831 fn validate_generic_param_order(
832 handler: &rustc_errors::Handler,
833 generics: &[GenericParam],
836 let mut max_param: Option<ParamKindOrd> = None;
837 let mut out_of_order = FxHashMap::default();
838 let mut param_idents = Vec::with_capacity(generics.len());
840 for (idx, param) in generics.iter().enumerate() {
841 let ident = param.ident;
842 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
843 let (ord_kind, ident) = match ¶m.kind {
844 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
845 GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()),
846 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
847 let ty = pprust::ty_to_string(ty);
848 (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
851 param_idents.push((kind, ord_kind, bounds, idx, ident));
853 Some(max_param) if max_param > ord_kind => {
854 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
857 Some(_) | None => max_param = Some(ord_kind),
861 if !out_of_order.is_empty() {
862 let mut ordered_params = "<".to_string();
863 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
864 let mut first = true;
865 for (kind, _, bounds, _, ident) in param_idents {
867 ordered_params += ", ";
869 ordered_params += &ident;
871 if !bounds.is_empty() {
872 ordered_params += ": ";
873 ordered_params += &pprust::bounds_to_string(&bounds);
877 GenericParamKind::Type { default: Some(default) } => {
878 ordered_params += " = ";
879 ordered_params += &pprust::ty_to_string(default);
881 GenericParamKind::Type { default: None } => (),
882 GenericParamKind::Lifetime => (),
883 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
884 ordered_params += " = ";
885 ordered_params += &pprust::expr_to_string(&*default.value);
887 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
892 ordered_params += ">";
894 for (param_ord, (max_param, spans)) in &out_of_order {
895 let mut err = handler.struct_span_err(
898 "{} parameters must be declared prior to {} parameters",
899 param_ord, max_param,
904 "reorder the parameters: lifetimes, then consts and types",
906 Applicability::MachineApplicable,
913 impl<'a> Visitor<'a> for AstValidator<'a> {
914 fn visit_attribute(&mut self, attr: &Attribute) {
915 validate_attr::check_meta(&self.session.parse_sess, attr);
918 fn visit_expr(&mut self, expr: &'a Expr) {
919 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
921 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
922 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
923 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
924 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
926 ExprKind::If(cond, then, opt_else) => {
927 this.visit_block(then);
928 walk_list!(this, visit_expr, opt_else);
929 this.with_let_management(None, |this, _| this.visit_expr(cond));
932 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
933 this.ban_let_expr(expr, elem);
935 ExprKind::Match(scrutinee, arms) => {
936 this.visit_expr(scrutinee);
938 this.visit_expr(&arm.body);
939 this.visit_pat(&arm.pat);
940 walk_list!(this, visit_attribute, &arm.attrs);
941 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
942 this.with_let_management(None, |this, _| {
943 this.visit_expr(guard_expr)
949 ExprKind::Paren(local_expr) => {
950 fn has_let_expr(expr: &Expr) -> bool {
952 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
953 ExprKind::Let(..) => true,
957 let local_reason = if has_let_expr(local_expr) {
958 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
963 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
965 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
966 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
969 ExprKind::While(cond, then, opt_label) => {
970 walk_list!(this, visit_label, opt_label);
971 this.visit_block(then);
972 this.with_let_management(None, |this, _| this.visit_expr(cond));
975 _ => visit::walk_expr(this, expr),
980 fn visit_ty(&mut self, ty: &'a Ty) {
981 self.visit_ty_common(ty);
985 fn visit_label(&mut self, label: &'a Label) {
986 self.check_label(label.ident);
987 visit::walk_label(self, label);
990 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
991 self.check_lifetime(lifetime.ident);
992 visit::walk_lifetime(self, lifetime);
995 fn visit_field_def(&mut self, field: &'a FieldDef) {
996 visit::walk_field_def(self, field)
999 fn visit_item(&mut self, item: &'a Item) {
1000 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1001 self.has_proc_macro_decls = true;
1004 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1005 self.check_nomangle_item_asciionly(item.ident, item.span);
1009 ItemKind::Impl(box Impl {
1015 of_trait: Some(ref t),
1019 self.with_in_trait_impl(true, Some(constness), |this| {
1020 this.invalid_visibility(&item.vis, None);
1021 if let TyKind::Err = self_ty.kind {
1025 "`impl Trait for .. {}` is an obsolete syntax",
1027 .help("use `auto trait Trait {}` instead")
1030 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1035 "negative impls cannot be unsafe"
1037 .span_label(sp, "negative because of this")
1038 .span_label(span, "unsafe because of this")
1042 this.visit_vis(&item.vis);
1043 this.visit_ident(item.ident);
1044 if let Const::Yes(_) = constness {
1045 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1047 this.visit_generics(generics);
1049 this.visit_trait_ref(t);
1050 this.visit_ty(self_ty);
1052 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1054 walk_list!(self, visit_attribute, &item.attrs);
1055 return; // Avoid visiting again.
1057 ItemKind::Impl(box Impl {
1067 let error = |annotation_span, annotation| {
1068 let mut err = self.err_handler().struct_span_err(
1070 &format!("inherent impls cannot be {}", annotation),
1072 err.span_label(annotation_span, &format!("{} because of this", annotation));
1073 err.span_label(self_ty.span, "inherent impl for this type");
1077 self.invalid_visibility(
1079 Some(InvalidVisibilityNote::IndividualImplItems),
1081 if let Unsafe::Yes(span) = unsafety {
1082 error(span, "unsafe").code(error_code!(E0197)).emit();
1084 if let ImplPolarity::Negative(span) = polarity {
1085 error(span, "negative").emit();
1087 if let Defaultness::Default(def_span) = defaultness {
1088 error(def_span, "`default`")
1089 .note("only trait implementations may be annotated with `default`")
1092 if let Const::Yes(span) = constness {
1093 error(span, "`const`")
1094 .note("only trait implementations may be annotated with `const`")
1098 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1099 self.check_defaultness(item.span, defaultness);
1102 self.session.emit_err(FnWithoutBody {
1104 replace_span: self.ending_semi_or_hi(item.span),
1105 extern_block_suggestion: match sig.header.ext {
1106 Extern::None => None,
1107 Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1109 end_span: item.span.shrink_to_hi(),
1112 Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1114 end_span: item.span.shrink_to_hi(),
1115 abi: Some(abi.symbol_unescaped),
1121 self.visit_vis(&item.vis);
1122 self.visit_ident(item.ident);
1124 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1125 self.visit_fn(kind, item.span, item.id);
1126 walk_list!(self, visit_attribute, &item.attrs);
1127 return; // Avoid visiting again.
1129 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1130 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1131 self.invalid_visibility(
1133 Some(InvalidVisibilityNote::IndividualForeignItems),
1135 if let Unsafe::Yes(span) = unsafety {
1136 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1139 self.maybe_lint_missing_abi(item.span, item.id);
1141 visit::walk_item(self, item);
1142 self.extern_mod = old_item;
1143 return; // Avoid visiting again.
1145 ItemKind::Enum(ref def, _) => {
1146 for variant in &def.variants {
1147 self.invalid_visibility(&variant.vis, None);
1148 for field in variant.data.fields() {
1149 self.invalid_visibility(&field.vis, None);
1153 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1154 if is_auto == IsAuto::Yes {
1155 // Auto traits cannot have generics, super traits nor contain items.
1156 self.deny_generic_params(generics, item.ident.span);
1157 self.deny_super_traits(bounds, item.ident.span);
1158 self.deny_where_clause(&generics.where_clause, item.ident.span);
1159 self.deny_items(items, item.ident.span);
1162 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1163 // context for the supertraits.
1164 self.visit_vis(&item.vis);
1165 self.visit_ident(item.ident);
1166 self.visit_generics(generics);
1167 self.with_tilde_const_allowed(|this| {
1168 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1170 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1171 walk_list!(self, visit_attribute, &item.attrs);
1172 return; // Avoid visiting again
1174 ItemKind::Mod(unsafety, ref mod_kind) => {
1175 if let Unsafe::Yes(span) = unsafety {
1176 self.err_handler().span_err(span, "module cannot be declared unsafe");
1178 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1179 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1180 && !self.session.contains_name(&item.attrs, sym::path)
1182 self.check_mod_file_item_asciionly(item.ident);
1185 ItemKind::Union(ref vdata, ..) => {
1186 if vdata.fields().is_empty() {
1187 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1190 ItemKind::Const(def, .., None) => {
1191 self.check_defaultness(item.span, def);
1192 self.session.emit_err(ConstWithoutBody {
1194 replace_span: self.ending_semi_or_hi(item.span),
1197 ItemKind::Static(.., None) => {
1198 self.session.emit_err(StaticWithoutBody {
1200 replace_span: self.ending_semi_or_hi(item.span),
1203 ItemKind::TyAlias(box TyAlias {
1210 self.check_defaultness(item.span, defaultness);
1212 self.session.emit_err(TyAliasWithoutBody {
1214 replace_span: self.ending_semi_or_hi(item.span),
1217 self.check_type_no_bounds(bounds, "this context");
1218 if where_clauses.1.0 {
1219 let mut err = self.err_handler().struct_span_err(
1221 "where clauses are not allowed after the type for type aliases",
1224 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1232 visit::walk_item(self, item);
1235 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1237 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1238 self.check_defaultness(fi.span, *defaultness);
1239 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1240 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1241 self.check_foreign_item_ascii_only(fi.ident);
1243 ForeignItemKind::TyAlias(box TyAlias {
1251 self.check_defaultness(fi.span, *defaultness);
1252 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1253 self.check_type_no_bounds(bounds, "`extern` blocks");
1254 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1255 self.check_foreign_item_ascii_only(fi.ident);
1257 ForeignItemKind::Static(_, _, body) => {
1258 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1259 self.check_foreign_item_ascii_only(fi.ident);
1261 ForeignItemKind::MacCall(..) => {}
1264 visit::walk_foreign_item(self, fi)
1267 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1268 fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
1269 match *generic_args {
1270 GenericArgs::AngleBracketed(ref data) => {
1271 self.check_generic_args_before_constraints(data);
1273 for arg in &data.args {
1275 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1276 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1277 // are allowed to contain nested `impl Trait`.
1278 AngleBracketedArg::Constraint(constraint) => {
1279 self.with_impl_trait(None, |this| {
1280 this.visit_assoc_constraint_from_generic_args(constraint);
1286 GenericArgs::Parenthesized(ref data) => {
1287 walk_list!(self, visit_ty, &data.inputs);
1288 if let FnRetTy::Ty(ty) = &data.output {
1289 // `-> Foo` syntax is essentially an associated type binding,
1290 // so it is also allowed to contain nested `impl Trait`.
1291 self.with_impl_trait(None, |this| this.visit_ty(ty));
1297 fn visit_generics(&mut self, generics: &'a Generics) {
1298 let mut prev_param_default = None;
1299 for param in &generics.params {
1301 GenericParamKind::Lifetime => (),
1302 GenericParamKind::Type { default: Some(_), .. }
1303 | GenericParamKind::Const { default: Some(_), .. } => {
1304 prev_param_default = Some(param.ident.span);
1306 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1307 if let Some(span) = prev_param_default {
1308 let mut err = self.err_handler().struct_span_err(
1310 "generic parameters with a default must be trailing",
1319 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1321 for predicate in &generics.where_clause.predicates {
1322 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1323 deny_equality_constraints(self, predicate, generics);
1326 walk_list!(self, visit_generic_param, &generics.params);
1327 for predicate in &generics.where_clause.predicates {
1329 WherePredicate::BoundPredicate(bound_pred) => {
1330 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1331 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1333 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1334 // binder and thus we only allow a single level of quantification. However,
1335 // the syntax of Rust permits quantification in two places in where clauses,
1336 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1337 // defined, then error.
1338 if !bound_pred.bound_generic_params.is_empty() {
1339 for bound in &bound_pred.bounds {
1341 GenericBound::Trait(t, _) => {
1342 if !t.bound_generic_params.is_empty() {
1347 "nested quantification of lifetimes"
1352 GenericBound::Outlives(_) => {}
1359 self.visit_where_predicate(predicate);
1363 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1364 if let GenericParamKind::Lifetime { .. } = param.kind {
1365 self.check_lifetime(param.ident);
1367 visit::walk_generic_param(self, param);
1370 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1371 if let GenericBound::Trait(ref poly, modify) = *bound {
1372 match (ctxt, modify) {
1373 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1376 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1377 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1378 err.note(&format!("traits are `?{}` by default", path_str));
1381 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1382 let mut err = self.err_handler().struct_span_err(
1384 "`?Trait` is not permitted in trait object types",
1388 (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
1389 let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
1391 DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
1392 DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
1393 DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
1394 DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
1398 (_, TraitBoundModifier::MaybeConstMaybe) => {
1400 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1406 visit::walk_param_bound(self, bound)
1409 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1410 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1411 visit::walk_poly_trait_ref(self, t);
1414 fn visit_variant_data(&mut self, s: &'a VariantData) {
1415 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1418 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1419 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1422 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1423 // Only associated `fn`s can have `self` parameters.
1424 let self_semantic = match fk.ctxt() {
1425 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1426 _ => SelfSemantic::No,
1428 self.check_fn_decl(fk.decl(), self_semantic);
1430 self.check_c_variadic_type(fk);
1432 // Functions cannot both be `const async`
1433 if let Some(FnHeader {
1434 constness: Const::Yes(cspan),
1435 asyncness: Async::Yes { span: aspan, .. },
1441 vec![*cspan, *aspan],
1442 "functions cannot be both `const` and `async`",
1444 .span_label(*cspan, "`const` because of this")
1445 .span_label(*aspan, "`async` because of this")
1446 .span_label(span, "") // Point at the fn header.
1450 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1451 self.check_late_bound_lifetime_defs(generic_params);
1457 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1463 self.maybe_lint_missing_abi(*sig_span, id);
1466 // Functions without bodies cannot have patterns.
1467 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1468 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1469 let (code, msg, label) = match ctxt {
1470 FnCtxt::Foreign => (
1472 "patterns aren't allowed in foreign function declarations",
1473 "pattern not allowed in foreign function",
1477 "patterns aren't allowed in functions without bodies",
1478 "pattern not allowed in function without body",
1481 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1482 if let Some(ident) = ident {
1483 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1484 self.lint_buffer.buffer_lint_with_diagnostic(
1485 PATTERNS_IN_FNS_WITHOUT_BODY,
1494 .struct_span_err(span, msg)
1495 .span_label(span, label)
1502 let tilde_const_allowed =
1503 matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1504 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1506 let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
1508 self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
1511 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1512 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1513 self.check_nomangle_item_asciionly(item.ident, item.span);
1516 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1517 self.check_defaultness(item.span, item.kind.defaultness());
1520 if ctxt == AssocCtxt::Impl {
1522 AssocItemKind::Const(_, _, body) => {
1524 self.session.emit_err(AssocConstWithoutBody {
1526 replace_span: self.ending_semi_or_hi(item.span),
1530 AssocItemKind::Fn(box Fn { body, .. }) => {
1532 self.session.emit_err(AssocFnWithoutBody {
1534 replace_span: self.ending_semi_or_hi(item.span),
1538 AssocItemKind::Type(box TyAlias {
1541 where_predicates_split,
1547 self.session.emit_err(AssocTypeWithoutBody {
1549 replace_span: self.ending_semi_or_hi(item.span),
1552 self.check_type_no_bounds(bounds, "`impl`s");
1554 self.check_gat_where(
1556 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1565 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1566 self.invalid_visibility(&item.vis, None);
1567 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1568 self.check_trait_fn_not_const(sig.header.constness);
1572 if let AssocItemKind::Const(..) = item.kind {
1573 self.check_item_named(item.ident, "const");
1577 AssocItemKind::Type(box TyAlias { ref generics, ref bounds, ref ty, .. })
1578 if ctxt == AssocCtxt::Trait =>
1580 self.visit_vis(&item.vis);
1581 self.visit_ident(item.ident);
1582 walk_list!(self, visit_attribute, &item.attrs);
1583 self.with_tilde_const_allowed(|this| {
1584 this.visit_generics(generics);
1585 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1587 walk_list!(self, visit_ty, ty);
1589 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1590 if self.in_const_trait_impl
1591 || ctxt == AssocCtxt::Trait
1592 || matches!(sig.header.constness, Const::Yes(_)) =>
1594 self.visit_vis(&item.vis);
1595 self.visit_ident(item.ident);
1596 let kind = FnKind::Fn(
1597 FnCtxt::Assoc(ctxt),
1604 self.visit_fn(kind, item.span, item.id);
1607 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1612 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1613 /// like it's setting an associated type, provide an appropriate suggestion.
1614 fn deny_equality_constraints(
1615 this: &mut AstValidator<'_>,
1616 predicate: &WhereEqPredicate,
1617 generics: &Generics,
1619 let mut err = this.err_handler().struct_span_err(
1621 "equality constraints are not yet supported in `where` clauses",
1623 err.span_label(predicate.span, "not supported");
1625 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1626 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1627 if let TyKind::Path(None, path) = &qself.ty.kind {
1628 match &path.segments[..] {
1629 [PathSegment { ident, args: None, .. }] => {
1630 for param in &generics.params {
1631 if param.ident == *ident {
1633 match &full_path.segments[qself.position..] {
1634 [PathSegment { ident, args, .. }] => {
1635 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1636 let mut assoc_path = full_path.clone();
1637 // Remove `Bar` from `Foo::Bar`.
1638 assoc_path.segments.pop();
1639 let len = assoc_path.segments.len() - 1;
1640 let gen_args = args.as_ref().map(|p| (**p).clone());
1641 // Build `<Bar = RhsTy>`.
1642 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1643 id: rustc_ast::node_id::DUMMY_NODE_ID,
1646 kind: AssocConstraintKind::Equality {
1647 term: predicate.rhs_ty.clone().into(),
1651 // Add `<Bar = RhsTy>` to `Foo`.
1652 match &mut assoc_path.segments[len].args {
1653 Some(args) => match args.deref_mut() {
1654 GenericArgs::Parenthesized(_) => continue,
1655 GenericArgs::AngleBracketed(args) => {
1656 args.args.push(arg);
1660 *empty_args = AngleBracketedArgs {
1667 err.span_suggestion_verbose(
1670 "if `{}` is an associated type you're trying to set, \
1671 use the associated type binding syntax",
1677 pprust::path_to_string(&assoc_path)
1679 Applicability::MaybeIncorrect,
1691 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1692 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1693 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1694 for param in &generics.params {
1695 if param.ident == potential_param.ident {
1696 for bound in ¶m.bounds {
1697 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1699 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1700 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1701 potential_assoc.ident,
1703 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1704 let (args, span) = match &trait_segment.args {
1705 Some(args) => match args.deref() {
1706 ast::GenericArgs::AngleBracketed(args) => {
1707 let Some(arg) = args.args.last() else {
1711 format!(", {} = {}", assoc, ty),
1712 arg.span().shrink_to_hi(),
1718 format!("<{} = {}>", assoc, ty),
1719 trait_segment.span().shrink_to_hi(),
1722 err.multipart_suggestion(
1724 "if `{}::{}` is an associated type you're trying to set, \
1725 use the associated type binding syntax",
1726 trait_segment.ident, potential_assoc.ident,
1728 vec![(span, args), (predicate.span, String::new())],
1729 Applicability::MaybeIncorrect,
1739 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1744 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1745 let mut validator = AstValidator {
1748 in_trait_impl: false,
1749 in_const_trait_impl: false,
1750 has_proc_macro_decls: false,
1751 outer_impl_trait: None,
1752 disallow_tilde_const: None,
1753 is_impl_trait_banned: false,
1754 is_assoc_ty_bound_banned: false,
1755 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1758 visit::walk_crate(&mut validator, krate);
1760 validator.has_proc_macro_decls
1763 /// Used to forbid `let` expressions in certain syntactic locations.
1764 #[derive(Clone, Copy, Subdiagnostic)]
1765 pub(crate) enum ForbiddenLetReason {
1766 /// `let` is not valid and the source environment is not important
1768 /// A let chain with the `||` operator
1769 #[note(not_supported_or)]
1770 NotSupportedOr(#[primary_span] Span),
1771 /// A let chain with invalid parentheses
1773 /// For example, `let 1 = 1 && (expr && expr)` is allowed
1774 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1775 #[note(not_supported_parentheses)]
1776 NotSupportedParentheses(#[primary_span] Span),