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 visit_struct_field_def(&mut self, field: &'a FieldDef) {
256 if let Some(ident) = field.ident {
257 if ident.name == kw::Underscore {
258 self.visit_vis(&field.vis);
259 self.visit_ident(ident);
260 self.visit_ty_common(&field.ty);
261 self.walk_ty(&field.ty);
262 walk_list!(self, visit_attribute, &field.attrs);
266 self.visit_field_def(field);
269 fn err_handler(&self) -> &rustc_errors::Handler {
270 &self.session.diagnostic()
273 fn check_lifetime(&self, ident: Ident) {
274 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
275 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
276 self.session.emit_err(KeywordLifetime { span: ident.span });
280 fn check_label(&self, ident: Ident) {
281 if ident.without_first_quote().is_reserved() {
282 self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
286 fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
287 if let VisibilityKind::Inherited = vis.kind {
291 self.session.emit_err(InvalidVisibility {
293 implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
298 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
299 for Param { pat, .. } in &decl.inputs {
301 PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {}
302 PatKind::Ident(BindingAnnotation::MUT, ident, None) => {
303 report_err(pat.span, Some(ident), true)
305 _ => report_err(pat.span, None, false),
310 fn check_trait_fn_not_const(&self, constness: Const) {
311 if let Const::Yes(span) = constness {
312 self.session.emit_err(TraitFnConst { span });
316 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
317 // Check only lifetime parameters are present and that the lifetime
318 // parameters that are present have no bounds.
319 let non_lt_param_spans: Vec<_> = params
321 .filter_map(|param| match param.kind {
322 GenericParamKind::Lifetime { .. } => {
323 if !param.bounds.is_empty() {
324 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
325 self.session.emit_err(ForbiddenLifetimeBound { spans });
329 _ => Some(param.ident.span),
332 if !non_lt_param_spans.is_empty() {
333 self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
337 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
338 self.check_decl_num_args(fn_decl);
339 self.check_decl_cvaradic_pos(fn_decl);
340 self.check_decl_attrs(fn_decl);
341 self.check_decl_self_param(fn_decl, self_semantic);
344 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
345 /// Error is fatal to prevent errors during typechecking
346 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
347 let max_num_args: usize = u16::MAX.into();
348 if fn_decl.inputs.len() > max_num_args {
349 let Param { span, .. } = fn_decl.inputs[0];
350 self.session.emit_fatal(FnParamTooMany { span, max_num_args });
354 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
355 match &*fn_decl.inputs {
356 [Param { ty, span, .. }] => {
357 if let TyKind::CVarArgs = ty.kind {
358 self.session.emit_err(FnParamCVarArgsOnly { span: *span });
362 for Param { ty, span, .. } in ps {
363 if let TyKind::CVarArgs = ty.kind {
364 self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
372 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
376 .flat_map(|i| i.attrs.as_ref())
387 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
390 if attr.is_doc_comment() {
391 self.session.emit_err(FnParamDocComment { span: attr.span });
393 self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
398 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
399 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
401 self.session.emit_err(FnParamForbiddenSelf { span: param.span });
406 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
407 if let Defaultness::Default(def_span) = defaultness {
408 let span = self.session.source_map().guess_head_span(span);
409 self.session.emit_err(ForbiddenDefault { span, def_span });
413 /// If `sp` ends with a semicolon, returns it as a `Span`
414 /// Otherwise, returns `sp.shrink_to_hi()`
415 fn ending_semi_or_hi(&self, sp: Span) -> Span {
416 let source_map = self.session.source_map();
417 let end = source_map.end_point(sp);
419 if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
426 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
427 let span = match bounds {
430 [b0, .., bl] => b0.span().to(bl.span()),
433 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
437 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
438 let cannot_have = |span, descr, remove_descr| {
442 &format!("`type`s inside `extern` blocks cannot have {}", descr),
446 &format!("remove the {}", remove_descr),
448 Applicability::MaybeIncorrect,
450 .span_label(self.current_extern_span(), "`extern` block begins here")
455 if !generics.params.is_empty() {
456 cannot_have(generics.span, "generic parameters", "generic parameters");
459 if !generics.where_clause.predicates.is_empty() {
460 cannot_have(where_span, "`where` clauses", "`where` clause");
464 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
465 let Some(body) = body else {
469 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
470 .span_label(ident.span, "cannot have a body")
471 .span_label(body, "the invalid body")
473 self.current_extern_span(),
475 "`extern` blocks define existing foreign {0}s and {0}s \
476 inside of them cannot have a body",
484 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
485 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
486 let Some(body) = body else {
490 .struct_span_err(ident.span, "incorrect function inside `extern` block")
491 .span_label(ident.span, "cannot have a body")
494 "remove the invalid body",
496 Applicability::MaybeIncorrect,
499 "you might have meant to write a function accessible through FFI, \
500 which can be done by writing `extern fn` outside of the `extern` block",
503 self.current_extern_span(),
504 "`extern` blocks define existing foreign functions and functions \
505 inside of them cannot have a body",
511 fn current_extern_span(&self) -> Span {
512 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
515 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
516 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
517 if header.has_qualifiers() {
519 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
520 .span_label(self.current_extern_span(), "in this `extern` block")
521 .span_suggestion_verbose(
522 span.until(ident.span.shrink_to_lo()),
523 "remove the qualifiers",
525 Applicability::MaybeIncorrect,
531 /// An item in `extern { ... }` cannot use non-ascii identifier.
532 fn check_foreign_item_ascii_only(&self, ident: Ident) {
533 if !ident.as_str().is_ascii() {
538 "items in `extern` blocks cannot use non-ascii identifiers",
540 .span_label(self.current_extern_span(), "in this `extern` block")
542 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
549 /// Reject C-variadic type unless the function is foreign,
550 /// or free and `unsafe extern "C"` semantically.
551 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
552 match (fk.ctxt(), fk.header()) {
553 (Some(FnCtxt::Foreign), _) => return,
554 (Some(FnCtxt::Free), Some(header)) => match header.ext {
555 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
556 | Extern::Implicit(_)
557 if matches!(header.unsafety, Unsafe::Yes(_)) =>
566 for Param { ty, span, .. } in &fk.decl().inputs {
567 if let TyKind::CVarArgs = ty.kind {
571 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
578 fn check_item_named(&self, ident: Ident, kind: &str) {
579 if ident.name != kw::Underscore {
583 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
584 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
588 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
589 if ident.name.as_str().is_ascii() {
592 let head_span = self.session.source_map().guess_head_span(item_span);
597 "`#[no_mangle]` requires ASCII identifier"
602 fn check_mod_file_item_asciionly(&self, ident: Ident) {
603 if ident.name.as_str().is_ascii() {
610 "trying to load file for module `{}` with non-ascii identifier name",
613 .help("consider using `#[path]` attribute to specify filesystem path")
617 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
618 if !generics.params.is_empty() {
623 "auto traits cannot have generic parameters"
625 .span_label(ident_span, "auto trait cannot have generic parameters")
628 "remove the parameters",
630 Applicability::MachineApplicable,
636 fn emit_e0568(&self, span: Span, ident_span: Span) {
641 "auto traits cannot have super traits or lifetime bounds"
643 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
646 "remove the super traits or lifetime bounds",
648 Applicability::MachineApplicable,
653 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
654 if let [.., last] = &bounds[..] {
655 let span = ident_span.shrink_to_hi().to(last.span());
656 self.emit_e0568(span, ident_span);
660 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
661 if !where_clause.predicates.is_empty() {
662 self.emit_e0568(where_clause.span, ident_span);
666 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
667 if !trait_items.is_empty() {
668 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
669 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
674 "auto traits cannot have associated items"
678 "remove these associated items",
680 Applicability::MachineApplicable,
682 .span_label(ident_span, "auto trait cannot have associated items")
687 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
688 // Lifetimes always come first.
689 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
690 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
691 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
695 let args_sugg = data.args.iter().filter_map(|a| match a {
696 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
699 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
701 // Constraints always come last.
702 let constraint_sugg = data.args.iter().filter_map(|a| match a {
703 AngleBracketedArg::Arg(_) => None,
704 AngleBracketedArg::Constraint(c) => {
705 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
710 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
714 /// Enforce generic args coming before constraints in `<...>` of a path segment.
715 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
716 // Early exit in case it's partitioned as it should be.
717 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
720 // Find all generic argument coming after the first constraint...
721 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
722 data.args.iter().partition_map(|arg| match arg {
723 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
724 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
726 let args_len = arg_spans.len();
727 let constraint_len = constraint_spans.len();
728 // ...and then error:
732 "generic arguments must come before the first constraint",
734 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
736 *arg_spans.iter().last().unwrap(),
737 &format!("generic argument{}", pluralize!(args_len)),
739 .span_labels(constraint_spans, "")
740 .span_labels(arg_spans, "")
741 .span_suggestion_verbose(
744 "move the constraint{} after the generic argument{}",
745 pluralize!(constraint_len),
748 self.correct_generic_order_suggestion(&data),
749 Applicability::MachineApplicable,
754 fn visit_ty_common(&mut self, ty: &'a Ty) {
756 TyKind::BareFn(ref bfty) => {
757 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
758 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
763 "patterns aren't allowed in function pointer types"
767 self.check_late_bound_lifetime_defs(&bfty.generic_params);
768 if let Extern::Implicit(_) = bfty.ext {
769 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
770 self.maybe_lint_missing_abi(sig_span, ty.id);
773 TyKind::TraitObject(ref bounds, ..) => {
774 let mut any_lifetime_bounds = false;
775 for bound in bounds {
776 if let GenericBound::Outlives(ref lifetime) = *bound {
777 if any_lifetime_bounds {
782 "only a single explicit lifetime bound is permitted"
787 any_lifetime_bounds = true;
791 TyKind::ImplTrait(_, ref bounds) => {
792 if self.is_impl_trait_banned {
797 "`impl Trait` is not allowed in path parameters"
802 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
807 "nested `impl Trait` is not allowed"
809 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
810 .span_label(ty.span, "nested `impl Trait` here")
814 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
815 self.err_handler().span_err(ty.span, "at least one trait must be specified");
822 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
823 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
824 // call site which do not have a macro backtrace. See #61963.
825 let is_macro_callsite = self
828 .span_to_snippet(span)
829 .map(|snippet| snippet.starts_with("#["))
831 if !is_macro_callsite {
832 self.lint_buffer.buffer_lint_with_diagnostic(
836 "extern declarations without an explicit ABI are deprecated",
837 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
843 /// Checks that generic parameters are in the correct order,
844 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
845 fn validate_generic_param_order(
846 handler: &rustc_errors::Handler,
847 generics: &[GenericParam],
850 let mut max_param: Option<ParamKindOrd> = None;
851 let mut out_of_order = FxHashMap::default();
852 let mut param_idents = Vec::with_capacity(generics.len());
854 for (idx, param) in generics.iter().enumerate() {
855 let ident = param.ident;
856 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
857 let (ord_kind, ident) = match ¶m.kind {
858 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
859 GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()),
860 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
861 let ty = pprust::ty_to_string(ty);
862 (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
865 param_idents.push((kind, ord_kind, bounds, idx, ident));
867 Some(max_param) if max_param > ord_kind => {
868 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
871 Some(_) | None => max_param = Some(ord_kind),
875 if !out_of_order.is_empty() {
876 let mut ordered_params = "<".to_string();
877 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
878 let mut first = true;
879 for (kind, _, bounds, _, ident) in param_idents {
881 ordered_params += ", ";
883 ordered_params += &ident;
885 if !bounds.is_empty() {
886 ordered_params += ": ";
887 ordered_params += &pprust::bounds_to_string(&bounds);
891 GenericParamKind::Type { default: Some(default) } => {
892 ordered_params += " = ";
893 ordered_params += &pprust::ty_to_string(default);
895 GenericParamKind::Type { default: None } => (),
896 GenericParamKind::Lifetime => (),
897 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
898 ordered_params += " = ";
899 ordered_params += &pprust::expr_to_string(&*default.value);
901 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
906 ordered_params += ">";
908 for (param_ord, (max_param, spans)) in &out_of_order {
909 let mut err = handler.struct_span_err(
912 "{} parameters must be declared prior to {} parameters",
913 param_ord, max_param,
918 "reorder the parameters: lifetimes, then consts and types",
920 Applicability::MachineApplicable,
927 impl<'a> Visitor<'a> for AstValidator<'a> {
928 fn visit_attribute(&mut self, attr: &Attribute) {
929 validate_attr::check_meta(&self.session.parse_sess, attr);
932 fn visit_expr(&mut self, expr: &'a Expr) {
933 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
935 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
936 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
937 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
938 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
940 ExprKind::If(cond, then, opt_else) => {
941 this.visit_block(then);
942 walk_list!(this, visit_expr, opt_else);
943 this.with_let_management(None, |this, _| this.visit_expr(cond));
946 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
947 this.ban_let_expr(expr, elem);
949 ExprKind::Match(scrutinee, arms) => {
950 this.visit_expr(scrutinee);
952 this.visit_expr(&arm.body);
953 this.visit_pat(&arm.pat);
954 walk_list!(this, visit_attribute, &arm.attrs);
955 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
956 this.with_let_management(None, |this, _| {
957 this.visit_expr(guard_expr)
963 ExprKind::Paren(local_expr) => {
964 fn has_let_expr(expr: &Expr) -> bool {
966 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
967 ExprKind::Let(..) => true,
971 let local_reason = if has_let_expr(local_expr) {
972 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
977 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
979 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
980 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
983 ExprKind::While(cond, then, opt_label) => {
984 walk_list!(this, visit_label, opt_label);
985 this.visit_block(then);
986 this.with_let_management(None, |this, _| this.visit_expr(cond));
989 _ => visit::walk_expr(this, expr),
994 fn visit_ty(&mut self, ty: &'a Ty) {
995 self.visit_ty_common(ty);
999 fn visit_label(&mut self, label: &'a Label) {
1000 self.check_label(label.ident);
1001 visit::walk_label(self, label);
1004 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
1005 self.check_lifetime(lifetime.ident);
1006 visit::walk_lifetime(self, lifetime);
1009 fn visit_field_def(&mut self, s: &'a FieldDef) {
1010 visit::walk_field_def(self, s)
1013 fn visit_item(&mut self, item: &'a Item) {
1014 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1015 self.has_proc_macro_decls = true;
1018 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1019 self.check_nomangle_item_asciionly(item.ident, item.span);
1023 ItemKind::Impl(box Impl {
1029 of_trait: Some(ref t),
1033 self.with_in_trait_impl(true, Some(constness), |this| {
1034 this.invalid_visibility(&item.vis, None);
1035 if let TyKind::Err = self_ty.kind {
1039 "`impl Trait for .. {}` is an obsolete syntax",
1041 .help("use `auto trait Trait {}` instead")
1044 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1049 "negative impls cannot be unsafe"
1051 .span_label(sp, "negative because of this")
1052 .span_label(span, "unsafe because of this")
1056 this.visit_vis(&item.vis);
1057 this.visit_ident(item.ident);
1058 if let Const::Yes(_) = constness {
1059 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1061 this.visit_generics(generics);
1063 this.visit_trait_ref(t);
1064 this.visit_ty(self_ty);
1066 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1068 return; // Avoid visiting again.
1070 ItemKind::Impl(box Impl {
1080 let error = |annotation_span, annotation| {
1081 let mut err = self.err_handler().struct_span_err(
1083 &format!("inherent impls cannot be {}", annotation),
1085 err.span_label(annotation_span, &format!("{} because of this", annotation));
1086 err.span_label(self_ty.span, "inherent impl for this type");
1090 self.invalid_visibility(
1092 Some(InvalidVisibilityNote::IndividualImplItems),
1094 if let Unsafe::Yes(span) = unsafety {
1095 error(span, "unsafe").code(error_code!(E0197)).emit();
1097 if let ImplPolarity::Negative(span) = polarity {
1098 error(span, "negative").emit();
1100 if let Defaultness::Default(def_span) = defaultness {
1101 error(def_span, "`default`")
1102 .note("only trait implementations may be annotated with `default`")
1105 if let Const::Yes(span) = constness {
1106 error(span, "`const`")
1107 .note("only trait implementations may be annotated with `const`")
1111 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1112 self.check_defaultness(item.span, defaultness);
1115 self.session.emit_err(FnWithoutBody {
1117 replace_span: self.ending_semi_or_hi(item.span),
1118 extern_block_suggestion: match sig.header.ext {
1119 Extern::None => None,
1120 Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1122 end_span: item.span.shrink_to_hi(),
1125 Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1127 end_span: item.span.shrink_to_hi(),
1128 abi: Some(abi.symbol_unescaped),
1134 self.visit_vis(&item.vis);
1135 self.visit_ident(item.ident);
1137 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1138 self.visit_fn(kind, item.span, item.id);
1139 walk_list!(self, visit_attribute, &item.attrs);
1140 return; // Avoid visiting again.
1142 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1143 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1144 self.invalid_visibility(
1146 Some(InvalidVisibilityNote::IndividualForeignItems),
1148 if let Unsafe::Yes(span) = unsafety {
1149 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1152 self.maybe_lint_missing_abi(item.span, item.id);
1154 visit::walk_item(self, item);
1155 self.extern_mod = old_item;
1156 return; // Avoid visiting again.
1158 ItemKind::Enum(ref def, _) => {
1159 for variant in &def.variants {
1160 self.invalid_visibility(&variant.vis, None);
1161 for field in variant.data.fields() {
1162 self.invalid_visibility(&field.vis, None);
1166 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1167 if is_auto == IsAuto::Yes {
1168 // Auto traits cannot have generics, super traits nor contain items.
1169 self.deny_generic_params(generics, item.ident.span);
1170 self.deny_super_traits(bounds, item.ident.span);
1171 self.deny_where_clause(&generics.where_clause, item.ident.span);
1172 self.deny_items(items, item.ident.span);
1175 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1176 // context for the supertraits.
1177 self.visit_vis(&item.vis);
1178 self.visit_ident(item.ident);
1179 self.visit_generics(generics);
1180 self.with_tilde_const_allowed(|this| {
1181 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1183 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1184 walk_list!(self, visit_attribute, &item.attrs);
1187 ItemKind::Mod(unsafety, ref mod_kind) => {
1188 if let Unsafe::Yes(span) = unsafety {
1189 self.err_handler().span_err(span, "module cannot be declared unsafe");
1191 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1192 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1193 && !self.session.contains_name(&item.attrs, sym::path)
1195 self.check_mod_file_item_asciionly(item.ident);
1198 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1199 // Duplicating the `Visitor` logic allows catching all cases
1200 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1202 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1203 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1204 // it uses `visit_ty_common`, which doesn't contain that specific check.
1205 VariantData::Struct(ref fields, ..) => {
1206 self.visit_vis(&item.vis);
1207 self.visit_ident(item.ident);
1208 self.visit_generics(generics);
1209 self.with_banned_assoc_ty_bound(|this| {
1210 walk_list!(this, visit_struct_field_def, fields);
1212 walk_list!(self, visit_attribute, &item.attrs);
1217 ItemKind::Union(ref vdata, ref generics) => {
1218 if vdata.fields().is_empty() {
1219 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1222 VariantData::Struct(ref fields, ..) => {
1223 self.visit_vis(&item.vis);
1224 self.visit_ident(item.ident);
1225 self.visit_generics(generics);
1226 self.with_banned_assoc_ty_bound(|this| {
1227 walk_list!(this, visit_struct_field_def, fields);
1229 walk_list!(self, visit_attribute, &item.attrs);
1235 ItemKind::Const(def, .., None) => {
1236 self.check_defaultness(item.span, def);
1237 self.session.emit_err(ConstWithoutBody {
1239 replace_span: self.ending_semi_or_hi(item.span),
1242 ItemKind::Static(.., None) => {
1243 self.session.emit_err(StaticWithoutBody {
1245 replace_span: self.ending_semi_or_hi(item.span),
1248 ItemKind::TyAlias(box TyAlias {
1255 self.check_defaultness(item.span, defaultness);
1257 self.session.emit_err(TyAliasWithoutBody {
1259 replace_span: self.ending_semi_or_hi(item.span),
1262 self.check_type_no_bounds(bounds, "this context");
1263 if where_clauses.1.0 {
1264 let mut err = self.err_handler().struct_span_err(
1266 "where clauses are not allowed after the type for type aliases",
1269 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1277 visit::walk_item(self, item);
1280 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1282 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1283 self.check_defaultness(fi.span, *defaultness);
1284 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1285 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1286 self.check_foreign_item_ascii_only(fi.ident);
1288 ForeignItemKind::TyAlias(box TyAlias {
1296 self.check_defaultness(fi.span, *defaultness);
1297 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1298 self.check_type_no_bounds(bounds, "`extern` blocks");
1299 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1300 self.check_foreign_item_ascii_only(fi.ident);
1302 ForeignItemKind::Static(_, _, body) => {
1303 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1304 self.check_foreign_item_ascii_only(fi.ident);
1306 ForeignItemKind::MacCall(..) => {}
1309 visit::walk_foreign_item(self, fi)
1312 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1313 fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
1314 match *generic_args {
1315 GenericArgs::AngleBracketed(ref data) => {
1316 self.check_generic_args_before_constraints(data);
1318 for arg in &data.args {
1320 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1321 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1322 // are allowed to contain nested `impl Trait`.
1323 AngleBracketedArg::Constraint(constraint) => {
1324 self.with_impl_trait(None, |this| {
1325 this.visit_assoc_constraint_from_generic_args(constraint);
1331 GenericArgs::Parenthesized(ref data) => {
1332 walk_list!(self, visit_ty, &data.inputs);
1333 if let FnRetTy::Ty(ty) = &data.output {
1334 // `-> Foo` syntax is essentially an associated type binding,
1335 // so it is also allowed to contain nested `impl Trait`.
1336 self.with_impl_trait(None, |this| this.visit_ty(ty));
1342 fn visit_generics(&mut self, generics: &'a Generics) {
1343 let mut prev_param_default = None;
1344 for param in &generics.params {
1346 GenericParamKind::Lifetime => (),
1347 GenericParamKind::Type { default: Some(_), .. }
1348 | GenericParamKind::Const { default: Some(_), .. } => {
1349 prev_param_default = Some(param.ident.span);
1351 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1352 if let Some(span) = prev_param_default {
1353 let mut err = self.err_handler().struct_span_err(
1355 "generic parameters with a default must be trailing",
1364 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1366 for predicate in &generics.where_clause.predicates {
1367 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1368 deny_equality_constraints(self, predicate, generics);
1371 walk_list!(self, visit_generic_param, &generics.params);
1372 for predicate in &generics.where_clause.predicates {
1374 WherePredicate::BoundPredicate(bound_pred) => {
1375 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1376 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1378 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1379 // binder and thus we only allow a single level of quantification. However,
1380 // the syntax of Rust permits quantification in two places in where clauses,
1381 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1382 // defined, then error.
1383 if !bound_pred.bound_generic_params.is_empty() {
1384 for bound in &bound_pred.bounds {
1386 GenericBound::Trait(t, _) => {
1387 if !t.bound_generic_params.is_empty() {
1392 "nested quantification of lifetimes"
1397 GenericBound::Outlives(_) => {}
1404 self.visit_where_predicate(predicate);
1408 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1409 if let GenericParamKind::Lifetime { .. } = param.kind {
1410 self.check_lifetime(param.ident);
1412 visit::walk_generic_param(self, param);
1415 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1416 if let GenericBound::Trait(ref poly, modify) = *bound {
1417 match (ctxt, modify) {
1418 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1421 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1422 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1423 err.note(&format!("traits are `?{}` by default", path_str));
1426 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1427 let mut err = self.err_handler().struct_span_err(
1429 "`?Trait` is not permitted in trait object types",
1433 (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
1434 let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
1436 DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
1437 DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
1438 DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
1439 DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
1443 (_, TraitBoundModifier::MaybeConstMaybe) => {
1445 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1451 visit::walk_param_bound(self, bound)
1454 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1455 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1456 visit::walk_poly_trait_ref(self, t);
1459 fn visit_variant_data(&mut self, s: &'a VariantData) {
1460 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1463 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1464 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1467 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1468 // Only associated `fn`s can have `self` parameters.
1469 let self_semantic = match fk.ctxt() {
1470 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1471 _ => SelfSemantic::No,
1473 self.check_fn_decl(fk.decl(), self_semantic);
1475 self.check_c_variadic_type(fk);
1477 // Functions cannot both be `const async`
1478 if let Some(FnHeader {
1479 constness: Const::Yes(cspan),
1480 asyncness: Async::Yes { span: aspan, .. },
1486 vec![*cspan, *aspan],
1487 "functions cannot be both `const` and `async`",
1489 .span_label(*cspan, "`const` because of this")
1490 .span_label(*aspan, "`async` because of this")
1491 .span_label(span, "") // Point at the fn header.
1495 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1496 self.check_late_bound_lifetime_defs(generic_params);
1502 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1508 self.maybe_lint_missing_abi(*sig_span, id);
1511 // Functions without bodies cannot have patterns.
1512 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1513 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1514 let (code, msg, label) = match ctxt {
1515 FnCtxt::Foreign => (
1517 "patterns aren't allowed in foreign function declarations",
1518 "pattern not allowed in foreign function",
1522 "patterns aren't allowed in functions without bodies",
1523 "pattern not allowed in function without body",
1526 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1527 if let Some(ident) = ident {
1528 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1529 self.lint_buffer.buffer_lint_with_diagnostic(
1530 PATTERNS_IN_FNS_WITHOUT_BODY,
1539 .struct_span_err(span, msg)
1540 .span_label(span, label)
1547 let tilde_const_allowed =
1548 matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1549 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1551 let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
1553 self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
1556 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1557 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1558 self.check_nomangle_item_asciionly(item.ident, item.span);
1561 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1562 self.check_defaultness(item.span, item.kind.defaultness());
1565 if ctxt == AssocCtxt::Impl {
1567 AssocItemKind::Const(_, _, body) => {
1569 self.session.emit_err(AssocConstWithoutBody {
1571 replace_span: self.ending_semi_or_hi(item.span),
1575 AssocItemKind::Fn(box Fn { body, .. }) => {
1577 self.session.emit_err(AssocFnWithoutBody {
1579 replace_span: self.ending_semi_or_hi(item.span),
1583 AssocItemKind::Type(box TyAlias {
1586 where_predicates_split,
1592 self.session.emit_err(AssocTypeWithoutBody {
1594 replace_span: self.ending_semi_or_hi(item.span),
1597 self.check_type_no_bounds(bounds, "`impl`s");
1599 self.check_gat_where(
1601 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1610 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1611 self.invalid_visibility(&item.vis, None);
1612 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1613 self.check_trait_fn_not_const(sig.header.constness);
1617 if let AssocItemKind::Const(..) = item.kind {
1618 self.check_item_named(item.ident, "const");
1622 AssocItemKind::Type(box TyAlias { ref generics, ref bounds, ref ty, .. })
1623 if ctxt == AssocCtxt::Trait =>
1625 self.visit_vis(&item.vis);
1626 self.visit_ident(item.ident);
1627 walk_list!(self, visit_attribute, &item.attrs);
1628 self.with_tilde_const_allowed(|this| {
1629 this.visit_generics(generics);
1630 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1632 walk_list!(self, visit_ty, ty);
1634 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1635 if self.in_const_trait_impl
1636 || ctxt == AssocCtxt::Trait
1637 || matches!(sig.header.constness, Const::Yes(_)) =>
1639 self.visit_vis(&item.vis);
1640 self.visit_ident(item.ident);
1641 let kind = FnKind::Fn(
1642 FnCtxt::Assoc(ctxt),
1649 self.visit_fn(kind, item.span, item.id);
1652 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1657 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1658 /// like it's setting an associated type, provide an appropriate suggestion.
1659 fn deny_equality_constraints(
1660 this: &mut AstValidator<'_>,
1661 predicate: &WhereEqPredicate,
1662 generics: &Generics,
1664 let mut err = this.err_handler().struct_span_err(
1666 "equality constraints are not yet supported in `where` clauses",
1668 err.span_label(predicate.span, "not supported");
1670 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1671 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1672 if let TyKind::Path(None, path) = &qself.ty.kind {
1673 match &path.segments[..] {
1674 [PathSegment { ident, args: None, .. }] => {
1675 for param in &generics.params {
1676 if param.ident == *ident {
1678 match &full_path.segments[qself.position..] {
1679 [PathSegment { ident, args, .. }] => {
1680 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1681 let mut assoc_path = full_path.clone();
1682 // Remove `Bar` from `Foo::Bar`.
1683 assoc_path.segments.pop();
1684 let len = assoc_path.segments.len() - 1;
1685 let gen_args = args.as_ref().map(|p| (**p).clone());
1686 // Build `<Bar = RhsTy>`.
1687 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1688 id: rustc_ast::node_id::DUMMY_NODE_ID,
1691 kind: AssocConstraintKind::Equality {
1692 term: predicate.rhs_ty.clone().into(),
1696 // Add `<Bar = RhsTy>` to `Foo`.
1697 match &mut assoc_path.segments[len].args {
1698 Some(args) => match args.deref_mut() {
1699 GenericArgs::Parenthesized(_) => continue,
1700 GenericArgs::AngleBracketed(args) => {
1701 args.args.push(arg);
1705 *empty_args = AngleBracketedArgs {
1712 err.span_suggestion_verbose(
1715 "if `{}` is an associated type you're trying to set, \
1716 use the associated type binding syntax",
1722 pprust::path_to_string(&assoc_path)
1724 Applicability::MaybeIncorrect,
1736 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1737 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1738 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1739 for param in &generics.params {
1740 if param.ident == potential_param.ident {
1741 for bound in ¶m.bounds {
1742 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1744 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1745 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1746 potential_assoc.ident,
1748 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1749 let (args, span) = match &trait_segment.args {
1750 Some(args) => match args.deref() {
1751 ast::GenericArgs::AngleBracketed(args) => {
1752 let Some(arg) = args.args.last() else {
1756 format!(", {} = {}", assoc, ty),
1757 arg.span().shrink_to_hi(),
1763 format!("<{} = {}>", assoc, ty),
1764 trait_segment.span().shrink_to_hi(),
1767 err.multipart_suggestion(
1769 "if `{}::{}` is an associated type you're trying to set, \
1770 use the associated type binding syntax",
1771 trait_segment.ident, potential_assoc.ident,
1773 vec![(span, args), (predicate.span, String::new())],
1774 Applicability::MaybeIncorrect,
1784 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1789 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1790 let mut validator = AstValidator {
1793 in_trait_impl: false,
1794 in_const_trait_impl: false,
1795 has_proc_macro_decls: false,
1796 outer_impl_trait: None,
1797 disallow_tilde_const: None,
1798 is_impl_trait_banned: false,
1799 is_assoc_ty_bound_banned: false,
1800 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1803 visit::walk_crate(&mut validator, krate);
1805 validator.has_proc_macro_decls
1808 /// Used to forbid `let` expressions in certain syntactic locations.
1809 #[derive(Clone, Copy, Subdiagnostic)]
1810 pub(crate) enum ForbiddenLetReason {
1811 /// `let` is not valid and the source environment is not important
1813 /// A let chain with the `||` operator
1814 #[note(ast_passes::not_supported_or)]
1815 NotSupportedOr(#[primary_span] Span),
1816 /// A let chain with invalid parentheses
1818 /// For example, `let 1 = 1 && (expr && expr)` is allowed
1819 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1820 #[note(ast_passes::not_supported_parentheses)]
1821 NotSupportedParentheses(#[primary_span] Span),