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, pluralize, struct_span_err, Applicability, Diagnostic};
17 use rustc_parse::validate_attr;
18 use rustc_session::lint::builtin::{
19 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
21 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
22 use rustc_session::Session;
23 use rustc_span::source_map::Spanned;
24 use rustc_span::symbol::{kw, sym, Ident};
26 use rustc_target::spec::abi;
28 use std::ops::{Deref, DerefMut};
30 const MORE_EXTERN: &str =
31 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
33 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
39 struct AstValidator<'a> {
42 /// The span of the `extern` in an `extern { ... }` block, if any.
43 extern_mod: Option<&'a Item>,
45 /// Are we inside a trait impl?
48 in_const_trait_impl: bool,
50 has_proc_macro_decls: bool,
52 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
53 /// Nested `impl Trait` _is_ allowed in associated type position,
54 /// e.g., `impl Iterator<Item = impl Debug>`.
55 outer_impl_trait: Option<Span>,
57 is_tilde_const_allowed: bool,
59 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
60 /// or `Foo::Bar<impl Trait>`
61 is_impl_trait_banned: bool,
63 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
64 /// certain positions.
65 is_assoc_ty_bound_banned: bool,
67 /// See [ForbiddenLetReason]
68 forbidden_let_reason: Option<ForbiddenLetReason>,
70 lint_buffer: &'a mut LintBuffer,
73 impl<'a> AstValidator<'a> {
74 fn with_in_trait_impl(
77 constness: Option<Const>,
78 f: impl FnOnce(&mut Self),
80 let old = mem::replace(&mut self.in_trait_impl, is_in);
82 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
84 self.in_trait_impl = old;
85 self.in_const_trait_impl = old_const;
88 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
89 let old = mem::replace(&mut self.is_impl_trait_banned, true);
91 self.is_impl_trait_banned = old;
94 fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
95 let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
97 self.is_tilde_const_allowed = old;
100 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
101 self.with_tilde_const(true, f)
104 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
105 self.with_tilde_const(false, f)
108 fn with_let_management(
110 forbidden_let_reason: Option<ForbiddenLetReason>,
111 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
113 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
115 self.forbidden_let_reason = old;
118 /// Emits an error banning the `let` expression provided in the given location.
119 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
120 let err = "`let` expressions are not supported here";
121 let mut diag = self.session.struct_span_err(expr.span, err);
122 diag.note("only supported directly in conditions of `if` and `while` expressions");
123 match forbidden_let_reason {
124 ForbiddenLetReason::GenericForbidden => {}
125 ForbiddenLetReason::NotSupportedOr(span) => {
126 diag.span_note(span, "`||` operators are not supported in let chain expressions");
128 ForbiddenLetReason::NotSupportedParentheses(span) => {
131 "`let`s wrapped in parentheses are not supported in a context with let \
142 before_predicates: &[WherePredicate],
143 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
145 if !before_predicates.is_empty() {
146 let mut state = State::new();
147 if !where_clauses.1.0 {
149 state.word_space("where");
151 state.word_space(",");
153 let mut first = true;
154 for p in before_predicates.iter() {
156 state.word_space(",");
159 state.print_where_predicate(p);
161 let suggestion = state.s.eof();
162 self.lint_buffer.buffer_lint_with_diagnostic(
163 DEPRECATED_WHERE_CLAUSE_LOCATION,
166 "where clause not allowed here",
167 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
168 where_clauses.1.1.shrink_to_hi(),
175 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
176 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
178 self.is_assoc_ty_bound_banned = old;
181 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
182 let old = mem::replace(&mut self.outer_impl_trait, outer);
184 self.with_banned_tilde_const(f);
188 self.outer_impl_trait = old;
191 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
192 match constraint.kind {
193 AssocConstraintKind::Equality { .. } => {}
194 AssocConstraintKind::Bound { .. } => {
195 if self.is_assoc_ty_bound_banned {
196 self.err_handler().span_err(
198 "associated type bounds are not allowed within structs, enums, or unions",
203 self.visit_assoc_constraint(constraint);
206 // Mirrors `visit::walk_ty`, but tracks relevant state.
207 fn walk_ty(&mut self, t: &'a Ty) {
209 TyKind::ImplTrait(..) => {
210 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
212 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
213 TyKind::Path(ref qself, ref path) => {
215 // - `Option<impl Trait>`
216 // - `option::Option<impl Trait>`
217 // - `option::Option<T>::Foo<impl Trait>
220 // - `<impl Trait>::Foo`
221 // - `option::Option<impl Trait>::Foo`.
223 // To implement this, we disallow `impl Trait` from `qself`
224 // (for cases like `<impl Trait>::Foo>`)
225 // but we allow `impl Trait` in `GenericArgs`
226 // iff there are no more PathSegments.
227 if let Some(ref qself) = *qself {
228 // `impl Trait` in `qself` is always illegal
229 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
232 // Note that there should be a call to visit_path here,
233 // so if any logic is added to process `Path`s a call to it should be
234 // added both in visit_path and here. This code mirrors visit::walk_path.
235 for (i, segment) in path.segments.iter().enumerate() {
236 // Allow `impl Trait` iff we're on the final path segment
237 if i == path.segments.len() - 1 {
238 self.visit_path_segment(path.span, segment);
240 self.with_banned_impl_trait(|this| {
241 this.visit_path_segment(path.span, segment)
246 _ => visit::walk_ty(self, t),
250 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
251 if let Some(ident) = field.ident {
252 if ident.name == kw::Underscore {
253 self.visit_vis(&field.vis);
254 self.visit_ident(ident);
255 self.visit_ty_common(&field.ty);
256 self.walk_ty(&field.ty);
257 walk_list!(self, visit_attribute, &field.attrs);
261 self.visit_field_def(field);
264 fn err_handler(&self) -> &rustc_errors::Handler {
265 &self.session.diagnostic()
268 fn check_lifetime(&self, ident: Ident) {
269 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
270 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
271 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
275 fn check_label(&self, ident: Ident) {
276 if ident.without_first_quote().is_reserved() {
278 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
282 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
283 if let VisibilityKind::Inherited = vis.kind {
288 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
289 if vis.kind.is_pub() {
290 err.span_label(vis.span, "`pub` not permitted here because it's implied");
292 if let Some(note) = note {
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(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
302 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
303 report_err(pat.span, Some(ident), true)
305 _ => report_err(pat.span, None, false),
310 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
311 if let Async::Yes { span, .. } = asyncness {
316 "functions in traits cannot be declared `async`"
318 .span_label(span, "`async` because of this")
319 .note("`async` trait functions are not currently supported")
320 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
325 fn check_trait_fn_not_const(&self, constness: Const) {
326 if let Const::Yes(span) = constness {
331 "functions in traits cannot be declared const"
333 .span_label(span, "functions in traits cannot be const")
338 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
339 // Check only lifetime parameters are present and that the lifetime
340 // parameters that are present have no bounds.
341 let non_lt_param_spans: Vec<_> = params
343 .filter_map(|param| match param.kind {
344 GenericParamKind::Lifetime { .. } => {
345 if !param.bounds.is_empty() {
346 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
348 .span_err(spans, "lifetime bounds cannot be used in this context");
352 _ => Some(param.ident.span),
355 if !non_lt_param_spans.is_empty() {
356 self.err_handler().span_err(
358 "only lifetime parameters can be used in this context",
363 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
364 self.check_decl_num_args(fn_decl);
365 self.check_decl_cvaradic_pos(fn_decl);
366 self.check_decl_attrs(fn_decl);
367 self.check_decl_self_param(fn_decl, self_semantic);
370 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
371 /// Error is fatal to prevent errors during typechecking
372 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
373 let max_num_args: usize = u16::MAX.into();
374 if fn_decl.inputs.len() > max_num_args {
375 let Param { span, .. } = fn_decl.inputs[0];
376 self.err_handler().span_fatal(
378 &format!("function can not have more than {} arguments", max_num_args),
383 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
384 match &*fn_decl.inputs {
385 [Param { ty, span, .. }] => {
386 if let TyKind::CVarArgs = ty.kind {
387 self.err_handler().span_err(
389 "C-variadic function must be declared with at least one named argument",
394 for Param { ty, span, .. } in ps {
395 if let TyKind::CVarArgs = ty.kind {
396 self.err_handler().span_err(
398 "`...` must be the last argument of a C-variadic function",
407 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
411 .flat_map(|i| i.attrs.as_ref())
422 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
425 if attr.is_doc_comment() {
429 "documentation comments cannot be applied to function parameters",
431 .span_label(attr.span, "doc comments are not allowed here")
434 self.err_handler().span_err(
436 "allow, cfg, cfg_attr, deny, expect, \
437 forbid, and warn are the only allowed built-in attributes in function parameters",
443 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
444 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
449 "`self` parameter is only allowed in associated functions",
451 .span_label(param.span, "not semantically valid as function parameter")
452 .note("associated functions are those in `impl` or `trait` definitions")
458 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
459 if let Defaultness::Default(def_span) = defaultness {
460 let span = self.session.source_map().guess_head_span(span);
462 .struct_span_err(span, "`default` is only allowed on items in trait impls")
463 .span_label(def_span, "`default` because of this")
468 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
469 self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
472 fn error_item_without_body_with_help(
478 help: impl FnOnce(&mut Diagnostic),
480 let source_map = self.session.source_map();
481 let end = source_map.end_point(sp);
482 let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
487 let mut err = self.err_handler().struct_span_err(sp, msg);
490 &format!("provide a definition for the {}", ctx),
492 Applicability::HasPlaceholders,
498 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
500 let msg = format!("associated {} in `impl` without body", ctx);
501 self.error_item_without_body(sp, ctx, &msg, sugg);
505 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
506 let span = match bounds {
509 [b0, .., bl] => b0.span().to(bl.span()),
512 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
516 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
517 let cannot_have = |span, descr, remove_descr| {
521 &format!("`type`s inside `extern` blocks cannot have {}", descr),
525 &format!("remove the {}", remove_descr),
527 Applicability::MaybeIncorrect,
529 .span_label(self.current_extern_span(), "`extern` block begins here")
534 if !generics.params.is_empty() {
535 cannot_have(generics.span, "generic parameters", "generic parameters");
538 if !generics.where_clause.predicates.is_empty() {
539 cannot_have(where_span, "`where` clauses", "`where` clause");
543 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
544 let Some(body) = body else {
548 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
549 .span_label(ident.span, "cannot have a body")
550 .span_label(body, "the invalid body")
552 self.current_extern_span(),
554 "`extern` blocks define existing foreign {0}s and {0}s \
555 inside of them cannot have a body",
563 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
564 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
565 let Some(body) = body else {
569 .struct_span_err(ident.span, "incorrect function inside `extern` block")
570 .span_label(ident.span, "cannot have a body")
573 "remove the invalid body",
575 Applicability::MaybeIncorrect,
578 "you might have meant to write a function accessible through FFI, \
579 which can be done by writing `extern fn` outside of the `extern` block",
582 self.current_extern_span(),
583 "`extern` blocks define existing foreign functions and functions \
584 inside of them cannot have a body",
590 fn current_extern_span(&self) -> Span {
591 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
594 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
595 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
596 if header.has_qualifiers() {
598 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
599 .span_label(self.current_extern_span(), "in this `extern` block")
600 .span_suggestion_verbose(
601 span.until(ident.span.shrink_to_lo()),
602 "remove the qualifiers",
604 Applicability::MaybeIncorrect,
610 /// An item in `extern { ... }` cannot use non-ascii identifier.
611 fn check_foreign_item_ascii_only(&self, ident: Ident) {
612 if !ident.as_str().is_ascii() {
617 "items in `extern` blocks cannot use non-ascii identifiers",
619 .span_label(self.current_extern_span(), "in this `extern` block")
621 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
628 /// Reject C-variadic type unless the function is foreign,
629 /// or free and `unsafe extern "C"` semantically.
630 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
631 match (fk.ctxt(), fk.header()) {
632 (Some(FnCtxt::Foreign), _) => return,
633 (Some(FnCtxt::Free), Some(header)) => match header.ext {
634 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
635 | Extern::Implicit(_)
636 if matches!(header.unsafety, Unsafe::Yes(_)) =>
645 for Param { ty, span, .. } in &fk.decl().inputs {
646 if let TyKind::CVarArgs = ty.kind {
650 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
657 fn check_item_named(&self, ident: Ident, kind: &str) {
658 if ident.name != kw::Underscore {
662 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
663 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
667 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
668 if ident.name.as_str().is_ascii() {
671 let head_span = self.session.source_map().guess_head_span(item_span);
676 "`#[no_mangle]` requires ASCII identifier"
681 fn check_mod_file_item_asciionly(&self, ident: Ident) {
682 if ident.name.as_str().is_ascii() {
689 "trying to load file for module `{}` with non-ascii identifier name",
692 .help("consider using `#[path]` attribute to specify filesystem path")
696 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
697 if !generics.params.is_empty() {
702 "auto traits cannot have generic parameters"
704 .span_label(ident_span, "auto trait cannot have generic parameters")
707 "remove the parameters",
709 Applicability::MachineApplicable,
715 fn emit_e0568(&self, span: Span, ident_span: Span) {
720 "auto traits cannot have super traits or lifetime bounds"
722 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
725 "remove the super traits or lifetime bounds",
727 Applicability::MachineApplicable,
732 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
733 if let [.., last] = &bounds[..] {
734 let span = ident_span.shrink_to_hi().to(last.span());
735 self.emit_e0568(span, ident_span);
739 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
740 if !where_clause.predicates.is_empty() {
741 self.emit_e0568(where_clause.span, ident_span);
745 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
746 if !trait_items.is_empty() {
747 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
748 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
753 "auto traits cannot have associated items"
757 "remove these associated items",
759 Applicability::MachineApplicable,
761 .span_label(ident_span, "auto trait cannot have associated items")
766 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
767 // Lifetimes always come first.
768 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
769 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
770 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
774 let args_sugg = data.args.iter().filter_map(|a| match a {
775 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
778 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
780 // Constraints always come last.
781 let constraint_sugg = data.args.iter().filter_map(|a| match a {
782 AngleBracketedArg::Arg(_) => None,
783 AngleBracketedArg::Constraint(c) => {
784 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
789 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
793 /// Enforce generic args coming before constraints in `<...>` of a path segment.
794 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
795 // Early exit in case it's partitioned as it should be.
796 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
799 // Find all generic argument coming after the first constraint...
800 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
801 data.args.iter().partition_map(|arg| match arg {
802 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
803 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
805 let args_len = arg_spans.len();
806 let constraint_len = constraint_spans.len();
807 // ...and then error:
811 "generic arguments must come before the first constraint",
813 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
815 *arg_spans.iter().last().unwrap(),
816 &format!("generic argument{}", pluralize!(args_len)),
818 .span_labels(constraint_spans, "")
819 .span_labels(arg_spans, "")
820 .span_suggestion_verbose(
823 "move the constraint{} after the generic argument{}",
824 pluralize!(constraint_len),
827 self.correct_generic_order_suggestion(&data),
828 Applicability::MachineApplicable,
833 fn visit_ty_common(&mut self, ty: &'a Ty) {
835 TyKind::BareFn(ref bfty) => {
836 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
837 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
842 "patterns aren't allowed in function pointer types"
846 self.check_late_bound_lifetime_defs(&bfty.generic_params);
847 if let Extern::Implicit(_) = bfty.ext {
848 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
849 self.maybe_lint_missing_abi(sig_span, ty.id);
852 TyKind::TraitObject(ref bounds, ..) => {
853 let mut any_lifetime_bounds = false;
854 for bound in bounds {
855 if let GenericBound::Outlives(ref lifetime) = *bound {
856 if any_lifetime_bounds {
861 "only a single explicit lifetime bound is permitted"
866 any_lifetime_bounds = true;
870 TyKind::ImplTrait(_, ref bounds) => {
871 if self.is_impl_trait_banned {
876 "`impl Trait` is not allowed in path parameters"
881 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
886 "nested `impl Trait` is not allowed"
888 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
889 .span_label(ty.span, "nested `impl Trait` here")
893 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
894 self.err_handler().span_err(ty.span, "at least one trait must be specified");
901 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
902 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
903 // call site which do not have a macro backtrace. See #61963.
904 let is_macro_callsite = self
907 .span_to_snippet(span)
908 .map(|snippet| snippet.starts_with("#["))
910 if !is_macro_callsite {
911 self.lint_buffer.buffer_lint_with_diagnostic(
915 "extern declarations without an explicit ABI are deprecated",
916 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
922 /// Checks that generic parameters are in the correct order,
923 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
924 fn validate_generic_param_order(
925 handler: &rustc_errors::Handler,
926 generics: &[GenericParam],
929 let mut max_param: Option<ParamKindOrd> = None;
930 let mut out_of_order = FxHashMap::default();
931 let mut param_idents = Vec::with_capacity(generics.len());
933 for (idx, param) in generics.iter().enumerate() {
934 let ident = param.ident;
935 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
936 let (ord_kind, ident) = match ¶m.kind {
937 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
938 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
939 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
940 let ty = pprust::ty_to_string(ty);
941 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
944 param_idents.push((kind, ord_kind, bounds, idx, ident));
946 Some(max_param) if max_param > ord_kind => {
947 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
950 Some(_) | None => max_param = Some(ord_kind),
954 if !out_of_order.is_empty() {
955 let mut ordered_params = "<".to_string();
956 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
957 let mut first = true;
958 for (kind, _, bounds, _, ident) in param_idents {
960 ordered_params += ", ";
962 ordered_params += &ident;
964 if !bounds.is_empty() {
965 ordered_params += ": ";
966 ordered_params += &pprust::bounds_to_string(&bounds);
970 GenericParamKind::Type { default: Some(default) } => {
971 ordered_params += " = ";
972 ordered_params += &pprust::ty_to_string(default);
974 GenericParamKind::Type { default: None } => (),
975 GenericParamKind::Lifetime => (),
976 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
977 ordered_params += " = ";
978 ordered_params += &pprust::expr_to_string(&*default.value);
980 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
985 ordered_params += ">";
987 for (param_ord, (max_param, spans)) in &out_of_order {
988 let mut err = handler.struct_span_err(
991 "{} parameters must be declared prior to {} parameters",
992 param_ord, max_param,
997 "reorder the parameters: lifetimes, then consts and types",
999 Applicability::MachineApplicable,
1006 impl<'a> Visitor<'a> for AstValidator<'a> {
1007 fn visit_attribute(&mut self, attr: &Attribute) {
1008 validate_attr::check_meta(&self.session.parse_sess, attr);
1011 fn visit_expr(&mut self, expr: &'a Expr) {
1012 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
1014 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
1015 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
1016 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
1017 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
1019 ExprKind::If(cond, then, opt_else) => {
1020 this.visit_block(then);
1021 walk_list!(this, visit_expr, opt_else);
1022 this.with_let_management(None, |this, _| this.visit_expr(cond));
1025 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
1026 this.ban_let_expr(expr, elem);
1028 ExprKind::Match(scrutinee, arms) => {
1029 this.visit_expr(scrutinee);
1031 this.visit_expr(&arm.body);
1032 this.visit_pat(&arm.pat);
1033 walk_list!(this, visit_attribute, &arm.attrs);
1034 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
1035 this.with_let_management(None, |this, _| {
1036 this.visit_expr(guard_expr)
1042 ExprKind::Paren(local_expr) => {
1043 fn has_let_expr(expr: &Expr) -> bool {
1045 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
1046 ExprKind::Let(..) => true,
1050 let local_reason = if has_let_expr(local_expr) {
1051 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
1054 forbidden_let_reason
1056 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
1058 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1059 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
1062 ExprKind::While(cond, then, opt_label) => {
1063 walk_list!(this, visit_label, opt_label);
1064 this.visit_block(then);
1065 this.with_let_management(None, |this, _| this.visit_expr(cond));
1068 _ => visit::walk_expr(this, expr),
1073 fn visit_ty(&mut self, ty: &'a Ty) {
1074 self.visit_ty_common(ty);
1078 fn visit_label(&mut self, label: &'a Label) {
1079 self.check_label(label.ident);
1080 visit::walk_label(self, label);
1083 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
1084 self.check_lifetime(lifetime.ident);
1085 visit::walk_lifetime(self, lifetime);
1088 fn visit_field_def(&mut self, s: &'a FieldDef) {
1089 visit::walk_field_def(self, s)
1092 fn visit_item(&mut self, item: &'a Item) {
1093 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1094 self.has_proc_macro_decls = true;
1097 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1098 self.check_nomangle_item_asciionly(item.ident, item.span);
1102 ItemKind::Impl(box Impl {
1108 of_trait: Some(ref t),
1112 self.with_in_trait_impl(true, Some(constness), |this| {
1113 this.invalid_visibility(&item.vis, None);
1114 if let TyKind::Err = self_ty.kind {
1118 "`impl Trait for .. {}` is an obsolete syntax",
1120 .help("use `auto trait Trait {}` instead")
1123 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1128 "negative impls cannot be unsafe"
1130 .span_label(sp, "negative because of this")
1131 .span_label(span, "unsafe because of this")
1135 this.visit_vis(&item.vis);
1136 this.visit_ident(item.ident);
1137 if let Const::Yes(_) = constness {
1138 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1140 this.visit_generics(generics);
1142 this.visit_trait_ref(t);
1143 this.visit_ty(self_ty);
1145 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1147 return; // Avoid visiting again.
1149 ItemKind::Impl(box Impl {
1159 let error = |annotation_span, annotation| {
1160 let mut err = self.err_handler().struct_span_err(
1162 &format!("inherent impls cannot be {}", annotation),
1164 err.span_label(annotation_span, &format!("{} because of this", annotation));
1165 err.span_label(self_ty.span, "inherent impl for this type");
1169 self.invalid_visibility(
1171 Some("place qualifiers on individual impl items instead"),
1173 if let Unsafe::Yes(span) = unsafety {
1174 error(span, "unsafe").code(error_code!(E0197)).emit();
1176 if let ImplPolarity::Negative(span) = polarity {
1177 error(span, "negative").emit();
1179 if let Defaultness::Default(def_span) = defaultness {
1180 error(def_span, "`default`")
1181 .note("only trait implementations may be annotated with `default`")
1184 if let Const::Yes(span) = constness {
1185 error(span, "`const`")
1186 .note("only trait implementations may be annotated with `const`")
1190 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1191 self.check_defaultness(item.span, defaultness);
1194 let msg = "free function without a body";
1195 let ext = sig.header.ext;
1197 let f = |e: &mut Diagnostic| {
1198 if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
1200 let start_suggestion = if let Extern::Explicit(abi, _) = ext {
1201 format!("extern \"{}\" {{", abi.symbol_unescaped)
1203 "extern {".to_owned()
1206 let end_suggestion = " }".to_owned();
1207 let end_span = item.span.shrink_to_hi();
1210 .multipart_suggestion(
1211 "if you meant to declare an externally defined function, use an `extern` block",
1212 vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
1213 Applicability::MaybeIncorrect,
1218 self.error_item_without_body_with_help(
1227 self.visit_vis(&item.vis);
1228 self.visit_ident(item.ident);
1230 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1231 self.visit_fn(kind, item.span, item.id);
1232 walk_list!(self, visit_attribute, &item.attrs);
1233 return; // Avoid visiting again.
1235 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1236 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1237 self.invalid_visibility(
1239 Some("place qualifiers on individual foreign items instead"),
1241 if let Unsafe::Yes(span) = unsafety {
1242 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1245 self.maybe_lint_missing_abi(item.span, item.id);
1247 visit::walk_item(self, item);
1248 self.extern_mod = old_item;
1249 return; // Avoid visiting again.
1251 ItemKind::Enum(ref def, _) => {
1252 for variant in &def.variants {
1253 self.invalid_visibility(&variant.vis, None);
1254 for field in variant.data.fields() {
1255 self.invalid_visibility(&field.vis, None);
1259 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1260 if is_auto == IsAuto::Yes {
1261 // Auto traits cannot have generics, super traits nor contain items.
1262 self.deny_generic_params(generics, item.ident.span);
1263 self.deny_super_traits(bounds, item.ident.span);
1264 self.deny_where_clause(&generics.where_clause, item.ident.span);
1265 self.deny_items(items, item.ident.span);
1268 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1269 // context for the supertraits.
1270 self.visit_vis(&item.vis);
1271 self.visit_ident(item.ident);
1272 self.visit_generics(generics);
1273 self.with_tilde_const_allowed(|this| {
1274 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1276 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1277 walk_list!(self, visit_attribute, &item.attrs);
1280 ItemKind::Mod(unsafety, ref mod_kind) => {
1281 if let Unsafe::Yes(span) = unsafety {
1282 self.err_handler().span_err(span, "module cannot be declared unsafe");
1284 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1285 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1286 && !self.session.contains_name(&item.attrs, sym::path)
1288 self.check_mod_file_item_asciionly(item.ident);
1291 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1292 // Duplicating the `Visitor` logic allows catching all cases
1293 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1295 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1296 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1297 // it uses `visit_ty_common`, which doesn't contain that specific check.
1298 VariantData::Struct(ref fields, ..) => {
1299 self.visit_vis(&item.vis);
1300 self.visit_ident(item.ident);
1301 self.visit_generics(generics);
1302 self.with_banned_assoc_ty_bound(|this| {
1303 walk_list!(this, visit_struct_field_def, fields);
1305 walk_list!(self, visit_attribute, &item.attrs);
1310 ItemKind::Union(ref vdata, ref generics) => {
1311 if vdata.fields().is_empty() {
1312 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1315 VariantData::Struct(ref fields, ..) => {
1316 self.visit_vis(&item.vis);
1317 self.visit_ident(item.ident);
1318 self.visit_generics(generics);
1319 self.with_banned_assoc_ty_bound(|this| {
1320 walk_list!(this, visit_struct_field_def, fields);
1322 walk_list!(self, visit_attribute, &item.attrs);
1328 ItemKind::Const(def, .., None) => {
1329 self.check_defaultness(item.span, def);
1330 let msg = "free constant item without body";
1331 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1333 ItemKind::Static(.., None) => {
1334 let msg = "free static item without body";
1335 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1337 ItemKind::TyAlias(box TyAlias {
1344 self.check_defaultness(item.span, defaultness);
1346 let msg = "free type alias without body";
1347 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1349 self.check_type_no_bounds(bounds, "this context");
1350 if where_clauses.1.0 {
1351 let mut err = self.err_handler().struct_span_err(
1353 "where clauses are not allowed after the type for type aliases",
1356 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1364 visit::walk_item(self, item);
1367 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1369 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1370 self.check_defaultness(fi.span, *defaultness);
1371 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1372 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1373 self.check_foreign_item_ascii_only(fi.ident);
1375 ForeignItemKind::TyAlias(box TyAlias {
1383 self.check_defaultness(fi.span, *defaultness);
1384 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1385 self.check_type_no_bounds(bounds, "`extern` blocks");
1386 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1387 self.check_foreign_item_ascii_only(fi.ident);
1389 ForeignItemKind::Static(_, _, body) => {
1390 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1391 self.check_foreign_item_ascii_only(fi.ident);
1393 ForeignItemKind::MacCall(..) => {}
1396 visit::walk_foreign_item(self, fi)
1399 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1400 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1401 match *generic_args {
1402 GenericArgs::AngleBracketed(ref data) => {
1403 self.check_generic_args_before_constraints(data);
1405 for arg in &data.args {
1407 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1408 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1409 // are allowed to contain nested `impl Trait`.
1410 AngleBracketedArg::Constraint(constraint) => {
1411 self.with_impl_trait(None, |this| {
1412 this.visit_assoc_constraint_from_generic_args(constraint);
1418 GenericArgs::Parenthesized(ref data) => {
1419 walk_list!(self, visit_ty, &data.inputs);
1420 if let FnRetTy::Ty(ty) = &data.output {
1421 // `-> Foo` syntax is essentially an associated type binding,
1422 // so it is also allowed to contain nested `impl Trait`.
1423 self.with_impl_trait(None, |this| this.visit_ty(ty));
1429 fn visit_generics(&mut self, generics: &'a Generics) {
1430 let mut prev_param_default = None;
1431 for param in &generics.params {
1433 GenericParamKind::Lifetime => (),
1434 GenericParamKind::Type { default: Some(_), .. }
1435 | GenericParamKind::Const { default: Some(_), .. } => {
1436 prev_param_default = Some(param.ident.span);
1438 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1439 if let Some(span) = prev_param_default {
1440 let mut err = self.err_handler().struct_span_err(
1442 "generic parameters with a default must be trailing",
1451 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1453 for predicate in &generics.where_clause.predicates {
1454 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1455 deny_equality_constraints(self, predicate, generics);
1458 walk_list!(self, visit_generic_param, &generics.params);
1459 for predicate in &generics.where_clause.predicates {
1461 WherePredicate::BoundPredicate(bound_pred) => {
1462 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1463 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1465 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1466 // binder and thus we only allow a single level of quantification. However,
1467 // the syntax of Rust permits quantification in two places in where clauses,
1468 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1469 // defined, then error.
1470 if !bound_pred.bound_generic_params.is_empty() {
1471 for bound in &bound_pred.bounds {
1473 GenericBound::Trait(t, _) => {
1474 if !t.bound_generic_params.is_empty() {
1479 "nested quantification of lifetimes"
1484 GenericBound::Outlives(_) => {}
1491 self.visit_where_predicate(predicate);
1495 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1496 if let GenericParamKind::Lifetime { .. } = param.kind {
1497 self.check_lifetime(param.ident);
1499 visit::walk_generic_param(self, param);
1502 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1503 if let GenericBound::Trait(ref poly, modify) = *bound {
1504 match (ctxt, modify) {
1505 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1508 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1509 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1510 err.note(&format!("traits are `?{}` by default", path_str));
1513 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1514 let mut err = self.err_handler().struct_span_err(
1516 "`?Trait` is not permitted in trait object types",
1520 (_, TraitBoundModifier::MaybeConst) => {
1521 if !self.is_tilde_const_allowed {
1523 .struct_span_err(bound.span(), "`~const` is not allowed here")
1524 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1528 (_, TraitBoundModifier::MaybeConstMaybe) => {
1530 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1536 visit::walk_param_bound(self, bound)
1539 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1540 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1541 visit::walk_poly_trait_ref(self, t);
1544 fn visit_variant_data(&mut self, s: &'a VariantData) {
1545 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1548 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1549 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1552 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1553 // Only associated `fn`s can have `self` parameters.
1554 let self_semantic = match fk.ctxt() {
1555 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1556 _ => SelfSemantic::No,
1558 self.check_fn_decl(fk.decl(), self_semantic);
1560 self.check_c_variadic_type(fk);
1562 // Functions cannot both be `const async`
1563 if let Some(FnHeader {
1564 constness: Const::Yes(cspan),
1565 asyncness: Async::Yes { span: aspan, .. },
1571 vec![*cspan, *aspan],
1572 "functions cannot be both `const` and `async`",
1574 .span_label(*cspan, "`const` because of this")
1575 .span_label(*aspan, "`async` because of this")
1576 .span_label(span, "") // Point at the fn header.
1580 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1581 self.check_late_bound_lifetime_defs(generic_params);
1587 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1593 self.maybe_lint_missing_abi(*sig_span, id);
1596 // Functions without bodies cannot have patterns.
1597 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1598 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1599 let (code, msg, label) = match ctxt {
1600 FnCtxt::Foreign => (
1602 "patterns aren't allowed in foreign function declarations",
1603 "pattern not allowed in foreign function",
1607 "patterns aren't allowed in functions without bodies",
1608 "pattern not allowed in function without body",
1611 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1612 if let Some(ident) = ident {
1613 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1614 self.lint_buffer.buffer_lint_with_diagnostic(
1615 PATTERNS_IN_FNS_WITHOUT_BODY,
1624 .struct_span_err(span, msg)
1625 .span_label(span, label)
1632 let tilde_const_allowed =
1633 matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1634 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1636 self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
1639 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1640 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1641 self.check_nomangle_item_asciionly(item.ident, item.span);
1644 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1645 self.check_defaultness(item.span, item.kind.defaultness());
1648 if ctxt == AssocCtxt::Impl {
1650 AssocItemKind::Const(_, _, body) => {
1651 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1653 AssocItemKind::Fn(box Fn { body, .. }) => {
1654 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1656 AssocItemKind::TyAlias(box TyAlias {
1659 where_predicates_split,
1664 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1665 self.check_type_no_bounds(bounds, "`impl`s");
1667 self.check_gat_where(
1669 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1678 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1679 self.invalid_visibility(&item.vis, None);
1680 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1681 self.check_trait_fn_not_const(sig.header.constness);
1682 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1686 if let AssocItemKind::Const(..) = item.kind {
1687 self.check_item_named(item.ident, "const");
1691 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1692 if ctxt == AssocCtxt::Trait =>
1694 self.visit_vis(&item.vis);
1695 self.visit_ident(item.ident);
1696 walk_list!(self, visit_attribute, &item.attrs);
1697 self.with_tilde_const_allowed(|this| {
1698 this.visit_generics(generics);
1699 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1701 walk_list!(self, visit_ty, ty);
1703 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1704 if self.in_const_trait_impl
1705 || ctxt == AssocCtxt::Trait
1706 || matches!(sig.header.constness, Const::Yes(_)) =>
1708 self.visit_vis(&item.vis);
1709 self.visit_ident(item.ident);
1710 let kind = FnKind::Fn(
1711 FnCtxt::Assoc(ctxt),
1718 self.visit_fn(kind, item.span, item.id);
1721 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1726 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1727 /// like it's setting an associated type, provide an appropriate suggestion.
1728 fn deny_equality_constraints(
1729 this: &mut AstValidator<'_>,
1730 predicate: &WhereEqPredicate,
1731 generics: &Generics,
1733 let mut err = this.err_handler().struct_span_err(
1735 "equality constraints are not yet supported in `where` clauses",
1737 err.span_label(predicate.span, "not supported");
1739 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1740 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1741 if let TyKind::Path(None, path) = &qself.ty.kind {
1742 match &path.segments[..] {
1743 [PathSegment { ident, args: None, .. }] => {
1744 for param in &generics.params {
1745 if param.ident == *ident {
1747 match &full_path.segments[qself.position..] {
1748 [PathSegment { ident, args, .. }] => {
1749 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1750 let mut assoc_path = full_path.clone();
1751 // Remove `Bar` from `Foo::Bar`.
1752 assoc_path.segments.pop();
1753 let len = assoc_path.segments.len() - 1;
1754 let gen_args = args.as_ref().map(|p| (**p).clone());
1755 // Build `<Bar = RhsTy>`.
1756 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1757 id: rustc_ast::node_id::DUMMY_NODE_ID,
1760 kind: AssocConstraintKind::Equality {
1761 term: predicate.rhs_ty.clone().into(),
1765 // Add `<Bar = RhsTy>` to `Foo`.
1766 match &mut assoc_path.segments[len].args {
1767 Some(args) => match args.deref_mut() {
1768 GenericArgs::Parenthesized(_) => continue,
1769 GenericArgs::AngleBracketed(args) => {
1770 args.args.push(arg);
1774 *empty_args = AngleBracketedArgs {
1781 err.span_suggestion_verbose(
1784 "if `{}` is an associated type you're trying to set, \
1785 use the associated type binding syntax",
1791 pprust::path_to_string(&assoc_path)
1793 Applicability::MaybeIncorrect,
1805 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1806 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1807 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1808 for param in &generics.params {
1809 if param.ident == potential_param.ident {
1810 for bound in ¶m.bounds {
1811 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1813 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1814 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1815 potential_assoc.ident,
1817 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1818 let (args, span) = match &trait_segment.args {
1819 Some(args) => match args.deref() {
1820 ast::GenericArgs::AngleBracketed(args) => {
1821 let Some(arg) = args.args.last() else {
1825 format!(", {} = {}", assoc, ty),
1826 arg.span().shrink_to_hi(),
1832 format!("<{} = {}>", assoc, ty),
1833 trait_segment.span().shrink_to_hi(),
1836 err.multipart_suggestion(
1838 "if `{}::{}` is an associated type you're trying to set, \
1839 use the associated type binding syntax",
1840 trait_segment.ident, potential_assoc.ident,
1842 vec![(span, args), (predicate.span, String::new())],
1843 Applicability::MaybeIncorrect,
1853 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1858 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1859 let mut validator = AstValidator {
1862 in_trait_impl: false,
1863 in_const_trait_impl: false,
1864 has_proc_macro_decls: false,
1865 outer_impl_trait: None,
1866 is_tilde_const_allowed: false,
1867 is_impl_trait_banned: false,
1868 is_assoc_ty_bound_banned: false,
1869 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1872 visit::walk_crate(&mut validator, krate);
1874 validator.has_proc_macro_decls
1877 /// Used to forbid `let` expressions in certain syntactic locations.
1878 #[derive(Clone, Copy)]
1879 enum ForbiddenLetReason {
1880 /// `let` is not valid and the source environment is not important
1882 /// A let chain with the `||` operator
1883 NotSupportedOr(Span),
1884 /// A let chain with invalid parentheses
1886 /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
1887 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1888 NotSupportedParentheses(Span),