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;
17 error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
19 use rustc_parse::validate_attr;
20 use rustc_session::lint::builtin::{
21 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
23 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
24 use rustc_session::Session;
25 use rustc_span::source_map::Spanned;
26 use rustc_span::symbol::{kw, sym, Ident};
28 use rustc_target::spec::abi;
30 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 "where clause not allowed here",
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.err_handler().span_err(
210 "associated type bounds are not allowed within structs, enums, or unions",
215 self.visit_assoc_constraint(constraint);
218 // Mirrors `visit::walk_ty`, but tracks relevant state.
219 fn walk_ty(&mut self, t: &'a Ty) {
221 TyKind::ImplTrait(..) => {
222 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
224 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
225 TyKind::Path(ref qself, ref path) => {
227 // - `Option<impl Trait>`
228 // - `option::Option<impl Trait>`
229 // - `option::Option<T>::Foo<impl Trait>
232 // - `<impl Trait>::Foo`
233 // - `option::Option<impl Trait>::Foo`.
235 // To implement this, we disallow `impl Trait` from `qself`
236 // (for cases like `<impl Trait>::Foo>`)
237 // but we allow `impl Trait` in `GenericArgs`
238 // iff there are no more PathSegments.
239 if let Some(ref qself) = *qself {
240 // `impl Trait` in `qself` is always illegal
241 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
244 // Note that there should be a call to visit_path here,
245 // so if any logic is added to process `Path`s a call to it should be
246 // added both in visit_path and here. This code mirrors visit::walk_path.
247 for (i, segment) in path.segments.iter().enumerate() {
248 // Allow `impl Trait` iff we're on the final path segment
249 if i == path.segments.len() - 1 {
250 self.visit_path_segment(path.span, segment);
252 self.with_banned_impl_trait(|this| {
253 this.visit_path_segment(path.span, segment)
258 _ => visit::walk_ty(self, t),
262 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
263 if let Some(ident) = field.ident {
264 if ident.name == kw::Underscore {
265 self.visit_vis(&field.vis);
266 self.visit_ident(ident);
267 self.visit_ty_common(&field.ty);
268 self.walk_ty(&field.ty);
269 walk_list!(self, visit_attribute, &field.attrs);
273 self.visit_field_def(field);
276 fn err_handler(&self) -> &rustc_errors::Handler {
277 &self.session.diagnostic()
280 fn check_lifetime(&self, ident: Ident) {
281 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
282 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
283 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
287 fn check_label(&self, ident: Ident) {
288 if ident.without_first_quote().is_reserved() {
290 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
294 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
295 if let VisibilityKind::Inherited = vis.kind {
300 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
301 if vis.kind.is_pub() {
302 err.span_label(vis.span, "`pub` not permitted here because it's implied");
304 if let Some(note) = note {
310 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
311 for Param { pat, .. } in &decl.inputs {
313 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
314 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
315 report_err(pat.span, Some(ident), true)
317 _ => report_err(pat.span, None, false),
322 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
323 if let Async::Yes { span, .. } = asyncness {
328 "functions in traits cannot be declared `async`"
330 .span_label(span, "`async` because of this")
331 .note("`async` trait functions are not currently supported")
332 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
337 fn check_trait_fn_not_const(&self, constness: Const) {
338 if let Const::Yes(span) = constness {
343 "functions in traits cannot be declared const"
345 .span_label(span, "functions in traits cannot be const")
350 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
351 // Check only lifetime parameters are present and that the lifetime
352 // parameters that are present have no bounds.
353 let non_lt_param_spans: Vec<_> = params
355 .filter_map(|param| match param.kind {
356 GenericParamKind::Lifetime { .. } => {
357 if !param.bounds.is_empty() {
358 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
360 .span_err(spans, "lifetime bounds cannot be used in this context");
364 _ => Some(param.ident.span),
367 if !non_lt_param_spans.is_empty() {
368 self.err_handler().span_err(
370 "only lifetime parameters can be used in this context",
375 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
376 self.check_decl_num_args(fn_decl);
377 self.check_decl_cvaradic_pos(fn_decl);
378 self.check_decl_attrs(fn_decl);
379 self.check_decl_self_param(fn_decl, self_semantic);
382 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
383 /// Error is fatal to prevent errors during typechecking
384 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
385 let max_num_args: usize = u16::MAX.into();
386 if fn_decl.inputs.len() > max_num_args {
387 let Param { span, .. } = fn_decl.inputs[0];
388 self.err_handler().span_fatal(
390 &format!("function can not have more than {} arguments", max_num_args),
395 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
396 match &*fn_decl.inputs {
397 [Param { ty, span, .. }] => {
398 if let TyKind::CVarArgs = ty.kind {
399 self.err_handler().span_err(
401 "C-variadic function must be declared with at least one named argument",
406 for Param { ty, span, .. } in ps {
407 if let TyKind::CVarArgs = ty.kind {
408 self.err_handler().span_err(
410 "`...` must be the last argument of a C-variadic function",
419 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
423 .flat_map(|i| i.attrs.as_ref())
434 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
437 if attr.is_doc_comment() {
441 "documentation comments cannot be applied to function parameters",
443 .span_label(attr.span, "doc comments are not allowed here")
446 self.err_handler().span_err(
448 "allow, cfg, cfg_attr, deny, expect, \
449 forbid, and warn are the only allowed built-in attributes in function parameters",
455 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
456 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
461 "`self` parameter is only allowed in associated functions",
463 .span_label(param.span, "not semantically valid as function parameter")
464 .note("associated functions are those in `impl` or `trait` definitions")
470 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
471 if let Defaultness::Default(def_span) = defaultness {
472 let span = self.session.source_map().guess_head_span(span);
474 .struct_span_err(span, "`default` is only allowed on items in trait impls")
475 .span_label(def_span, "`default` because of this")
480 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
481 self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
484 fn error_item_without_body_with_help(
490 help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>),
492 let source_map = self.session.source_map();
493 let end = source_map.end_point(sp);
494 let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
499 let mut err = self.err_handler().struct_span_err(sp, msg);
502 &format!("provide a definition for the {}", ctx),
504 Applicability::HasPlaceholders,
510 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
512 let msg = format!("associated {} in `impl` without body", ctx);
513 self.error_item_without_body(sp, ctx, &msg, sugg);
517 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
518 let span = match bounds {
521 [b0, .., bl] => b0.span().to(bl.span()),
524 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
528 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
529 let cannot_have = |span, descr, remove_descr| {
533 &format!("`type`s inside `extern` blocks cannot have {}", descr),
537 &format!("remove the {}", remove_descr),
539 Applicability::MaybeIncorrect,
541 .span_label(self.current_extern_span(), "`extern` block begins here")
546 if !generics.params.is_empty() {
547 cannot_have(generics.span, "generic parameters", "generic parameters");
550 if !generics.where_clause.predicates.is_empty() {
551 cannot_have(where_span, "`where` clauses", "`where` clause");
555 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
556 let Some(body) = body else {
560 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
561 .span_label(ident.span, "cannot have a body")
562 .span_label(body, "the invalid body")
564 self.current_extern_span(),
566 "`extern` blocks define existing foreign {0}s and {0}s \
567 inside of them cannot have a body",
575 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
576 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
577 let Some(body) = body else {
581 .struct_span_err(ident.span, "incorrect function inside `extern` block")
582 .span_label(ident.span, "cannot have a body")
585 "remove the invalid body",
587 Applicability::MaybeIncorrect,
590 "you might have meant to write a function accessible through FFI, \
591 which can be done by writing `extern fn` outside of the `extern` block",
594 self.current_extern_span(),
595 "`extern` blocks define existing foreign functions and functions \
596 inside of them cannot have a body",
602 fn current_extern_span(&self) -> Span {
603 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
606 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
607 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
608 if header.has_qualifiers() {
610 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
611 .span_label(self.current_extern_span(), "in this `extern` block")
612 .span_suggestion_verbose(
613 span.until(ident.span.shrink_to_lo()),
614 "remove the qualifiers",
616 Applicability::MaybeIncorrect,
622 /// An item in `extern { ... }` cannot use non-ascii identifier.
623 fn check_foreign_item_ascii_only(&self, ident: Ident) {
624 if !ident.as_str().is_ascii() {
629 "items in `extern` blocks cannot use non-ascii identifiers",
631 .span_label(self.current_extern_span(), "in this `extern` block")
633 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
640 /// Reject C-variadic type unless the function is foreign,
641 /// or free and `unsafe extern "C"` semantically.
642 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
643 match (fk.ctxt(), fk.header()) {
644 (Some(FnCtxt::Foreign), _) => return,
645 (Some(FnCtxt::Free), Some(header)) => match header.ext {
646 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
647 | Extern::Implicit(_)
648 if matches!(header.unsafety, Unsafe::Yes(_)) =>
657 for Param { ty, span, .. } in &fk.decl().inputs {
658 if let TyKind::CVarArgs = ty.kind {
662 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
669 fn check_item_named(&self, ident: Ident, kind: &str) {
670 if ident.name != kw::Underscore {
674 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
675 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
679 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
680 if ident.name.as_str().is_ascii() {
683 let head_span = self.session.source_map().guess_head_span(item_span);
688 "`#[no_mangle]` requires ASCII identifier"
693 fn check_mod_file_item_asciionly(&self, ident: Ident) {
694 if ident.name.as_str().is_ascii() {
701 "trying to load file for module `{}` with non-ascii identifier name",
704 .help("consider using `#[path]` attribute to specify filesystem path")
708 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
709 if !generics.params.is_empty() {
714 "auto traits cannot have generic parameters"
716 .span_label(ident_span, "auto trait cannot have generic parameters")
719 "remove the parameters",
721 Applicability::MachineApplicable,
727 fn emit_e0568(&self, span: Span, ident_span: Span) {
732 "auto traits cannot have super traits or lifetime bounds"
734 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
737 "remove the super traits or lifetime bounds",
739 Applicability::MachineApplicable,
744 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
745 if let [.., last] = &bounds[..] {
746 let span = ident_span.shrink_to_hi().to(last.span());
747 self.emit_e0568(span, ident_span);
751 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
752 if !where_clause.predicates.is_empty() {
753 self.emit_e0568(where_clause.span, ident_span);
757 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
758 if !trait_items.is_empty() {
759 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
760 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
765 "auto traits cannot have associated items"
769 "remove these associated items",
771 Applicability::MachineApplicable,
773 .span_label(ident_span, "auto trait cannot have associated items")
778 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
779 // Lifetimes always come first.
780 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
781 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
782 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
786 let args_sugg = data.args.iter().filter_map(|a| match a {
787 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
790 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
792 // Constraints always come last.
793 let constraint_sugg = data.args.iter().filter_map(|a| match a {
794 AngleBracketedArg::Arg(_) => None,
795 AngleBracketedArg::Constraint(c) => {
796 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
801 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
805 /// Enforce generic args coming before constraints in `<...>` of a path segment.
806 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
807 // Early exit in case it's partitioned as it should be.
808 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
811 // Find all generic argument coming after the first constraint...
812 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
813 data.args.iter().partition_map(|arg| match arg {
814 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
815 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
817 let args_len = arg_spans.len();
818 let constraint_len = constraint_spans.len();
819 // ...and then error:
823 "generic arguments must come before the first constraint",
825 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
827 *arg_spans.iter().last().unwrap(),
828 &format!("generic argument{}", pluralize!(args_len)),
830 .span_labels(constraint_spans, "")
831 .span_labels(arg_spans, "")
832 .span_suggestion_verbose(
835 "move the constraint{} after the generic argument{}",
836 pluralize!(constraint_len),
839 self.correct_generic_order_suggestion(&data),
840 Applicability::MachineApplicable,
845 fn visit_ty_common(&mut self, ty: &'a Ty) {
847 TyKind::BareFn(ref bfty) => {
848 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
849 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
854 "patterns aren't allowed in function pointer types"
858 self.check_late_bound_lifetime_defs(&bfty.generic_params);
859 if let Extern::Implicit(_) = bfty.ext {
860 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
861 self.maybe_lint_missing_abi(sig_span, ty.id);
864 TyKind::TraitObject(ref bounds, ..) => {
865 let mut any_lifetime_bounds = false;
866 for bound in bounds {
867 if let GenericBound::Outlives(ref lifetime) = *bound {
868 if any_lifetime_bounds {
873 "only a single explicit lifetime bound is permitted"
878 any_lifetime_bounds = true;
882 TyKind::ImplTrait(_, ref bounds) => {
883 if self.is_impl_trait_banned {
888 "`impl Trait` is not allowed in path parameters"
893 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
898 "nested `impl Trait` is not allowed"
900 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
901 .span_label(ty.span, "nested `impl Trait` here")
905 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
906 self.err_handler().span_err(ty.span, "at least one trait must be specified");
913 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
914 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
915 // call site which do not have a macro backtrace. See #61963.
916 let is_macro_callsite = self
919 .span_to_snippet(span)
920 .map(|snippet| snippet.starts_with("#["))
922 if !is_macro_callsite {
923 self.lint_buffer.buffer_lint_with_diagnostic(
927 "extern declarations without an explicit ABI are deprecated",
928 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
934 /// Checks that generic parameters are in the correct order,
935 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
936 fn validate_generic_param_order(
937 handler: &rustc_errors::Handler,
938 generics: &[GenericParam],
941 let mut max_param: Option<ParamKindOrd> = None;
942 let mut out_of_order = FxHashMap::default();
943 let mut param_idents = Vec::with_capacity(generics.len());
945 for (idx, param) in generics.iter().enumerate() {
946 let ident = param.ident;
947 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
948 let (ord_kind, ident) = match ¶m.kind {
949 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
950 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
951 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
952 let ty = pprust::ty_to_string(ty);
953 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
956 param_idents.push((kind, ord_kind, bounds, idx, ident));
958 Some(max_param) if max_param > ord_kind => {
959 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
962 Some(_) | None => max_param = Some(ord_kind),
966 if !out_of_order.is_empty() {
967 let mut ordered_params = "<".to_string();
968 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
969 let mut first = true;
970 for (kind, _, bounds, _, ident) in param_idents {
972 ordered_params += ", ";
974 ordered_params += &ident;
976 if !bounds.is_empty() {
977 ordered_params += ": ";
978 ordered_params += &pprust::bounds_to_string(&bounds);
982 GenericParamKind::Type { default: Some(default) } => {
983 ordered_params += " = ";
984 ordered_params += &pprust::ty_to_string(default);
986 GenericParamKind::Type { default: None } => (),
987 GenericParamKind::Lifetime => (),
988 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
989 ordered_params += " = ";
990 ordered_params += &pprust::expr_to_string(&*default.value);
992 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
997 ordered_params += ">";
999 for (param_ord, (max_param, spans)) in &out_of_order {
1000 let mut err = handler.struct_span_err(
1003 "{} parameters must be declared prior to {} parameters",
1004 param_ord, max_param,
1007 err.span_suggestion(
1009 "reorder the parameters: lifetimes, then consts and types",
1011 Applicability::MachineApplicable,
1018 impl<'a> Visitor<'a> for AstValidator<'a> {
1019 fn visit_attribute(&mut self, attr: &Attribute) {
1020 validate_attr::check_meta(&self.session.parse_sess, attr);
1023 fn visit_expr(&mut self, expr: &'a Expr) {
1024 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
1026 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
1027 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
1028 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
1029 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
1031 ExprKind::If(cond, then, opt_else) => {
1032 this.visit_block(then);
1033 walk_list!(this, visit_expr, opt_else);
1034 this.with_let_management(None, |this, _| this.visit_expr(cond));
1037 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
1038 this.ban_let_expr(expr, elem);
1040 ExprKind::Match(scrutinee, arms) => {
1041 this.visit_expr(scrutinee);
1043 this.visit_expr(&arm.body);
1044 this.visit_pat(&arm.pat);
1045 walk_list!(this, visit_attribute, &arm.attrs);
1046 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
1047 this.with_let_management(None, |this, _| {
1048 this.visit_expr(guard_expr)
1054 ExprKind::Paren(local_expr) => {
1055 fn has_let_expr(expr: &Expr) -> bool {
1057 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
1058 ExprKind::Let(..) => true,
1062 let local_reason = if has_let_expr(local_expr) {
1063 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
1066 forbidden_let_reason
1068 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
1070 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1071 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
1074 ExprKind::While(cond, then, opt_label) => {
1075 walk_list!(this, visit_label, opt_label);
1076 this.visit_block(then);
1077 this.with_let_management(None, |this, _| this.visit_expr(cond));
1080 _ => visit::walk_expr(this, expr),
1085 fn visit_ty(&mut self, ty: &'a Ty) {
1086 self.visit_ty_common(ty);
1090 fn visit_label(&mut self, label: &'a Label) {
1091 self.check_label(label.ident);
1092 visit::walk_label(self, label);
1095 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
1096 self.check_lifetime(lifetime.ident);
1097 visit::walk_lifetime(self, lifetime);
1100 fn visit_field_def(&mut self, s: &'a FieldDef) {
1101 visit::walk_field_def(self, s)
1104 fn visit_item(&mut self, item: &'a Item) {
1105 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1106 self.has_proc_macro_decls = true;
1109 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1110 self.check_nomangle_item_asciionly(item.ident, item.span);
1114 ItemKind::Impl(box Impl {
1120 of_trait: Some(ref t),
1124 self.with_in_trait_impl(true, Some(constness), |this| {
1125 this.invalid_visibility(&item.vis, None);
1126 if let TyKind::Err = self_ty.kind {
1130 "`impl Trait for .. {}` is an obsolete syntax",
1132 .help("use `auto trait Trait {}` instead")
1135 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1140 "negative impls cannot be unsafe"
1142 .span_label(sp, "negative because of this")
1143 .span_label(span, "unsafe because of this")
1147 this.visit_vis(&item.vis);
1148 this.visit_ident(item.ident);
1149 if let Const::Yes(_) = constness {
1150 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1152 this.visit_generics(generics);
1154 this.visit_trait_ref(t);
1155 this.visit_ty(self_ty);
1157 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1159 return; // Avoid visiting again.
1161 ItemKind::Impl(box Impl {
1171 let error = |annotation_span, annotation| {
1172 let mut err = self.err_handler().struct_span_err(
1174 &format!("inherent impls cannot be {}", annotation),
1176 err.span_label(annotation_span, &format!("{} because of this", annotation));
1177 err.span_label(self_ty.span, "inherent impl for this type");
1181 self.invalid_visibility(
1183 Some("place qualifiers on individual impl items instead"),
1185 if let Unsafe::Yes(span) = unsafety {
1186 error(span, "unsafe").code(error_code!(E0197)).emit();
1188 if let ImplPolarity::Negative(span) = polarity {
1189 error(span, "negative").emit();
1191 if let Defaultness::Default(def_span) = defaultness {
1192 error(def_span, "`default`")
1193 .note("only trait implementations may be annotated with `default`")
1196 if let Const::Yes(span) = constness {
1197 error(span, "`const`")
1198 .note("only trait implementations may be annotated with `const`")
1202 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1203 self.check_defaultness(item.span, defaultness);
1206 let msg = "free function without a body";
1207 let ext = sig.header.ext;
1209 let f = |e: &mut DiagnosticBuilder<'_, _>| {
1210 if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
1212 let start_suggestion = if let Extern::Explicit(abi, _) = ext {
1213 format!("extern \"{}\" {{", abi.symbol_unescaped)
1215 "extern {".to_owned()
1218 let end_suggestion = " }".to_owned();
1219 let end_span = item.span.shrink_to_hi();
1222 .multipart_suggestion(
1223 "if you meant to declare an externally defined function, use an `extern` block",
1224 vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
1225 Applicability::MaybeIncorrect,
1230 self.error_item_without_body_with_help(
1239 self.visit_vis(&item.vis);
1240 self.visit_ident(item.ident);
1242 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1243 self.visit_fn(kind, item.span, item.id);
1244 walk_list!(self, visit_attribute, &item.attrs);
1245 return; // Avoid visiting again.
1247 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1248 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1249 self.invalid_visibility(
1251 Some("place qualifiers on individual foreign items instead"),
1253 if let Unsafe::Yes(span) = unsafety {
1254 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1257 self.maybe_lint_missing_abi(item.span, item.id);
1259 visit::walk_item(self, item);
1260 self.extern_mod = old_item;
1261 return; // Avoid visiting again.
1263 ItemKind::Enum(ref def, _) => {
1264 for variant in &def.variants {
1265 self.invalid_visibility(&variant.vis, None);
1266 for field in variant.data.fields() {
1267 self.invalid_visibility(&field.vis, None);
1271 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1272 if is_auto == IsAuto::Yes {
1273 // Auto traits cannot have generics, super traits nor contain items.
1274 self.deny_generic_params(generics, item.ident.span);
1275 self.deny_super_traits(bounds, item.ident.span);
1276 self.deny_where_clause(&generics.where_clause, item.ident.span);
1277 self.deny_items(items, item.ident.span);
1280 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1281 // context for the supertraits.
1282 self.visit_vis(&item.vis);
1283 self.visit_ident(item.ident);
1284 self.visit_generics(generics);
1285 self.with_banned_tilde_const(|this| {
1286 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1288 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1289 walk_list!(self, visit_attribute, &item.attrs);
1292 ItemKind::Mod(unsafety, ref mod_kind) => {
1293 if let Unsafe::Yes(span) = unsafety {
1294 self.err_handler().span_err(span, "module cannot be declared unsafe");
1296 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1297 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1298 && !self.session.contains_name(&item.attrs, sym::path)
1300 self.check_mod_file_item_asciionly(item.ident);
1303 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1304 // Duplicating the `Visitor` logic allows catching all cases
1305 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1307 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1308 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1309 // it uses `visit_ty_common`, which doesn't contain that specific check.
1310 VariantData::Struct(ref fields, ..) => {
1311 self.visit_vis(&item.vis);
1312 self.visit_ident(item.ident);
1313 self.visit_generics(generics);
1314 self.with_banned_assoc_ty_bound(|this| {
1315 walk_list!(this, visit_struct_field_def, fields);
1317 walk_list!(self, visit_attribute, &item.attrs);
1322 ItemKind::Union(ref vdata, ref generics) => {
1323 if vdata.fields().is_empty() {
1324 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1327 VariantData::Struct(ref fields, ..) => {
1328 self.visit_vis(&item.vis);
1329 self.visit_ident(item.ident);
1330 self.visit_generics(generics);
1331 self.with_banned_assoc_ty_bound(|this| {
1332 walk_list!(this, visit_struct_field_def, fields);
1334 walk_list!(self, visit_attribute, &item.attrs);
1340 ItemKind::Const(def, .., None) => {
1341 self.check_defaultness(item.span, def);
1342 let msg = "free constant item without body";
1343 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1345 ItemKind::Static(.., None) => {
1346 let msg = "free static item without body";
1347 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1349 ItemKind::TyAlias(box TyAlias {
1356 self.check_defaultness(item.span, defaultness);
1358 let msg = "free type alias without body";
1359 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1361 self.check_type_no_bounds(bounds, "this context");
1362 if where_clauses.1.0 {
1363 let mut err = self.err_handler().struct_span_err(
1365 "where clauses are not allowed after the type for type aliases",
1368 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1376 visit::walk_item(self, item);
1379 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1381 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1382 self.check_defaultness(fi.span, *defaultness);
1383 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1384 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1385 self.check_foreign_item_ascii_only(fi.ident);
1387 ForeignItemKind::TyAlias(box TyAlias {
1395 self.check_defaultness(fi.span, *defaultness);
1396 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1397 self.check_type_no_bounds(bounds, "`extern` blocks");
1398 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1399 self.check_foreign_item_ascii_only(fi.ident);
1401 ForeignItemKind::Static(_, _, body) => {
1402 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1403 self.check_foreign_item_ascii_only(fi.ident);
1405 ForeignItemKind::MacCall(..) => {}
1408 visit::walk_foreign_item(self, fi)
1411 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1412 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1413 match *generic_args {
1414 GenericArgs::AngleBracketed(ref data) => {
1415 self.check_generic_args_before_constraints(data);
1417 for arg in &data.args {
1419 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1420 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1421 // are allowed to contain nested `impl Trait`.
1422 AngleBracketedArg::Constraint(constraint) => {
1423 self.with_impl_trait(None, |this| {
1424 this.visit_assoc_constraint_from_generic_args(constraint);
1430 GenericArgs::Parenthesized(ref data) => {
1431 walk_list!(self, visit_ty, &data.inputs);
1432 if let FnRetTy::Ty(ty) = &data.output {
1433 // `-> Foo` syntax is essentially an associated type binding,
1434 // so it is also allowed to contain nested `impl Trait`.
1435 self.with_impl_trait(None, |this| this.visit_ty(ty));
1441 fn visit_generics(&mut self, generics: &'a Generics) {
1442 let mut prev_param_default = None;
1443 for param in &generics.params {
1445 GenericParamKind::Lifetime => (),
1446 GenericParamKind::Type { default: Some(_), .. }
1447 | GenericParamKind::Const { default: Some(_), .. } => {
1448 prev_param_default = Some(param.ident.span);
1450 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1451 if let Some(span) = prev_param_default {
1452 let mut err = self.err_handler().struct_span_err(
1454 "generic parameters with a default must be trailing",
1463 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1465 for predicate in &generics.where_clause.predicates {
1466 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1467 deny_equality_constraints(self, predicate, generics);
1470 walk_list!(self, visit_generic_param, &generics.params);
1471 for predicate in &generics.where_clause.predicates {
1473 WherePredicate::BoundPredicate(bound_pred) => {
1474 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1475 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1477 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1478 // binder and thus we only allow a single level of quantification. However,
1479 // the syntax of Rust permits quantification in two places in where clauses,
1480 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1481 // defined, then error.
1482 if !bound_pred.bound_generic_params.is_empty() {
1483 for bound in &bound_pred.bounds {
1485 GenericBound::Trait(t, _) => {
1486 if !t.bound_generic_params.is_empty() {
1491 "nested quantification of lifetimes"
1496 GenericBound::Outlives(_) => {}
1503 self.visit_where_predicate(predicate);
1507 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1508 if let GenericParamKind::Lifetime { .. } = param.kind {
1509 self.check_lifetime(param.ident);
1511 visit::walk_generic_param(self, param);
1514 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1515 if let GenericBound::Trait(ref poly, modify) = *bound {
1516 match (ctxt, modify) {
1517 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1520 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1521 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1522 err.note(&format!("traits are `?{}` by default", path_str));
1525 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1526 let mut err = self.err_handler().struct_span_err(
1528 "`?Trait` is not permitted in trait object types",
1532 (_, TraitBoundModifier::MaybeConst) => {
1533 if !self.is_tilde_const_allowed {
1535 .struct_span_err(bound.span(), "`~const` is not allowed here")
1536 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1540 (_, TraitBoundModifier::MaybeConstMaybe) => {
1542 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1548 visit::walk_param_bound(self, bound)
1551 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1552 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1553 visit::walk_poly_trait_ref(self, t, m);
1556 fn visit_variant_data(&mut self, s: &'a VariantData) {
1557 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1562 enum_definition: &'a EnumDef,
1563 generics: &'a Generics,
1567 self.with_banned_assoc_ty_bound(|this| {
1568 visit::walk_enum_def(this, enum_definition, generics, item_id)
1572 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1573 // Only associated `fn`s can have `self` parameters.
1574 let self_semantic = match fk.ctxt() {
1575 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1576 _ => SelfSemantic::No,
1578 self.check_fn_decl(fk.decl(), self_semantic);
1580 self.check_c_variadic_type(fk);
1582 // Functions cannot both be `const async`
1583 if let Some(FnHeader {
1584 constness: Const::Yes(cspan),
1585 asyncness: Async::Yes { span: aspan, .. },
1591 vec![*cspan, *aspan],
1592 "functions cannot be both `const` and `async`",
1594 .span_label(*cspan, "`const` because of this")
1595 .span_label(*aspan, "`async` because of this")
1596 .span_label(span, "") // Point at the fn header.
1603 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1609 self.maybe_lint_missing_abi(*sig_span, id);
1612 // Functions without bodies cannot have patterns.
1613 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1614 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1615 let (code, msg, label) = match ctxt {
1616 FnCtxt::Foreign => (
1618 "patterns aren't allowed in foreign function declarations",
1619 "pattern not allowed in foreign function",
1623 "patterns aren't allowed in functions without bodies",
1624 "pattern not allowed in function without body",
1627 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1628 if let Some(ident) = ident {
1629 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1630 self.lint_buffer.buffer_lint_with_diagnostic(
1631 PATTERNS_IN_FNS_WITHOUT_BODY,
1640 .struct_span_err(span, msg)
1641 .span_label(span, label)
1648 let tilde_const_allowed =
1649 matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1650 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1652 self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
1655 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1656 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1657 self.check_nomangle_item_asciionly(item.ident, item.span);
1660 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1661 self.check_defaultness(item.span, item.kind.defaultness());
1664 if ctxt == AssocCtxt::Impl {
1666 AssocItemKind::Const(_, _, body) => {
1667 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1669 AssocItemKind::Fn(box Fn { body, .. }) => {
1670 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1672 AssocItemKind::TyAlias(box TyAlias {
1675 where_predicates_split,
1680 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1681 self.check_type_no_bounds(bounds, "`impl`s");
1683 self.check_gat_where(
1685 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1694 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1695 self.invalid_visibility(&item.vis, None);
1696 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1697 self.check_trait_fn_not_const(sig.header.constness);
1698 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1702 if let AssocItemKind::Const(..) = item.kind {
1703 self.check_item_named(item.ident, "const");
1707 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1708 if ctxt == AssocCtxt::Trait =>
1710 self.visit_vis(&item.vis);
1711 self.visit_ident(item.ident);
1712 walk_list!(self, visit_attribute, &item.attrs);
1713 self.with_tilde_const_allowed(|this| {
1714 this.visit_generics(generics);
1715 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1717 walk_list!(self, visit_ty, ty);
1719 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1720 if self.in_const_trait_impl
1721 || ctxt == AssocCtxt::Trait
1722 || matches!(sig.header.constness, Const::Yes(_)) =>
1724 self.visit_vis(&item.vis);
1725 self.visit_ident(item.ident);
1726 let kind = FnKind::Fn(
1727 FnCtxt::Assoc(ctxt),
1734 self.visit_fn(kind, item.span, item.id);
1737 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1742 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1743 /// like it's setting an associated type, provide an appropriate suggestion.
1744 fn deny_equality_constraints(
1745 this: &mut AstValidator<'_>,
1746 predicate: &WhereEqPredicate,
1747 generics: &Generics,
1749 let mut err = this.err_handler().struct_span_err(
1751 "equality constraints are not yet supported in `where` clauses",
1753 err.span_label(predicate.span, "not supported");
1755 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1756 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1757 if let TyKind::Path(None, path) = &qself.ty.kind {
1758 match &path.segments[..] {
1759 [PathSegment { ident, args: None, .. }] => {
1760 for param in &generics.params {
1761 if param.ident == *ident {
1763 match &full_path.segments[qself.position..] {
1764 [PathSegment { ident, args, .. }] => {
1765 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1766 let mut assoc_path = full_path.clone();
1767 // Remove `Bar` from `Foo::Bar`.
1768 assoc_path.segments.pop();
1769 let len = assoc_path.segments.len() - 1;
1770 let gen_args = args.as_ref().map(|p| (**p).clone());
1771 // Build `<Bar = RhsTy>`.
1772 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1773 id: rustc_ast::node_id::DUMMY_NODE_ID,
1776 kind: AssocConstraintKind::Equality {
1777 term: predicate.rhs_ty.clone().into(),
1781 // Add `<Bar = RhsTy>` to `Foo`.
1782 match &mut assoc_path.segments[len].args {
1783 Some(args) => match args.deref_mut() {
1784 GenericArgs::Parenthesized(_) => continue,
1785 GenericArgs::AngleBracketed(args) => {
1786 args.args.push(arg);
1790 *empty_args = AngleBracketedArgs {
1797 err.span_suggestion_verbose(
1800 "if `{}` is an associated type you're trying to set, \
1801 use the associated type binding syntax",
1807 pprust::path_to_string(&assoc_path)
1809 Applicability::MaybeIncorrect,
1821 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1822 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1823 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1824 for param in &generics.params {
1825 if param.ident == potential_param.ident {
1826 for bound in ¶m.bounds {
1827 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1829 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1830 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1831 potential_assoc.ident,
1833 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1834 let (args, span) = match &trait_segment.args {
1835 Some(args) => match args.deref() {
1836 ast::GenericArgs::AngleBracketed(args) => {
1837 let Some(arg) = args.args.last() else {
1841 format!(", {} = {}", assoc, ty),
1842 arg.span().shrink_to_hi(),
1848 format!("<{} = {}>", assoc, ty),
1849 trait_segment.span().shrink_to_hi(),
1852 err.multipart_suggestion(
1854 "if `{}::{}` is an associated type you're trying to set, \
1855 use the associated type binding syntax",
1856 trait_segment.ident, potential_assoc.ident,
1858 vec![(span, args), (predicate.span, String::new())],
1859 Applicability::MaybeIncorrect,
1869 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1874 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1875 let mut validator = AstValidator {
1878 in_trait_impl: false,
1879 in_const_trait_impl: false,
1880 has_proc_macro_decls: false,
1881 outer_impl_trait: None,
1882 is_tilde_const_allowed: false,
1883 is_impl_trait_banned: false,
1884 is_assoc_ty_bound_banned: false,
1885 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1888 visit::walk_crate(&mut validator, krate);
1890 validator.has_proc_macro_decls
1893 /// Used to forbid `let` expressions in certain syntactic locations.
1894 #[derive(Clone, Copy)]
1895 enum ForbiddenLetReason {
1896 /// `let` is not valid and the source environment is not important
1898 /// A let chain with the `||` operator
1899 NotSupportedOr(Span),
1900 /// A let chain with invalid parentheses
1902 /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
1903 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1904 NotSupportedParentheses(Span),