1 // Validate AST before lowering it to HIR.
3 // This pass is supposed to catch things that fit into AST data structures,
4 // but not permitted by the language. It runs after expansion when AST is frozen,
5 // so it can check for erroneous constructions produced by syntax extensions.
6 // This pass is supposed to perform only simple checks not requiring name resolution
7 // or type checking or some other kind of complex analysis.
9 use itertools::{Either, Itertools};
10 use rustc_ast::ptr::P;
11 use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
12 use rustc_ast::walk_list;
14 use rustc_ast_pretty::pprust::{self, State};
15 use rustc_data_structures::fx::FxHashMap;
16 use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
17 use rustc_parse::validate_attr;
18 use rustc_session::lint::builtin::{
19 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
21 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
22 use rustc_session::Session;
23 use rustc_span::source_map::Spanned;
24 use rustc_span::symbol::{kw, sym, Ident};
26 use rustc_target::spec::abi;
28 use std::ops::{Deref, DerefMut};
32 const MORE_EXTERN: &str =
33 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
35 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
41 struct AstValidator<'a> {
44 /// The span of the `extern` in an `extern { ... }` block, if any.
45 extern_mod: Option<&'a Item>,
47 /// Are we inside a trait impl?
50 in_const_trait_impl: bool,
52 has_proc_macro_decls: bool,
54 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
55 /// Nested `impl Trait` _is_ allowed in associated type position,
56 /// e.g., `impl Iterator<Item = impl Debug>`.
57 outer_impl_trait: Option<Span>,
59 is_tilde_const_allowed: bool,
61 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
62 /// or `Foo::Bar<impl Trait>`
63 is_impl_trait_banned: bool,
65 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
66 /// certain positions.
67 is_assoc_ty_bound_banned: bool,
69 /// See [ForbiddenLetReason]
70 forbidden_let_reason: Option<ForbiddenLetReason>,
72 lint_buffer: &'a mut LintBuffer,
75 impl<'a> AstValidator<'a> {
76 fn with_in_trait_impl(
79 constness: Option<Const>,
80 f: impl FnOnce(&mut Self),
82 let old = mem::replace(&mut self.in_trait_impl, is_in);
84 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
86 self.in_trait_impl = old;
87 self.in_const_trait_impl = old_const;
90 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
91 let old = mem::replace(&mut self.is_impl_trait_banned, true);
93 self.is_impl_trait_banned = old;
96 fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
97 let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
99 self.is_tilde_const_allowed = old;
102 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
103 self.with_tilde_const(true, f)
106 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
107 self.with_tilde_const(false, f)
110 fn with_let_management(
112 forbidden_let_reason: Option<ForbiddenLetReason>,
113 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
115 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
117 self.forbidden_let_reason = old;
120 /// Emits an error banning the `let` expression provided in the given location.
121 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
122 let sess = &self.session;
123 if sess.opts.unstable_features.is_nightly_build() {
124 let err = "`let` expressions are not supported here";
125 let mut diag = sess.struct_span_err(expr.span, err);
126 diag.note("only supported directly in conditions of `if` and `while` expressions");
127 match forbidden_let_reason {
128 ForbiddenLetReason::GenericForbidden => {}
129 ForbiddenLetReason::NotSupportedOr(span) => {
132 "`||` operators are not supported in let chain expressions",
135 ForbiddenLetReason::NotSupportedParentheses(span) => {
138 "`let`s wrapped in parentheses are not supported in a context with let \
145 sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
146 .note("variable declaration using `let` is a statement")
154 before_predicates: &[WherePredicate],
155 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
157 if !before_predicates.is_empty() {
158 let mut state = State::new();
159 if !where_clauses.1.0 {
161 state.word_space("where");
163 state.word_space(",");
165 let mut first = true;
166 for p in before_predicates.iter() {
168 state.word_space(",");
171 state.print_where_predicate(p);
173 let suggestion = state.s.eof();
174 self.lint_buffer.buffer_lint_with_diagnostic(
175 DEPRECATED_WHERE_CLAUSE_LOCATION,
178 fluent::ast_passes::deprecated_where_clause_location,
179 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
180 where_clauses.1.1.shrink_to_hi(),
187 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
188 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
190 self.is_assoc_ty_bound_banned = old;
193 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
194 let old = mem::replace(&mut self.outer_impl_trait, outer);
196 self.with_banned_tilde_const(f);
200 self.outer_impl_trait = old;
203 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
204 match constraint.kind {
205 AssocConstraintKind::Equality { .. } => {}
206 AssocConstraintKind::Bound { .. } => {
207 if self.is_assoc_ty_bound_banned {
208 self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
212 self.visit_assoc_constraint(constraint);
215 // Mirrors `visit::walk_ty`, but tracks relevant state.
216 fn walk_ty(&mut self, t: &'a Ty) {
218 TyKind::ImplTrait(..) => {
219 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
221 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
222 TyKind::Path(ref qself, ref path) => {
224 // - `Option<impl Trait>`
225 // - `option::Option<impl Trait>`
226 // - `option::Option<T>::Foo<impl Trait>
229 // - `<impl Trait>::Foo`
230 // - `option::Option<impl Trait>::Foo`.
232 // To implement this, we disallow `impl Trait` from `qself`
233 // (for cases like `<impl Trait>::Foo>`)
234 // but we allow `impl Trait` in `GenericArgs`
235 // iff there are no more PathSegments.
236 if let Some(ref qself) = *qself {
237 // `impl Trait` in `qself` is always illegal
238 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
241 // Note that there should be a call to visit_path here,
242 // so if any logic is added to process `Path`s a call to it should be
243 // added both in visit_path and here. This code mirrors visit::walk_path.
244 for (i, segment) in path.segments.iter().enumerate() {
245 // Allow `impl Trait` iff we're on the final path segment
246 if i == path.segments.len() - 1 {
247 self.visit_path_segment(path.span, segment);
249 self.with_banned_impl_trait(|this| {
250 this.visit_path_segment(path.span, segment)
255 _ => visit::walk_ty(self, t),
259 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
260 if let Some(ident) = field.ident {
261 if ident.name == kw::Underscore {
262 self.visit_vis(&field.vis);
263 self.visit_ident(ident);
264 self.visit_ty_common(&field.ty);
265 self.walk_ty(&field.ty);
266 walk_list!(self, visit_attribute, &field.attrs);
270 self.visit_field_def(field);
273 fn err_handler(&self) -> &rustc_errors::Handler {
274 &self.session.diagnostic()
277 fn check_lifetime(&self, ident: Ident) {
278 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
279 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
280 self.session.emit_err(KeywordLifetime { span: ident.span });
284 fn check_label(&self, ident: Ident) {
285 if ident.without_first_quote().is_reserved() {
286 self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
290 fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
291 if let VisibilityKind::Inherited = vis.kind {
295 self.session.emit_err(InvalidVisibility {
297 implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
302 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
303 for Param { pat, .. } in &decl.inputs {
305 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
306 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
307 report_err(pat.span, Some(ident), true)
309 _ => report_err(pat.span, None, false),
314 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
315 if let Async::Yes { span, .. } = asyncness {
316 self.session.emit_err(TraitFnAsync { fn_span, span });
320 fn check_trait_fn_not_const(&self, constness: Const) {
321 if let Const::Yes(span) = constness {
322 self.session.emit_err(TraitFnConst { span });
326 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
327 // Check only lifetime parameters are present and that the lifetime
328 // parameters that are present have no bounds.
329 let non_lt_param_spans: Vec<_> = params
331 .filter_map(|param| match param.kind {
332 GenericParamKind::Lifetime { .. } => {
333 if !param.bounds.is_empty() {
334 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
335 self.session.emit_err(ForbiddenLifetimeBound { spans });
339 _ => Some(param.ident.span),
342 if !non_lt_param_spans.is_empty() {
343 self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
347 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
348 self.check_decl_num_args(fn_decl);
349 self.check_decl_cvaradic_pos(fn_decl);
350 self.check_decl_attrs(fn_decl);
351 self.check_decl_self_param(fn_decl, self_semantic);
354 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
355 /// Error is fatal to prevent errors during typechecking
356 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
357 let max_num_args: usize = u16::MAX.into();
358 if fn_decl.inputs.len() > max_num_args {
359 let Param { span, .. } = fn_decl.inputs[0];
360 self.session.emit_fatal(FnParamTooMany { span, max_num_args });
364 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
365 match &*fn_decl.inputs {
366 [Param { ty, span, .. }] => {
367 if let TyKind::CVarArgs = ty.kind {
368 self.session.emit_err(FnParamCVarArgsOnly { span: *span });
372 for Param { ty, span, .. } in ps {
373 if let TyKind::CVarArgs = ty.kind {
374 self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
382 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
386 .flat_map(|i| i.attrs.as_ref())
397 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
400 if attr.is_doc_comment() {
401 self.session.emit_err(FnParamDocComment { span: attr.span });
403 self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
408 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
409 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
411 self.session.emit_err(FnParamForbiddenSelf { span: param.span });
416 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
417 if let Defaultness::Default(def_span) = defaultness {
418 let span = self.session.source_map().guess_head_span(span);
419 self.session.emit_err(ForbiddenDefault { span, def_span });
423 /// If `sp` ends with a semicolon, returns it as a `Span`
424 /// Otherwise, returns `sp.shrink_to_hi()`
425 fn ending_semi_or_hi(&self, sp: Span) -> Span {
426 let source_map = self.session.source_map();
427 let end = source_map.end_point(sp);
429 if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
436 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
437 let span = match bounds {
440 [b0, .., bl] => b0.span().to(bl.span()),
443 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
447 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
448 let cannot_have = |span, descr, remove_descr| {
452 &format!("`type`s inside `extern` blocks cannot have {}", descr),
456 &format!("remove the {}", remove_descr),
458 Applicability::MaybeIncorrect,
460 .span_label(self.current_extern_span(), "`extern` block begins here")
465 if !generics.params.is_empty() {
466 cannot_have(generics.span, "generic parameters", "generic parameters");
469 if !generics.where_clause.predicates.is_empty() {
470 cannot_have(where_span, "`where` clauses", "`where` clause");
474 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
475 let Some(body) = body else {
479 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
480 .span_label(ident.span, "cannot have a body")
481 .span_label(body, "the invalid body")
483 self.current_extern_span(),
485 "`extern` blocks define existing foreign {0}s and {0}s \
486 inside of them cannot have a body",
494 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
495 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
496 let Some(body) = body else {
500 .struct_span_err(ident.span, "incorrect function inside `extern` block")
501 .span_label(ident.span, "cannot have a body")
504 "remove the invalid body",
506 Applicability::MaybeIncorrect,
509 "you might have meant to write a function accessible through FFI, \
510 which can be done by writing `extern fn` outside of the `extern` block",
513 self.current_extern_span(),
514 "`extern` blocks define existing foreign functions and functions \
515 inside of them cannot have a body",
521 fn current_extern_span(&self) -> Span {
522 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
525 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
526 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
527 if header.has_qualifiers() {
529 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
530 .span_label(self.current_extern_span(), "in this `extern` block")
531 .span_suggestion_verbose(
532 span.until(ident.span.shrink_to_lo()),
533 "remove the qualifiers",
535 Applicability::MaybeIncorrect,
541 /// An item in `extern { ... }` cannot use non-ascii identifier.
542 fn check_foreign_item_ascii_only(&self, ident: Ident) {
543 if !ident.as_str().is_ascii() {
548 "items in `extern` blocks cannot use non-ascii identifiers",
550 .span_label(self.current_extern_span(), "in this `extern` block")
552 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
559 /// Reject C-variadic type unless the function is foreign,
560 /// or free and `unsafe extern "C"` semantically.
561 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
562 match (fk.ctxt(), fk.header()) {
563 (Some(FnCtxt::Foreign), _) => return,
564 (Some(FnCtxt::Free), Some(header)) => match header.ext {
565 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
566 | Extern::Implicit(_)
567 if matches!(header.unsafety, Unsafe::Yes(_)) =>
576 for Param { ty, span, .. } in &fk.decl().inputs {
577 if let TyKind::CVarArgs = ty.kind {
581 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
588 fn check_item_named(&self, ident: Ident, kind: &str) {
589 if ident.name != kw::Underscore {
593 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
594 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
598 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
599 if ident.name.as_str().is_ascii() {
602 let head_span = self.session.source_map().guess_head_span(item_span);
607 "`#[no_mangle]` requires ASCII identifier"
612 fn check_mod_file_item_asciionly(&self, ident: Ident) {
613 if ident.name.as_str().is_ascii() {
620 "trying to load file for module `{}` with non-ascii identifier name",
623 .help("consider using `#[path]` attribute to specify filesystem path")
627 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
628 if !generics.params.is_empty() {
633 "auto traits cannot have generic parameters"
635 .span_label(ident_span, "auto trait cannot have generic parameters")
638 "remove the parameters",
640 Applicability::MachineApplicable,
646 fn emit_e0568(&self, span: Span, ident_span: Span) {
651 "auto traits cannot have super traits or lifetime bounds"
653 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
656 "remove the super traits or lifetime bounds",
658 Applicability::MachineApplicable,
663 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
664 if let [.., last] = &bounds[..] {
665 let span = ident_span.shrink_to_hi().to(last.span());
666 self.emit_e0568(span, ident_span);
670 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
671 if !where_clause.predicates.is_empty() {
672 self.emit_e0568(where_clause.span, ident_span);
676 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
677 if !trait_items.is_empty() {
678 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
679 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
684 "auto traits cannot have associated items"
688 "remove these associated items",
690 Applicability::MachineApplicable,
692 .span_label(ident_span, "auto trait cannot have associated items")
697 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
698 // Lifetimes always come first.
699 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
700 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
701 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
705 let args_sugg = data.args.iter().filter_map(|a| match a {
706 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
709 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
711 // Constraints always come last.
712 let constraint_sugg = data.args.iter().filter_map(|a| match a {
713 AngleBracketedArg::Arg(_) => None,
714 AngleBracketedArg::Constraint(c) => {
715 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
720 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
724 /// Enforce generic args coming before constraints in `<...>` of a path segment.
725 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
726 // Early exit in case it's partitioned as it should be.
727 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
730 // Find all generic argument coming after the first constraint...
731 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
732 data.args.iter().partition_map(|arg| match arg {
733 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
734 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
736 let args_len = arg_spans.len();
737 let constraint_len = constraint_spans.len();
738 // ...and then error:
742 "generic arguments must come before the first constraint",
744 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
746 *arg_spans.iter().last().unwrap(),
747 &format!("generic argument{}", pluralize!(args_len)),
749 .span_labels(constraint_spans, "")
750 .span_labels(arg_spans, "")
751 .span_suggestion_verbose(
754 "move the constraint{} after the generic argument{}",
755 pluralize!(constraint_len),
758 self.correct_generic_order_suggestion(&data),
759 Applicability::MachineApplicable,
764 fn visit_ty_common(&mut self, ty: &'a Ty) {
766 TyKind::BareFn(ref bfty) => {
767 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
768 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
773 "patterns aren't allowed in function pointer types"
777 self.check_late_bound_lifetime_defs(&bfty.generic_params);
778 if let Extern::Implicit(_) = bfty.ext {
779 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
780 self.maybe_lint_missing_abi(sig_span, ty.id);
783 TyKind::TraitObject(ref bounds, ..) => {
784 let mut any_lifetime_bounds = false;
785 for bound in bounds {
786 if let GenericBound::Outlives(ref lifetime) = *bound {
787 if any_lifetime_bounds {
792 "only a single explicit lifetime bound is permitted"
797 any_lifetime_bounds = true;
801 TyKind::ImplTrait(_, ref bounds) => {
802 if self.is_impl_trait_banned {
807 "`impl Trait` is not allowed in path parameters"
812 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
817 "nested `impl Trait` is not allowed"
819 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
820 .span_label(ty.span, "nested `impl Trait` here")
824 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
825 self.err_handler().span_err(ty.span, "at least one trait must be specified");
832 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
833 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
834 // call site which do not have a macro backtrace. See #61963.
835 let is_macro_callsite = self
838 .span_to_snippet(span)
839 .map(|snippet| snippet.starts_with("#["))
841 if !is_macro_callsite {
842 self.lint_buffer.buffer_lint_with_diagnostic(
846 "extern declarations without an explicit ABI are deprecated",
847 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
853 /// Checks that generic parameters are in the correct order,
854 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
855 fn validate_generic_param_order(
856 handler: &rustc_errors::Handler,
857 generics: &[GenericParam],
860 let mut max_param: Option<ParamKindOrd> = None;
861 let mut out_of_order = FxHashMap::default();
862 let mut param_idents = Vec::with_capacity(generics.len());
864 for (idx, param) in generics.iter().enumerate() {
865 let ident = param.ident;
866 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
867 let (ord_kind, ident) = match ¶m.kind {
868 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
869 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
870 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
871 let ty = pprust::ty_to_string(ty);
872 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
875 param_idents.push((kind, ord_kind, bounds, idx, ident));
877 Some(max_param) if max_param > ord_kind => {
878 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
881 Some(_) | None => max_param = Some(ord_kind),
885 if !out_of_order.is_empty() {
886 let mut ordered_params = "<".to_string();
887 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
888 let mut first = true;
889 for (kind, _, bounds, _, ident) in param_idents {
891 ordered_params += ", ";
893 ordered_params += &ident;
895 if !bounds.is_empty() {
896 ordered_params += ": ";
897 ordered_params += &pprust::bounds_to_string(&bounds);
901 GenericParamKind::Type { default: Some(default) } => {
902 ordered_params += " = ";
903 ordered_params += &pprust::ty_to_string(default);
905 GenericParamKind::Type { default: None } => (),
906 GenericParamKind::Lifetime => (),
907 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
908 ordered_params += " = ";
909 ordered_params += &pprust::expr_to_string(&*default.value);
911 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
916 ordered_params += ">";
918 for (param_ord, (max_param, spans)) in &out_of_order {
919 let mut err = handler.struct_span_err(
922 "{} parameters must be declared prior to {} parameters",
923 param_ord, max_param,
928 "reorder the parameters: lifetimes, then consts and types",
930 Applicability::MachineApplicable,
937 impl<'a> Visitor<'a> for AstValidator<'a> {
938 fn visit_attribute(&mut self, attr: &Attribute) {
939 validate_attr::check_meta(&self.session.parse_sess, attr);
942 fn visit_expr(&mut self, expr: &'a Expr) {
943 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
945 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
946 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
947 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
948 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
950 ExprKind::If(cond, then, opt_else) => {
951 this.visit_block(then);
952 walk_list!(this, visit_expr, opt_else);
953 this.with_let_management(None, |this, _| this.visit_expr(cond));
956 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
957 this.ban_let_expr(expr, elem);
959 ExprKind::Match(scrutinee, arms) => {
960 this.visit_expr(scrutinee);
962 this.visit_expr(&arm.body);
963 this.visit_pat(&arm.pat);
964 walk_list!(this, visit_attribute, &arm.attrs);
965 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
966 this.with_let_management(None, |this, _| {
967 this.visit_expr(guard_expr)
973 ExprKind::Paren(local_expr) => {
974 fn has_let_expr(expr: &Expr) -> bool {
976 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
977 ExprKind::Let(..) => true,
981 let local_reason = if has_let_expr(local_expr) {
982 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
987 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
989 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
990 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
993 ExprKind::While(cond, then, opt_label) => {
994 walk_list!(this, visit_label, opt_label);
995 this.visit_block(then);
996 this.with_let_management(None, |this, _| this.visit_expr(cond));
999 _ => visit::walk_expr(this, expr),
1004 fn visit_ty(&mut self, ty: &'a Ty) {
1005 self.visit_ty_common(ty);
1009 fn visit_label(&mut self, label: &'a Label) {
1010 self.check_label(label.ident);
1011 visit::walk_label(self, label);
1014 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
1015 self.check_lifetime(lifetime.ident);
1016 visit::walk_lifetime(self, lifetime);
1019 fn visit_field_def(&mut self, s: &'a FieldDef) {
1020 visit::walk_field_def(self, s)
1023 fn visit_item(&mut self, item: &'a Item) {
1024 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1025 self.has_proc_macro_decls = true;
1028 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1029 self.check_nomangle_item_asciionly(item.ident, item.span);
1033 ItemKind::Impl(box Impl {
1039 of_trait: Some(ref t),
1043 self.with_in_trait_impl(true, Some(constness), |this| {
1044 this.invalid_visibility(&item.vis, None);
1045 if let TyKind::Err = self_ty.kind {
1049 "`impl Trait for .. {}` is an obsolete syntax",
1051 .help("use `auto trait Trait {}` instead")
1054 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1059 "negative impls cannot be unsafe"
1061 .span_label(sp, "negative because of this")
1062 .span_label(span, "unsafe because of this")
1066 this.visit_vis(&item.vis);
1067 this.visit_ident(item.ident);
1068 if let Const::Yes(_) = constness {
1069 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1071 this.visit_generics(generics);
1073 this.visit_trait_ref(t);
1074 this.visit_ty(self_ty);
1076 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1078 return; // Avoid visiting again.
1080 ItemKind::Impl(box Impl {
1090 let error = |annotation_span, annotation| {
1091 let mut err = self.err_handler().struct_span_err(
1093 &format!("inherent impls cannot be {}", annotation),
1095 err.span_label(annotation_span, &format!("{} because of this", annotation));
1096 err.span_label(self_ty.span, "inherent impl for this type");
1100 self.invalid_visibility(
1102 Some(InvalidVisibilityNote::IndividualImplItems),
1104 if let Unsafe::Yes(span) = unsafety {
1105 error(span, "unsafe").code(error_code!(E0197)).emit();
1107 if let ImplPolarity::Negative(span) = polarity {
1108 error(span, "negative").emit();
1110 if let Defaultness::Default(def_span) = defaultness {
1111 error(def_span, "`default`")
1112 .note("only trait implementations may be annotated with `default`")
1115 if let Const::Yes(span) = constness {
1116 error(span, "`const`")
1117 .note("only trait implementations may be annotated with `const`")
1121 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1122 self.check_defaultness(item.span, defaultness);
1125 self.session.emit_err(FnWithoutBody {
1127 replace_span: self.ending_semi_or_hi(item.span),
1128 extern_block_suggestion: match sig.header.ext {
1129 Extern::None => None,
1130 Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1132 end_span: item.span.shrink_to_hi(),
1135 Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1137 end_span: item.span.shrink_to_hi(),
1138 abi: Some(abi.symbol_unescaped),
1144 self.visit_vis(&item.vis);
1145 self.visit_ident(item.ident);
1147 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1148 self.visit_fn(kind, item.span, item.id);
1149 walk_list!(self, visit_attribute, &item.attrs);
1150 return; // Avoid visiting again.
1152 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1153 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1154 self.invalid_visibility(
1156 Some(InvalidVisibilityNote::IndividualForeignItems),
1158 if let Unsafe::Yes(span) = unsafety {
1159 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1162 self.maybe_lint_missing_abi(item.span, item.id);
1164 visit::walk_item(self, item);
1165 self.extern_mod = old_item;
1166 return; // Avoid visiting again.
1168 ItemKind::Enum(ref def, _) => {
1169 for variant in &def.variants {
1170 self.invalid_visibility(&variant.vis, None);
1171 for field in variant.data.fields() {
1172 self.invalid_visibility(&field.vis, None);
1176 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1177 if is_auto == IsAuto::Yes {
1178 // Auto traits cannot have generics, super traits nor contain items.
1179 self.deny_generic_params(generics, item.ident.span);
1180 self.deny_super_traits(bounds, item.ident.span);
1181 self.deny_where_clause(&generics.where_clause, item.ident.span);
1182 self.deny_items(items, item.ident.span);
1185 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1186 // context for the supertraits.
1187 self.visit_vis(&item.vis);
1188 self.visit_ident(item.ident);
1189 self.visit_generics(generics);
1190 self.with_tilde_const_allowed(|this| {
1191 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1193 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1194 walk_list!(self, visit_attribute, &item.attrs);
1197 ItemKind::Mod(unsafety, ref mod_kind) => {
1198 if let Unsafe::Yes(span) = unsafety {
1199 self.err_handler().span_err(span, "module cannot be declared unsafe");
1201 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1202 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1203 && !self.session.contains_name(&item.attrs, sym::path)
1205 self.check_mod_file_item_asciionly(item.ident);
1208 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1209 // Duplicating the `Visitor` logic allows catching all cases
1210 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1212 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1213 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1214 // it uses `visit_ty_common`, which doesn't contain that specific check.
1215 VariantData::Struct(ref fields, ..) => {
1216 self.visit_vis(&item.vis);
1217 self.visit_ident(item.ident);
1218 self.visit_generics(generics);
1219 self.with_banned_assoc_ty_bound(|this| {
1220 walk_list!(this, visit_struct_field_def, fields);
1222 walk_list!(self, visit_attribute, &item.attrs);
1227 ItemKind::Union(ref vdata, ref generics) => {
1228 if vdata.fields().is_empty() {
1229 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1232 VariantData::Struct(ref fields, ..) => {
1233 self.visit_vis(&item.vis);
1234 self.visit_ident(item.ident);
1235 self.visit_generics(generics);
1236 self.with_banned_assoc_ty_bound(|this| {
1237 walk_list!(this, visit_struct_field_def, fields);
1239 walk_list!(self, visit_attribute, &item.attrs);
1245 ItemKind::Const(def, .., None) => {
1246 self.check_defaultness(item.span, def);
1247 self.session.emit_err(ConstWithoutBody {
1249 replace_span: self.ending_semi_or_hi(item.span),
1252 ItemKind::Static(.., None) => {
1253 self.session.emit_err(StaticWithoutBody {
1255 replace_span: self.ending_semi_or_hi(item.span),
1258 ItemKind::TyAlias(box TyAlias {
1265 self.check_defaultness(item.span, defaultness);
1267 self.session.emit_err(TyAliasWithoutBody {
1269 replace_span: self.ending_semi_or_hi(item.span),
1272 self.check_type_no_bounds(bounds, "this context");
1273 if where_clauses.1.0 {
1274 let mut err = self.err_handler().struct_span_err(
1276 "where clauses are not allowed after the type for type aliases",
1279 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1287 visit::walk_item(self, item);
1290 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1292 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1293 self.check_defaultness(fi.span, *defaultness);
1294 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1295 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1296 self.check_foreign_item_ascii_only(fi.ident);
1298 ForeignItemKind::TyAlias(box TyAlias {
1306 self.check_defaultness(fi.span, *defaultness);
1307 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1308 self.check_type_no_bounds(bounds, "`extern` blocks");
1309 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1310 self.check_foreign_item_ascii_only(fi.ident);
1312 ForeignItemKind::Static(_, _, body) => {
1313 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1314 self.check_foreign_item_ascii_only(fi.ident);
1316 ForeignItemKind::MacCall(..) => {}
1319 visit::walk_foreign_item(self, fi)
1322 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1323 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1324 match *generic_args {
1325 GenericArgs::AngleBracketed(ref data) => {
1326 self.check_generic_args_before_constraints(data);
1328 for arg in &data.args {
1330 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1331 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1332 // are allowed to contain nested `impl Trait`.
1333 AngleBracketedArg::Constraint(constraint) => {
1334 self.with_impl_trait(None, |this| {
1335 this.visit_assoc_constraint_from_generic_args(constraint);
1341 GenericArgs::Parenthesized(ref data) => {
1342 walk_list!(self, visit_ty, &data.inputs);
1343 if let FnRetTy::Ty(ty) = &data.output {
1344 // `-> Foo` syntax is essentially an associated type binding,
1345 // so it is also allowed to contain nested `impl Trait`.
1346 self.with_impl_trait(None, |this| this.visit_ty(ty));
1352 fn visit_generics(&mut self, generics: &'a Generics) {
1353 let mut prev_param_default = None;
1354 for param in &generics.params {
1356 GenericParamKind::Lifetime => (),
1357 GenericParamKind::Type { default: Some(_), .. }
1358 | GenericParamKind::Const { default: Some(_), .. } => {
1359 prev_param_default = Some(param.ident.span);
1361 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1362 if let Some(span) = prev_param_default {
1363 let mut err = self.err_handler().struct_span_err(
1365 "generic parameters with a default must be trailing",
1374 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1376 for predicate in &generics.where_clause.predicates {
1377 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1378 deny_equality_constraints(self, predicate, generics);
1381 walk_list!(self, visit_generic_param, &generics.params);
1382 for predicate in &generics.where_clause.predicates {
1384 WherePredicate::BoundPredicate(bound_pred) => {
1385 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1386 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1388 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1389 // binder and thus we only allow a single level of quantification. However,
1390 // the syntax of Rust permits quantification in two places in where clauses,
1391 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1392 // defined, then error.
1393 if !bound_pred.bound_generic_params.is_empty() {
1394 for bound in &bound_pred.bounds {
1396 GenericBound::Trait(t, _) => {
1397 if !t.bound_generic_params.is_empty() {
1402 "nested quantification of lifetimes"
1407 GenericBound::Outlives(_) => {}
1414 self.visit_where_predicate(predicate);
1418 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1419 if let GenericParamKind::Lifetime { .. } = param.kind {
1420 self.check_lifetime(param.ident);
1422 visit::walk_generic_param(self, param);
1425 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1426 if let GenericBound::Trait(ref poly, modify) = *bound {
1427 match (ctxt, modify) {
1428 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1431 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1432 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1433 err.note(&format!("traits are `?{}` by default", path_str));
1436 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1437 let mut err = self.err_handler().struct_span_err(
1439 "`?Trait` is not permitted in trait object types",
1443 (_, TraitBoundModifier::MaybeConst) => {
1444 if !self.is_tilde_const_allowed {
1446 .struct_span_err(bound.span(), "`~const` is not allowed here")
1447 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1451 (_, TraitBoundModifier::MaybeConstMaybe) => {
1453 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1459 visit::walk_param_bound(self, bound)
1462 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1463 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1464 visit::walk_poly_trait_ref(self, t);
1467 fn visit_variant_data(&mut self, s: &'a VariantData) {
1468 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1471 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1472 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1475 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1476 // Only associated `fn`s can have `self` parameters.
1477 let self_semantic = match fk.ctxt() {
1478 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1479 _ => SelfSemantic::No,
1481 self.check_fn_decl(fk.decl(), self_semantic);
1483 self.check_c_variadic_type(fk);
1485 // Functions cannot both be `const async`
1486 if let Some(FnHeader {
1487 constness: Const::Yes(cspan),
1488 asyncness: Async::Yes { span: aspan, .. },
1494 vec![*cspan, *aspan],
1495 "functions cannot be both `const` and `async`",
1497 .span_label(*cspan, "`const` because of this")
1498 .span_label(*aspan, "`async` because of this")
1499 .span_label(span, "") // Point at the fn header.
1503 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1504 self.check_late_bound_lifetime_defs(generic_params);
1510 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1516 self.maybe_lint_missing_abi(*sig_span, id);
1519 // Functions without bodies cannot have patterns.
1520 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1521 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1522 let (code, msg, label) = match ctxt {
1523 FnCtxt::Foreign => (
1525 "patterns aren't allowed in foreign function declarations",
1526 "pattern not allowed in foreign function",
1530 "patterns aren't allowed in functions without bodies",
1531 "pattern not allowed in function without body",
1534 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1535 if let Some(ident) = ident {
1536 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1537 self.lint_buffer.buffer_lint_with_diagnostic(
1538 PATTERNS_IN_FNS_WITHOUT_BODY,
1547 .struct_span_err(span, msg)
1548 .span_label(span, label)
1555 let tilde_const_allowed =
1556 matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1557 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1559 self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
1562 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1563 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1564 self.check_nomangle_item_asciionly(item.ident, item.span);
1567 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1568 self.check_defaultness(item.span, item.kind.defaultness());
1571 if ctxt == AssocCtxt::Impl {
1573 AssocItemKind::Const(_, _, body) => {
1575 self.session.emit_err(AssocConstWithoutBody {
1577 replace_span: self.ending_semi_or_hi(item.span),
1581 AssocItemKind::Fn(box Fn { body, .. }) => {
1583 self.session.emit_err(AssocFnWithoutBody {
1585 replace_span: self.ending_semi_or_hi(item.span),
1589 AssocItemKind::TyAlias(box TyAlias {
1592 where_predicates_split,
1598 self.session.emit_err(AssocTypeWithoutBody {
1600 replace_span: self.ending_semi_or_hi(item.span),
1603 self.check_type_no_bounds(bounds, "`impl`s");
1605 self.check_gat_where(
1607 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1616 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1617 self.invalid_visibility(&item.vis, None);
1618 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1619 self.check_trait_fn_not_const(sig.header.constness);
1620 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1624 if let AssocItemKind::Const(..) = item.kind {
1625 self.check_item_named(item.ident, "const");
1629 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1630 if ctxt == AssocCtxt::Trait =>
1632 self.visit_vis(&item.vis);
1633 self.visit_ident(item.ident);
1634 walk_list!(self, visit_attribute, &item.attrs);
1635 self.with_tilde_const_allowed(|this| {
1636 this.visit_generics(generics);
1637 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1639 walk_list!(self, visit_ty, ty);
1641 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1642 if self.in_const_trait_impl
1643 || ctxt == AssocCtxt::Trait
1644 || matches!(sig.header.constness, Const::Yes(_)) =>
1646 self.visit_vis(&item.vis);
1647 self.visit_ident(item.ident);
1648 let kind = FnKind::Fn(
1649 FnCtxt::Assoc(ctxt),
1656 self.visit_fn(kind, item.span, item.id);
1659 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1664 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1665 /// like it's setting an associated type, provide an appropriate suggestion.
1666 fn deny_equality_constraints(
1667 this: &mut AstValidator<'_>,
1668 predicate: &WhereEqPredicate,
1669 generics: &Generics,
1671 let mut err = this.err_handler().struct_span_err(
1673 "equality constraints are not yet supported in `where` clauses",
1675 err.span_label(predicate.span, "not supported");
1677 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1678 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1679 if let TyKind::Path(None, path) = &qself.ty.kind {
1680 match &path.segments[..] {
1681 [PathSegment { ident, args: None, .. }] => {
1682 for param in &generics.params {
1683 if param.ident == *ident {
1685 match &full_path.segments[qself.position..] {
1686 [PathSegment { ident, args, .. }] => {
1687 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1688 let mut assoc_path = full_path.clone();
1689 // Remove `Bar` from `Foo::Bar`.
1690 assoc_path.segments.pop();
1691 let len = assoc_path.segments.len() - 1;
1692 let gen_args = args.as_ref().map(|p| (**p).clone());
1693 // Build `<Bar = RhsTy>`.
1694 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1695 id: rustc_ast::node_id::DUMMY_NODE_ID,
1698 kind: AssocConstraintKind::Equality {
1699 term: predicate.rhs_ty.clone().into(),
1703 // Add `<Bar = RhsTy>` to `Foo`.
1704 match &mut assoc_path.segments[len].args {
1705 Some(args) => match args.deref_mut() {
1706 GenericArgs::Parenthesized(_) => continue,
1707 GenericArgs::AngleBracketed(args) => {
1708 args.args.push(arg);
1712 *empty_args = AngleBracketedArgs {
1719 err.span_suggestion_verbose(
1722 "if `{}` is an associated type you're trying to set, \
1723 use the associated type binding syntax",
1729 pprust::path_to_string(&assoc_path)
1731 Applicability::MaybeIncorrect,
1743 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1744 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1745 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1746 for param in &generics.params {
1747 if param.ident == potential_param.ident {
1748 for bound in ¶m.bounds {
1749 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1751 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1752 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1753 potential_assoc.ident,
1755 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1756 let (args, span) = match &trait_segment.args {
1757 Some(args) => match args.deref() {
1758 ast::GenericArgs::AngleBracketed(args) => {
1759 let Some(arg) = args.args.last() else {
1763 format!(", {} = {}", assoc, ty),
1764 arg.span().shrink_to_hi(),
1770 format!("<{} = {}>", assoc, ty),
1771 trait_segment.span().shrink_to_hi(),
1774 err.multipart_suggestion(
1776 "if `{}::{}` is an associated type you're trying to set, \
1777 use the associated type binding syntax",
1778 trait_segment.ident, potential_assoc.ident,
1780 vec![(span, args), (predicate.span, String::new())],
1781 Applicability::MaybeIncorrect,
1791 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1796 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1797 let mut validator = AstValidator {
1800 in_trait_impl: false,
1801 in_const_trait_impl: false,
1802 has_proc_macro_decls: false,
1803 outer_impl_trait: None,
1804 is_tilde_const_allowed: false,
1805 is_impl_trait_banned: false,
1806 is_assoc_ty_bound_banned: false,
1807 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1810 visit::walk_crate(&mut validator, krate);
1812 validator.has_proc_macro_decls
1815 /// Used to forbid `let` expressions in certain syntactic locations.
1816 #[derive(Clone, Copy)]
1817 pub(crate) enum ForbiddenLetReason {
1818 /// `let` is not valid and the source environment is not important
1820 /// A let chain with the `||` operator
1821 NotSupportedOr(Span),
1822 /// A let chain with invalid parentheses
1824 /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
1825 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1826 NotSupportedParentheses(Span),