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 return; // Avoid visiting again.
1056 ItemKind::Impl(box Impl {
1066 let error = |annotation_span, annotation| {
1067 let mut err = self.err_handler().struct_span_err(
1069 &format!("inherent impls cannot be {}", annotation),
1071 err.span_label(annotation_span, &format!("{} because of this", annotation));
1072 err.span_label(self_ty.span, "inherent impl for this type");
1076 self.invalid_visibility(
1078 Some(InvalidVisibilityNote::IndividualImplItems),
1080 if let Unsafe::Yes(span) = unsafety {
1081 error(span, "unsafe").code(error_code!(E0197)).emit();
1083 if let ImplPolarity::Negative(span) = polarity {
1084 error(span, "negative").emit();
1086 if let Defaultness::Default(def_span) = defaultness {
1087 error(def_span, "`default`")
1088 .note("only trait implementations may be annotated with `default`")
1091 if let Const::Yes(span) = constness {
1092 error(span, "`const`")
1093 .note("only trait implementations may be annotated with `const`")
1097 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1098 self.check_defaultness(item.span, defaultness);
1101 self.session.emit_err(FnWithoutBody {
1103 replace_span: self.ending_semi_or_hi(item.span),
1104 extern_block_suggestion: match sig.header.ext {
1105 Extern::None => None,
1106 Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1108 end_span: item.span.shrink_to_hi(),
1111 Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1113 end_span: item.span.shrink_to_hi(),
1114 abi: Some(abi.symbol_unescaped),
1120 self.visit_vis(&item.vis);
1121 self.visit_ident(item.ident);
1123 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1124 self.visit_fn(kind, item.span, item.id);
1125 walk_list!(self, visit_attribute, &item.attrs);
1126 return; // Avoid visiting again.
1128 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1129 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1130 self.invalid_visibility(
1132 Some(InvalidVisibilityNote::IndividualForeignItems),
1134 if let Unsafe::Yes(span) = unsafety {
1135 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1138 self.maybe_lint_missing_abi(item.span, item.id);
1140 visit::walk_item(self, item);
1141 self.extern_mod = old_item;
1142 return; // Avoid visiting again.
1144 ItemKind::Enum(ref def, _) => {
1145 for variant in &def.variants {
1146 self.invalid_visibility(&variant.vis, None);
1147 for field in variant.data.fields() {
1148 self.invalid_visibility(&field.vis, None);
1152 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1153 if is_auto == IsAuto::Yes {
1154 // Auto traits cannot have generics, super traits nor contain items.
1155 self.deny_generic_params(generics, item.ident.span);
1156 self.deny_super_traits(bounds, item.ident.span);
1157 self.deny_where_clause(&generics.where_clause, item.ident.span);
1158 self.deny_items(items, item.ident.span);
1161 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1162 // context for the supertraits.
1163 self.visit_vis(&item.vis);
1164 self.visit_ident(item.ident);
1165 self.visit_generics(generics);
1166 self.with_tilde_const_allowed(|this| {
1167 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1169 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1170 walk_list!(self, visit_attribute, &item.attrs);
1173 ItemKind::Mod(unsafety, ref mod_kind) => {
1174 if let Unsafe::Yes(span) = unsafety {
1175 self.err_handler().span_err(span, "module cannot be declared unsafe");
1177 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1178 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1179 && !self.session.contains_name(&item.attrs, sym::path)
1181 self.check_mod_file_item_asciionly(item.ident);
1184 ItemKind::Union(ref vdata, ..) => {
1185 if vdata.fields().is_empty() {
1186 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1189 ItemKind::Const(def, .., None) => {
1190 self.check_defaultness(item.span, def);
1191 self.session.emit_err(ConstWithoutBody {
1193 replace_span: self.ending_semi_or_hi(item.span),
1196 ItemKind::Static(.., None) => {
1197 self.session.emit_err(StaticWithoutBody {
1199 replace_span: self.ending_semi_or_hi(item.span),
1202 ItemKind::TyAlias(box TyAlias {
1209 self.check_defaultness(item.span, defaultness);
1211 self.session.emit_err(TyAliasWithoutBody {
1213 replace_span: self.ending_semi_or_hi(item.span),
1216 self.check_type_no_bounds(bounds, "this context");
1217 if where_clauses.1.0 {
1218 let mut err = self.err_handler().struct_span_err(
1220 "where clauses are not allowed after the type for type aliases",
1223 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1231 visit::walk_item(self, item);
1234 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1236 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1237 self.check_defaultness(fi.span, *defaultness);
1238 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1239 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1240 self.check_foreign_item_ascii_only(fi.ident);
1242 ForeignItemKind::TyAlias(box TyAlias {
1250 self.check_defaultness(fi.span, *defaultness);
1251 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1252 self.check_type_no_bounds(bounds, "`extern` blocks");
1253 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1254 self.check_foreign_item_ascii_only(fi.ident);
1256 ForeignItemKind::Static(_, _, body) => {
1257 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1258 self.check_foreign_item_ascii_only(fi.ident);
1260 ForeignItemKind::MacCall(..) => {}
1263 visit::walk_foreign_item(self, fi)
1266 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1267 fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
1268 match *generic_args {
1269 GenericArgs::AngleBracketed(ref data) => {
1270 self.check_generic_args_before_constraints(data);
1272 for arg in &data.args {
1274 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1275 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1276 // are allowed to contain nested `impl Trait`.
1277 AngleBracketedArg::Constraint(constraint) => {
1278 self.with_impl_trait(None, |this| {
1279 this.visit_assoc_constraint_from_generic_args(constraint);
1285 GenericArgs::Parenthesized(ref data) => {
1286 walk_list!(self, visit_ty, &data.inputs);
1287 if let FnRetTy::Ty(ty) = &data.output {
1288 // `-> Foo` syntax is essentially an associated type binding,
1289 // so it is also allowed to contain nested `impl Trait`.
1290 self.with_impl_trait(None, |this| this.visit_ty(ty));
1296 fn visit_generics(&mut self, generics: &'a Generics) {
1297 let mut prev_param_default = None;
1298 for param in &generics.params {
1300 GenericParamKind::Lifetime => (),
1301 GenericParamKind::Type { default: Some(_), .. }
1302 | GenericParamKind::Const { default: Some(_), .. } => {
1303 prev_param_default = Some(param.ident.span);
1305 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1306 if let Some(span) = prev_param_default {
1307 let mut err = self.err_handler().struct_span_err(
1309 "generic parameters with a default must be trailing",
1318 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1320 for predicate in &generics.where_clause.predicates {
1321 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1322 deny_equality_constraints(self, predicate, generics);
1325 walk_list!(self, visit_generic_param, &generics.params);
1326 for predicate in &generics.where_clause.predicates {
1328 WherePredicate::BoundPredicate(bound_pred) => {
1329 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1330 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1332 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1333 // binder and thus we only allow a single level of quantification. However,
1334 // the syntax of Rust permits quantification in two places in where clauses,
1335 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1336 // defined, then error.
1337 if !bound_pred.bound_generic_params.is_empty() {
1338 for bound in &bound_pred.bounds {
1340 GenericBound::Trait(t, _) => {
1341 if !t.bound_generic_params.is_empty() {
1346 "nested quantification of lifetimes"
1351 GenericBound::Outlives(_) => {}
1358 self.visit_where_predicate(predicate);
1362 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1363 if let GenericParamKind::Lifetime { .. } = param.kind {
1364 self.check_lifetime(param.ident);
1366 visit::walk_generic_param(self, param);
1369 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1370 if let GenericBound::Trait(ref poly, modify) = *bound {
1371 match (ctxt, modify) {
1372 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1375 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1376 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1377 err.note(&format!("traits are `?{}` by default", path_str));
1380 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1381 let mut err = self.err_handler().struct_span_err(
1383 "`?Trait` is not permitted in trait object types",
1387 (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
1388 let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
1390 DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
1391 DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
1392 DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
1393 DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
1397 (_, TraitBoundModifier::MaybeConstMaybe) => {
1399 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1405 visit::walk_param_bound(self, bound)
1408 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1409 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1410 visit::walk_poly_trait_ref(self, t);
1413 fn visit_variant_data(&mut self, s: &'a VariantData) {
1414 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1417 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1418 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1421 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1422 // Only associated `fn`s can have `self` parameters.
1423 let self_semantic = match fk.ctxt() {
1424 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1425 _ => SelfSemantic::No,
1427 self.check_fn_decl(fk.decl(), self_semantic);
1429 self.check_c_variadic_type(fk);
1431 // Functions cannot both be `const async`
1432 if let Some(FnHeader {
1433 constness: Const::Yes(cspan),
1434 asyncness: Async::Yes { span: aspan, .. },
1440 vec![*cspan, *aspan],
1441 "functions cannot be both `const` and `async`",
1443 .span_label(*cspan, "`const` because of this")
1444 .span_label(*aspan, "`async` because of this")
1445 .span_label(span, "") // Point at the fn header.
1449 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1450 self.check_late_bound_lifetime_defs(generic_params);
1456 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1462 self.maybe_lint_missing_abi(*sig_span, id);
1465 // Functions without bodies cannot have patterns.
1466 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1467 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1468 let (code, msg, label) = match ctxt {
1469 FnCtxt::Foreign => (
1471 "patterns aren't allowed in foreign function declarations",
1472 "pattern not allowed in foreign function",
1476 "patterns aren't allowed in functions without bodies",
1477 "pattern not allowed in function without body",
1480 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1481 if let Some(ident) = ident {
1482 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1483 self.lint_buffer.buffer_lint_with_diagnostic(
1484 PATTERNS_IN_FNS_WITHOUT_BODY,
1493 .struct_span_err(span, msg)
1494 .span_label(span, label)
1501 let tilde_const_allowed =
1502 matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1503 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1505 let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
1507 self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
1510 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1511 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1512 self.check_nomangle_item_asciionly(item.ident, item.span);
1515 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1516 self.check_defaultness(item.span, item.kind.defaultness());
1519 if ctxt == AssocCtxt::Impl {
1521 AssocItemKind::Const(_, _, body) => {
1523 self.session.emit_err(AssocConstWithoutBody {
1525 replace_span: self.ending_semi_or_hi(item.span),
1529 AssocItemKind::Fn(box Fn { body, .. }) => {
1531 self.session.emit_err(AssocFnWithoutBody {
1533 replace_span: self.ending_semi_or_hi(item.span),
1537 AssocItemKind::Type(box TyAlias {
1540 where_predicates_split,
1546 self.session.emit_err(AssocTypeWithoutBody {
1548 replace_span: self.ending_semi_or_hi(item.span),
1551 self.check_type_no_bounds(bounds, "`impl`s");
1553 self.check_gat_where(
1555 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1564 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1565 self.invalid_visibility(&item.vis, None);
1566 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1567 self.check_trait_fn_not_const(sig.header.constness);
1571 if let AssocItemKind::Const(..) = item.kind {
1572 self.check_item_named(item.ident, "const");
1576 AssocItemKind::Type(box TyAlias { ref generics, ref bounds, ref ty, .. })
1577 if ctxt == AssocCtxt::Trait =>
1579 self.visit_vis(&item.vis);
1580 self.visit_ident(item.ident);
1581 walk_list!(self, visit_attribute, &item.attrs);
1582 self.with_tilde_const_allowed(|this| {
1583 this.visit_generics(generics);
1584 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1586 walk_list!(self, visit_ty, ty);
1588 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1589 if self.in_const_trait_impl
1590 || ctxt == AssocCtxt::Trait
1591 || matches!(sig.header.constness, Const::Yes(_)) =>
1593 self.visit_vis(&item.vis);
1594 self.visit_ident(item.ident);
1595 let kind = FnKind::Fn(
1596 FnCtxt::Assoc(ctxt),
1603 self.visit_fn(kind, item.span, item.id);
1606 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1611 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1612 /// like it's setting an associated type, provide an appropriate suggestion.
1613 fn deny_equality_constraints(
1614 this: &mut AstValidator<'_>,
1615 predicate: &WhereEqPredicate,
1616 generics: &Generics,
1618 let mut err = this.err_handler().struct_span_err(
1620 "equality constraints are not yet supported in `where` clauses",
1622 err.span_label(predicate.span, "not supported");
1624 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1625 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1626 if let TyKind::Path(None, path) = &qself.ty.kind {
1627 match &path.segments[..] {
1628 [PathSegment { ident, args: None, .. }] => {
1629 for param in &generics.params {
1630 if param.ident == *ident {
1632 match &full_path.segments[qself.position..] {
1633 [PathSegment { ident, args, .. }] => {
1634 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1635 let mut assoc_path = full_path.clone();
1636 // Remove `Bar` from `Foo::Bar`.
1637 assoc_path.segments.pop();
1638 let len = assoc_path.segments.len() - 1;
1639 let gen_args = args.as_ref().map(|p| (**p).clone());
1640 // Build `<Bar = RhsTy>`.
1641 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1642 id: rustc_ast::node_id::DUMMY_NODE_ID,
1645 kind: AssocConstraintKind::Equality {
1646 term: predicate.rhs_ty.clone().into(),
1650 // Add `<Bar = RhsTy>` to `Foo`.
1651 match &mut assoc_path.segments[len].args {
1652 Some(args) => match args.deref_mut() {
1653 GenericArgs::Parenthesized(_) => continue,
1654 GenericArgs::AngleBracketed(args) => {
1655 args.args.push(arg);
1659 *empty_args = AngleBracketedArgs {
1666 err.span_suggestion_verbose(
1669 "if `{}` is an associated type you're trying to set, \
1670 use the associated type binding syntax",
1676 pprust::path_to_string(&assoc_path)
1678 Applicability::MaybeIncorrect,
1690 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1691 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1692 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1693 for param in &generics.params {
1694 if param.ident == potential_param.ident {
1695 for bound in ¶m.bounds {
1696 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1698 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1699 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1700 potential_assoc.ident,
1702 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1703 let (args, span) = match &trait_segment.args {
1704 Some(args) => match args.deref() {
1705 ast::GenericArgs::AngleBracketed(args) => {
1706 let Some(arg) = args.args.last() else {
1710 format!(", {} = {}", assoc, ty),
1711 arg.span().shrink_to_hi(),
1717 format!("<{} = {}>", assoc, ty),
1718 trait_segment.span().shrink_to_hi(),
1721 err.multipart_suggestion(
1723 "if `{}::{}` is an associated type you're trying to set, \
1724 use the associated type binding syntax",
1725 trait_segment.ident, potential_assoc.ident,
1727 vec![(span, args), (predicate.span, String::new())],
1728 Applicability::MaybeIncorrect,
1738 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1743 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1744 let mut validator = AstValidator {
1747 in_trait_impl: false,
1748 in_const_trait_impl: false,
1749 has_proc_macro_decls: false,
1750 outer_impl_trait: None,
1751 disallow_tilde_const: None,
1752 is_impl_trait_banned: false,
1753 is_assoc_ty_bound_banned: false,
1754 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1757 visit::walk_crate(&mut validator, krate);
1759 validator.has_proc_macro_decls
1762 /// Used to forbid `let` expressions in certain syntactic locations.
1763 #[derive(Clone, Copy, Subdiagnostic)]
1764 pub(crate) enum ForbiddenLetReason {
1765 /// `let` is not valid and the source environment is not important
1767 /// A let chain with the `||` operator
1768 #[note(not_supported_or)]
1769 NotSupportedOr(#[primary_span] Span),
1770 /// A let chain with invalid parentheses
1772 /// For example, `let 1 = 1 && (expr && expr)` is allowed
1773 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1774 #[note(not_supported_parentheses)]
1775 NotSupportedParentheses(#[primary_span] Span),