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(qself, 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(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(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(bounds, ..) => {
760 let mut any_lifetime_bounds = false;
761 for bound in bounds {
762 if let GenericBound::Outlives(lifetime) = bound {
763 if any_lifetime_bounds {
768 "only a single explicit lifetime bound is permitted"
773 any_lifetime_bounds = true;
777 TyKind::ImplTrait(_, 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 { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),
846 GenericParamKind::Const { ty, .. } => {
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_attr(&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(_, lhs, 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 {
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)
1036 "negative impls cannot be unsafe"
1038 .span_label(sp, "negative because of this")
1039 .span_label(span, "unsafe because of this")
1043 this.visit_vis(&item.vis);
1044 this.visit_ident(item.ident);
1045 if let Const::Yes(_) = constness {
1046 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1048 this.visit_generics(generics);
1050 this.visit_trait_ref(t);
1051 this.visit_ty(self_ty);
1053 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1055 walk_list!(self, visit_attribute, &item.attrs);
1056 return; // Avoid visiting again.
1058 ItemKind::Impl(box Impl {
1068 let error = |annotation_span, annotation| {
1069 let mut err = self.err_handler().struct_span_err(
1071 &format!("inherent impls cannot be {}", annotation),
1073 err.span_label(annotation_span, &format!("{} because of this", annotation));
1074 err.span_label(self_ty.span, "inherent impl for this type");
1078 self.invalid_visibility(
1080 Some(InvalidVisibilityNote::IndividualImplItems),
1082 if let &Unsafe::Yes(span) = unsafety {
1083 error(span, "unsafe").code(error_code!(E0197)).emit();
1085 if let &ImplPolarity::Negative(span) = polarity {
1086 error(span, "negative").emit();
1088 if let &Defaultness::Default(def_span) = defaultness {
1089 error(def_span, "`default`")
1090 .note("only trait implementations may be annotated with `default`")
1093 if let &Const::Yes(span) = constness {
1094 error(span, "`const`")
1095 .note("only trait implementations may be annotated with `const`")
1099 ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
1100 self.check_defaultness(item.span, *defaultness);
1103 self.session.emit_err(FnWithoutBody {
1105 replace_span: self.ending_semi_or_hi(item.span),
1106 extern_block_suggestion: match sig.header.ext {
1107 Extern::None => None,
1108 Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1110 end_span: item.span.shrink_to_hi(),
1113 Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1115 end_span: item.span.shrink_to_hi(),
1116 abi: Some(abi.symbol_unescaped),
1122 self.visit_vis(&item.vis);
1123 self.visit_ident(item.ident);
1125 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1126 self.visit_fn(kind, item.span, item.id);
1127 walk_list!(self, visit_attribute, &item.attrs);
1128 return; // Avoid visiting again.
1130 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1131 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1132 self.invalid_visibility(
1134 Some(InvalidVisibilityNote::IndividualForeignItems),
1136 if let &Unsafe::Yes(span) = unsafety {
1137 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1140 self.maybe_lint_missing_abi(item.span, item.id);
1142 visit::walk_item(self, item);
1143 self.extern_mod = old_item;
1144 return; // Avoid visiting again.
1146 ItemKind::Enum(def, _) => {
1147 for variant in &def.variants {
1148 self.invalid_visibility(&variant.vis, None);
1149 for field in variant.data.fields() {
1150 self.invalid_visibility(&field.vis, None);
1154 ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
1155 if *is_auto == IsAuto::Yes {
1156 // Auto traits cannot have generics, super traits nor contain items.
1157 self.deny_generic_params(generics, item.ident.span);
1158 self.deny_super_traits(bounds, item.ident.span);
1159 self.deny_where_clause(&generics.where_clause, item.ident.span);
1160 self.deny_items(items, item.ident.span);
1163 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1164 // context for the supertraits.
1165 self.visit_vis(&item.vis);
1166 self.visit_ident(item.ident);
1167 self.visit_generics(generics);
1168 self.with_tilde_const_allowed(|this| {
1169 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1171 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1172 walk_list!(self, visit_attribute, &item.attrs);
1173 return; // Avoid visiting again
1175 ItemKind::Mod(unsafety, mod_kind) => {
1176 if let &Unsafe::Yes(span) = unsafety {
1177 self.err_handler().span_err(span, "module cannot be declared unsafe");
1179 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1180 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1181 && !self.session.contains_name(&item.attrs, sym::path)
1183 self.check_mod_file_item_asciionly(item.ident);
1186 ItemKind::Union(vdata, ..) => {
1187 if vdata.fields().is_empty() {
1188 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1191 ItemKind::Const(def, .., None) => {
1192 self.check_defaultness(item.span, *def);
1193 self.session.emit_err(ConstWithoutBody {
1195 replace_span: self.ending_semi_or_hi(item.span),
1198 ItemKind::Static(.., None) => {
1199 self.session.emit_err(StaticWithoutBody {
1201 replace_span: self.ending_semi_or_hi(item.span),
1204 ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
1205 self.check_defaultness(item.span, *defaultness);
1207 self.session.emit_err(TyAliasWithoutBody {
1209 replace_span: self.ending_semi_or_hi(item.span),
1212 self.check_type_no_bounds(bounds, "this context");
1213 if where_clauses.1.0 {
1214 let mut err = self.err_handler().struct_span_err(
1216 "where clauses are not allowed after the type for type aliases",
1219 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1227 visit::walk_item(self, item);
1230 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1232 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1233 self.check_defaultness(fi.span, *defaultness);
1234 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1235 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1236 self.check_foreign_item_ascii_only(fi.ident);
1238 ForeignItemKind::TyAlias(box TyAlias {
1246 self.check_defaultness(fi.span, *defaultness);
1247 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1248 self.check_type_no_bounds(bounds, "`extern` blocks");
1249 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1250 self.check_foreign_item_ascii_only(fi.ident);
1252 ForeignItemKind::Static(_, _, body) => {
1253 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1254 self.check_foreign_item_ascii_only(fi.ident);
1256 ForeignItemKind::MacCall(..) => {}
1259 visit::walk_foreign_item(self, fi)
1262 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1263 fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
1264 match generic_args {
1265 GenericArgs::AngleBracketed(data) => {
1266 self.check_generic_args_before_constraints(data);
1268 for arg in &data.args {
1270 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1271 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1272 // are allowed to contain nested `impl Trait`.
1273 AngleBracketedArg::Constraint(constraint) => {
1274 self.with_impl_trait(None, |this| {
1275 this.visit_assoc_constraint_from_generic_args(constraint);
1281 GenericArgs::Parenthesized(data) => {
1282 walk_list!(self, visit_ty, &data.inputs);
1283 if let FnRetTy::Ty(ty) = &data.output {
1284 // `-> Foo` syntax is essentially an associated type binding,
1285 // so it is also allowed to contain nested `impl Trait`.
1286 self.with_impl_trait(None, |this| this.visit_ty(ty));
1292 fn visit_generics(&mut self, generics: &'a Generics) {
1293 let mut prev_param_default = None;
1294 for param in &generics.params {
1296 GenericParamKind::Lifetime => (),
1297 GenericParamKind::Type { default: Some(_), .. }
1298 | GenericParamKind::Const { default: Some(_), .. } => {
1299 prev_param_default = Some(param.ident.span);
1301 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1302 if let Some(span) = prev_param_default {
1303 let mut err = self.err_handler().struct_span_err(
1305 "generic parameters with a default must be trailing",
1314 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1316 for predicate in &generics.where_clause.predicates {
1317 if let WherePredicate::EqPredicate(predicate) = predicate {
1318 deny_equality_constraints(self, predicate, generics);
1321 walk_list!(self, visit_generic_param, &generics.params);
1322 for predicate in &generics.where_clause.predicates {
1324 WherePredicate::BoundPredicate(bound_pred) => {
1325 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1326 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1328 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1329 // binder and thus we only allow a single level of quantification. However,
1330 // the syntax of Rust permits quantification in two places in where clauses,
1331 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1332 // defined, then error.
1333 if !bound_pred.bound_generic_params.is_empty() {
1334 for bound in &bound_pred.bounds {
1336 GenericBound::Trait(t, _) => {
1337 if !t.bound_generic_params.is_empty() {
1342 "nested quantification of lifetimes"
1347 GenericBound::Outlives(_) => {}
1354 self.visit_where_predicate(predicate);
1358 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1359 if let GenericParamKind::Lifetime { .. } = param.kind {
1360 self.check_lifetime(param.ident);
1362 visit::walk_generic_param(self, param);
1365 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1366 if let GenericBound::Trait(poly, modify) = bound {
1367 match (ctxt, modify) {
1368 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1371 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1372 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1373 err.note(&format!("traits are `?{}` by default", path_str));
1376 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1377 let mut err = self.err_handler().struct_span_err(
1379 "`?Trait` is not permitted in trait object types",
1383 (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
1384 let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
1386 DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
1387 DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
1388 DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
1389 DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
1393 (_, TraitBoundModifier::MaybeConstMaybe) => {
1395 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1401 visit::walk_param_bound(self, bound)
1404 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1405 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1406 visit::walk_poly_trait_ref(self, t);
1409 fn visit_variant_data(&mut self, s: &'a VariantData) {
1410 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1413 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1414 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1417 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1418 // Only associated `fn`s can have `self` parameters.
1419 let self_semantic = match fk.ctxt() {
1420 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1421 _ => SelfSemantic::No,
1423 self.check_fn_decl(fk.decl(), self_semantic);
1425 self.check_c_variadic_type(fk);
1427 // Functions cannot both be `const async`
1428 if let Some(FnHeader {
1429 constness: Const::Yes(cspan),
1430 asyncness: Async::Yes { span: aspan, .. },
1436 vec![*cspan, *aspan],
1437 "functions cannot be both `const` and `async`",
1439 .span_label(*cspan, "`const` because of this")
1440 .span_label(*aspan, "`async` because of this")
1441 .span_label(span, "") // Point at the fn header.
1445 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1446 self.check_late_bound_lifetime_defs(generic_params);
1452 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1458 self.maybe_lint_missing_abi(*sig_span, id);
1461 // Functions without bodies cannot have patterns.
1462 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1463 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1464 let (code, msg, label) = match ctxt {
1465 FnCtxt::Foreign => (
1467 "patterns aren't allowed in foreign function declarations",
1468 "pattern not allowed in foreign function",
1472 "patterns aren't allowed in functions without bodies",
1473 "pattern not allowed in function without body",
1476 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1477 if let Some(ident) = ident {
1478 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1479 self.lint_buffer.buffer_lint_with_diagnostic(
1480 PATTERNS_IN_FNS_WITHOUT_BODY,
1489 .struct_span_err(span, msg)
1490 .span_label(span, label)
1497 let tilde_const_allowed =
1498 matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1499 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1501 let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
1503 self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
1506 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1507 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1508 self.check_nomangle_item_asciionly(item.ident, item.span);
1511 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1512 self.check_defaultness(item.span, item.kind.defaultness());
1515 if ctxt == AssocCtxt::Impl {
1517 AssocItemKind::Const(_, _, body) => {
1519 self.session.emit_err(AssocConstWithoutBody {
1521 replace_span: self.ending_semi_or_hi(item.span),
1525 AssocItemKind::Fn(box Fn { body, .. }) => {
1527 self.session.emit_err(AssocFnWithoutBody {
1529 replace_span: self.ending_semi_or_hi(item.span),
1533 AssocItemKind::Type(box TyAlias {
1536 where_predicates_split,
1542 self.session.emit_err(AssocTypeWithoutBody {
1544 replace_span: self.ending_semi_or_hi(item.span),
1547 self.check_type_no_bounds(bounds, "`impl`s");
1549 self.check_gat_where(
1551 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1560 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1561 self.invalid_visibility(&item.vis, None);
1562 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1563 self.check_trait_fn_not_const(sig.header.constness);
1567 if let AssocItemKind::Const(..) = item.kind {
1568 self.check_item_named(item.ident, "const");
1572 AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. })
1573 if ctxt == AssocCtxt::Trait =>
1575 self.visit_vis(&item.vis);
1576 self.visit_ident(item.ident);
1577 walk_list!(self, visit_attribute, &item.attrs);
1578 self.with_tilde_const_allowed(|this| {
1579 this.visit_generics(generics);
1580 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1582 walk_list!(self, visit_ty, ty);
1584 AssocItemKind::Fn(box Fn { sig, generics, body, .. })
1585 if self.in_const_trait_impl
1586 || ctxt == AssocCtxt::Trait
1587 || matches!(sig.header.constness, Const::Yes(_)) =>
1589 self.visit_vis(&item.vis);
1590 self.visit_ident(item.ident);
1591 let kind = FnKind::Fn(
1592 FnCtxt::Assoc(ctxt),
1599 self.visit_fn(kind, item.span, item.id);
1602 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1607 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1608 /// like it's setting an associated type, provide an appropriate suggestion.
1609 fn deny_equality_constraints(
1610 this: &mut AstValidator<'_>,
1611 predicate: &WhereEqPredicate,
1612 generics: &Generics,
1614 let mut err = this.err_handler().struct_span_err(
1616 "equality constraints are not yet supported in `where` clauses",
1618 err.span_label(predicate.span, "not supported");
1620 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1621 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1622 if let TyKind::Path(None, path) = &qself.ty.kind {
1623 match &path.segments[..] {
1624 [PathSegment { ident, args: None, .. }] => {
1625 for param in &generics.params {
1626 if param.ident == *ident {
1628 match &full_path.segments[qself.position..] {
1629 [PathSegment { ident, args, .. }] => {
1630 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1631 let mut assoc_path = full_path.clone();
1632 // Remove `Bar` from `Foo::Bar`.
1633 assoc_path.segments.pop();
1634 let len = assoc_path.segments.len() - 1;
1635 let gen_args = args.as_deref().cloned();
1636 // Build `<Bar = RhsTy>`.
1637 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1638 id: rustc_ast::node_id::DUMMY_NODE_ID,
1641 kind: AssocConstraintKind::Equality {
1642 term: predicate.rhs_ty.clone().into(),
1646 // Add `<Bar = RhsTy>` to `Foo`.
1647 match &mut assoc_path.segments[len].args {
1648 Some(args) => match args.deref_mut() {
1649 GenericArgs::Parenthesized(_) => continue,
1650 GenericArgs::AngleBracketed(args) => {
1651 args.args.push(arg);
1655 *empty_args = AngleBracketedArgs {
1662 err.span_suggestion_verbose(
1665 "if `{}` is an associated type you're trying to set, \
1666 use the associated type binding syntax",
1672 pprust::path_to_string(&assoc_path)
1674 Applicability::MaybeIncorrect,
1686 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1687 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1688 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1689 for param in &generics.params {
1690 if param.ident == potential_param.ident {
1691 for bound in ¶m.bounds {
1692 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1694 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1695 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1696 potential_assoc.ident,
1698 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1699 let (args, span) = match &trait_segment.args {
1700 Some(args) => match args.deref() {
1701 ast::GenericArgs::AngleBracketed(args) => {
1702 let Some(arg) = args.args.last() else {
1706 format!(", {} = {}", assoc, ty),
1707 arg.span().shrink_to_hi(),
1713 format!("<{} = {}>", assoc, ty),
1714 trait_segment.span().shrink_to_hi(),
1717 err.multipart_suggestion(
1719 "if `{}::{}` is an associated type you're trying to set, \
1720 use the associated type binding syntax",
1721 trait_segment.ident, potential_assoc.ident,
1723 vec![(span, args), (predicate.span, String::new())],
1724 Applicability::MaybeIncorrect,
1734 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1739 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1740 let mut validator = AstValidator {
1743 in_trait_impl: false,
1744 in_const_trait_impl: false,
1745 has_proc_macro_decls: false,
1746 outer_impl_trait: None,
1747 disallow_tilde_const: None,
1748 is_impl_trait_banned: false,
1749 is_assoc_ty_bound_banned: false,
1750 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1753 visit::walk_crate(&mut validator, krate);
1755 validator.has_proc_macro_decls
1758 /// Used to forbid `let` expressions in certain syntactic locations.
1759 #[derive(Clone, Copy, Subdiagnostic)]
1760 pub(crate) enum ForbiddenLetReason {
1761 /// `let` is not valid and the source environment is not important
1763 /// A let chain with the `||` operator
1764 #[note(not_supported_or)]
1765 NotSupportedOr(#[primary_span] Span),
1766 /// A let chain with invalid parentheses
1768 /// For example, `let 1 = 1 && (expr && expr)` is allowed
1769 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1770 #[note(not_supported_parentheses)]
1771 NotSupportedParentheses(#[primary_span] Span),