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 err = "`let` expressions are not supported here";
123 let mut diag = self.session.struct_span_err(expr.span, err);
124 diag.note("only supported directly in conditions of `if` and `while` expressions");
125 match forbidden_let_reason {
126 ForbiddenLetReason::GenericForbidden => {}
127 ForbiddenLetReason::NotSupportedOr(span) => {
128 diag.span_note(span, "`||` operators are not supported in let chain expressions");
130 ForbiddenLetReason::NotSupportedParentheses(span) => {
133 "`let`s wrapped in parentheses are not supported in a context with let \
144 before_predicates: &[WherePredicate],
145 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
147 if !before_predicates.is_empty() {
148 let mut state = State::new();
149 if !where_clauses.1.0 {
151 state.word_space("where");
153 state.word_space(",");
155 let mut first = true;
156 for p in before_predicates.iter() {
158 state.word_space(",");
161 state.print_where_predicate(p);
163 let suggestion = state.s.eof();
164 self.lint_buffer.buffer_lint_with_diagnostic(
165 DEPRECATED_WHERE_CLAUSE_LOCATION,
168 "where clause not allowed here",
169 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
170 where_clauses.1.1.shrink_to_hi(),
177 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
178 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
180 self.is_assoc_ty_bound_banned = old;
183 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
184 let old = mem::replace(&mut self.outer_impl_trait, outer);
186 self.with_banned_tilde_const(f);
190 self.outer_impl_trait = old;
193 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
194 match constraint.kind {
195 AssocConstraintKind::Equality { .. } => {}
196 AssocConstraintKind::Bound { .. } => {
197 if self.is_assoc_ty_bound_banned {
198 self.err_handler().span_err(
200 "associated type bounds are not allowed within structs, enums, or unions",
205 self.visit_assoc_constraint(constraint);
208 // Mirrors `visit::walk_ty`, but tracks relevant state.
209 fn walk_ty(&mut self, t: &'a Ty) {
211 TyKind::ImplTrait(..) => {
212 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
214 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
215 TyKind::Path(ref qself, ref path) => {
217 // - `Option<impl Trait>`
218 // - `option::Option<impl Trait>`
219 // - `option::Option<T>::Foo<impl Trait>
222 // - `<impl Trait>::Foo`
223 // - `option::Option<impl Trait>::Foo`.
225 // To implement this, we disallow `impl Trait` from `qself`
226 // (for cases like `<impl Trait>::Foo>`)
227 // but we allow `impl Trait` in `GenericArgs`
228 // iff there are no more PathSegments.
229 if let Some(ref qself) = *qself {
230 // `impl Trait` in `qself` is always illegal
231 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
234 // Note that there should be a call to visit_path here,
235 // so if any logic is added to process `Path`s a call to it should be
236 // added both in visit_path and here. This code mirrors visit::walk_path.
237 for (i, segment) in path.segments.iter().enumerate() {
238 // Allow `impl Trait` iff we're on the final path segment
239 if i == path.segments.len() - 1 {
240 self.visit_path_segment(path.span, segment);
242 self.with_banned_impl_trait(|this| {
243 this.visit_path_segment(path.span, segment)
248 _ => visit::walk_ty(self, t),
252 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
253 if let Some(ident) = field.ident {
254 if ident.name == kw::Underscore {
255 self.visit_vis(&field.vis);
256 self.visit_ident(ident);
257 self.visit_ty_common(&field.ty);
258 self.walk_ty(&field.ty);
259 walk_list!(self, visit_attribute, &field.attrs);
263 self.visit_field_def(field);
266 fn err_handler(&self) -> &rustc_errors::Handler {
267 &self.session.diagnostic()
270 fn check_lifetime(&self, ident: Ident) {
271 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
272 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
273 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
277 fn check_label(&self, ident: Ident) {
278 if ident.without_first_quote().is_reserved() {
280 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
284 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
285 if let VisibilityKind::Inherited = vis.kind {
290 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
291 if vis.kind.is_pub() {
292 err.span_label(vis.span, "`pub` not permitted here because it's implied");
294 if let Some(note) = note {
300 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
301 for Param { pat, .. } in &decl.inputs {
303 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
304 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
305 report_err(pat.span, Some(ident), true)
307 _ => report_err(pat.span, None, false),
312 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
313 if let Async::Yes { span, .. } = asyncness {
318 "functions in traits cannot be declared `async`"
320 .span_label(span, "`async` because of this")
321 .note("`async` trait functions are not currently supported")
322 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
327 fn check_trait_fn_not_const(&self, constness: Const) {
328 if let Const::Yes(span) = constness {
333 "functions in traits cannot be declared const"
335 .span_label(span, "functions in traits cannot be const")
340 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
341 // Check only lifetime parameters are present and that the lifetime
342 // parameters that are present have no bounds.
343 let non_lt_param_spans: Vec<_> = params
345 .filter_map(|param| match param.kind {
346 GenericParamKind::Lifetime { .. } => {
347 if !param.bounds.is_empty() {
348 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
350 .span_err(spans, "lifetime bounds cannot be used in this context");
354 _ => Some(param.ident.span),
357 if !non_lt_param_spans.is_empty() {
358 self.err_handler().span_err(
360 "only lifetime parameters can be used in this context",
365 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
366 self.check_decl_num_args(fn_decl);
367 self.check_decl_cvaradic_pos(fn_decl);
368 self.check_decl_attrs(fn_decl);
369 self.check_decl_self_param(fn_decl, self_semantic);
372 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
373 /// Error is fatal to prevent errors during typechecking
374 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
375 let max_num_args: usize = u16::MAX.into();
376 if fn_decl.inputs.len() > max_num_args {
377 let Param { span, .. } = fn_decl.inputs[0];
378 self.err_handler().span_fatal(
380 &format!("function can not have more than {} arguments", max_num_args),
385 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
386 match &*fn_decl.inputs {
387 [Param { ty, span, .. }] => {
388 if let TyKind::CVarArgs = ty.kind {
389 self.err_handler().span_err(
391 "C-variadic function must be declared with at least one named argument",
396 for Param { ty, span, .. } in ps {
397 if let TyKind::CVarArgs = ty.kind {
398 self.err_handler().span_err(
400 "`...` must be the last argument of a C-variadic function",
409 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
413 .flat_map(|i| i.attrs.as_ref())
424 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
427 if attr.is_doc_comment() {
431 "documentation comments cannot be applied to function parameters",
433 .span_label(attr.span, "doc comments are not allowed here")
436 self.err_handler().span_err(
438 "allow, cfg, cfg_attr, deny, expect, \
439 forbid, and warn are the only allowed built-in attributes in function parameters",
445 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
446 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
451 "`self` parameter is only allowed in associated functions",
453 .span_label(param.span, "not semantically valid as function parameter")
454 .note("associated functions are those in `impl` or `trait` definitions")
460 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
461 if let Defaultness::Default(def_span) = defaultness {
462 let span = self.session.source_map().guess_head_span(span);
464 .struct_span_err(span, "`default` is only allowed on items in trait impls")
465 .span_label(def_span, "`default` because of this")
470 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
471 self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
474 fn error_item_without_body_with_help(
480 help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>),
482 let source_map = self.session.source_map();
483 let end = source_map.end_point(sp);
484 let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
489 let mut err = self.err_handler().struct_span_err(sp, msg);
492 &format!("provide a definition for the {}", ctx),
494 Applicability::HasPlaceholders,
500 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
502 let msg = format!("associated {} in `impl` without body", ctx);
503 self.error_item_without_body(sp, ctx, &msg, sugg);
507 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
508 let span = match bounds {
511 [b0, .., bl] => b0.span().to(bl.span()),
514 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
518 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
519 let cannot_have = |span, descr, remove_descr| {
523 &format!("`type`s inside `extern` blocks cannot have {}", descr),
527 &format!("remove the {}", remove_descr),
529 Applicability::MaybeIncorrect,
531 .span_label(self.current_extern_span(), "`extern` block begins here")
536 if !generics.params.is_empty() {
537 cannot_have(generics.span, "generic parameters", "generic parameters");
540 if !generics.where_clause.predicates.is_empty() {
541 cannot_have(where_span, "`where` clauses", "`where` clause");
545 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
546 let Some(body) = body else {
550 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
551 .span_label(ident.span, "cannot have a body")
552 .span_label(body, "the invalid body")
554 self.current_extern_span(),
556 "`extern` blocks define existing foreign {0}s and {0}s \
557 inside of them cannot have a body",
565 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
566 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
567 let Some(body) = body else {
571 .struct_span_err(ident.span, "incorrect function inside `extern` block")
572 .span_label(ident.span, "cannot have a body")
575 "remove the invalid body",
577 Applicability::MaybeIncorrect,
580 "you might have meant to write a function accessible through FFI, \
581 which can be done by writing `extern fn` outside of the `extern` block",
584 self.current_extern_span(),
585 "`extern` blocks define existing foreign functions and functions \
586 inside of them cannot have a body",
592 fn current_extern_span(&self) -> Span {
593 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
596 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
597 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
598 if header.has_qualifiers() {
600 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
601 .span_label(self.current_extern_span(), "in this `extern` block")
602 .span_suggestion_verbose(
603 span.until(ident.span.shrink_to_lo()),
604 "remove the qualifiers",
606 Applicability::MaybeIncorrect,
612 /// An item in `extern { ... }` cannot use non-ascii identifier.
613 fn check_foreign_item_ascii_only(&self, ident: Ident) {
614 if !ident.as_str().is_ascii() {
619 "items in `extern` blocks cannot use non-ascii identifiers",
621 .span_label(self.current_extern_span(), "in this `extern` block")
623 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
630 /// Reject C-variadic type unless the function is foreign,
631 /// or free and `unsafe extern "C"` semantically.
632 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
633 match (fk.ctxt(), fk.header()) {
634 (Some(FnCtxt::Foreign), _) => return,
635 (Some(FnCtxt::Free), Some(header)) => match header.ext {
636 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
637 | Extern::Implicit(_)
638 if matches!(header.unsafety, Unsafe::Yes(_)) =>
647 for Param { ty, span, .. } in &fk.decl().inputs {
648 if let TyKind::CVarArgs = ty.kind {
652 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
659 fn check_item_named(&self, ident: Ident, kind: &str) {
660 if ident.name != kw::Underscore {
664 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
665 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
669 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
670 if ident.name.as_str().is_ascii() {
673 let head_span = self.session.source_map().guess_head_span(item_span);
678 "`#[no_mangle]` requires ASCII identifier"
683 fn check_mod_file_item_asciionly(&self, ident: Ident) {
684 if ident.name.as_str().is_ascii() {
691 "trying to load file for module `{}` with non-ascii identifier name",
694 .help("consider using `#[path]` attribute to specify filesystem path")
698 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
699 if !generics.params.is_empty() {
704 "auto traits cannot have generic parameters"
706 .span_label(ident_span, "auto trait cannot have generic parameters")
709 "remove the parameters",
711 Applicability::MachineApplicable,
717 fn emit_e0568(&self, span: Span, ident_span: Span) {
722 "auto traits cannot have super traits or lifetime bounds"
724 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
727 "remove the super traits or lifetime bounds",
729 Applicability::MachineApplicable,
734 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
735 if let [.., last] = &bounds[..] {
736 let span = ident_span.shrink_to_hi().to(last.span());
737 self.emit_e0568(span, ident_span);
741 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
742 if !where_clause.predicates.is_empty() {
743 self.emit_e0568(where_clause.span, ident_span);
747 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
748 if !trait_items.is_empty() {
749 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
750 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
755 "auto traits cannot have associated items"
759 "remove these associated items",
761 Applicability::MachineApplicable,
763 .span_label(ident_span, "auto trait cannot have associated items")
768 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
769 // Lifetimes always come first.
770 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
771 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
772 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
776 let args_sugg = data.args.iter().filter_map(|a| match a {
777 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
780 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
782 // Constraints always come last.
783 let constraint_sugg = data.args.iter().filter_map(|a| match a {
784 AngleBracketedArg::Arg(_) => None,
785 AngleBracketedArg::Constraint(c) => {
786 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
791 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
795 /// Enforce generic args coming before constraints in `<...>` of a path segment.
796 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
797 // Early exit in case it's partitioned as it should be.
798 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
801 // Find all generic argument coming after the first constraint...
802 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
803 data.args.iter().partition_map(|arg| match arg {
804 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
805 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
807 let args_len = arg_spans.len();
808 let constraint_len = constraint_spans.len();
809 // ...and then error:
813 "generic arguments must come before the first constraint",
815 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
817 *arg_spans.iter().last().unwrap(),
818 &format!("generic argument{}", pluralize!(args_len)),
820 .span_labels(constraint_spans, "")
821 .span_labels(arg_spans, "")
822 .span_suggestion_verbose(
825 "move the constraint{} after the generic argument{}",
826 pluralize!(constraint_len),
829 self.correct_generic_order_suggestion(&data),
830 Applicability::MachineApplicable,
835 fn visit_ty_common(&mut self, ty: &'a Ty) {
837 TyKind::BareFn(ref bfty) => {
838 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
839 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
844 "patterns aren't allowed in function pointer types"
848 self.check_late_bound_lifetime_defs(&bfty.generic_params);
849 if let Extern::Implicit(_) = bfty.ext {
850 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
851 self.maybe_lint_missing_abi(sig_span, ty.id);
854 TyKind::TraitObject(ref bounds, ..) => {
855 let mut any_lifetime_bounds = false;
856 for bound in bounds {
857 if let GenericBound::Outlives(ref lifetime) = *bound {
858 if any_lifetime_bounds {
863 "only a single explicit lifetime bound is permitted"
868 any_lifetime_bounds = true;
872 TyKind::ImplTrait(_, ref bounds) => {
873 if self.is_impl_trait_banned {
878 "`impl Trait` is not allowed in path parameters"
883 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
888 "nested `impl Trait` is not allowed"
890 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
891 .span_label(ty.span, "nested `impl Trait` here")
895 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
896 self.err_handler().span_err(ty.span, "at least one trait must be specified");
903 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
904 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
905 // call site which do not have a macro backtrace. See #61963.
906 let is_macro_callsite = self
909 .span_to_snippet(span)
910 .map(|snippet| snippet.starts_with("#["))
912 if !is_macro_callsite {
913 self.lint_buffer.buffer_lint_with_diagnostic(
917 "extern declarations without an explicit ABI are deprecated",
918 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
924 /// Checks that generic parameters are in the correct order,
925 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
926 fn validate_generic_param_order(
927 handler: &rustc_errors::Handler,
928 generics: &[GenericParam],
931 let mut max_param: Option<ParamKindOrd> = None;
932 let mut out_of_order = FxHashMap::default();
933 let mut param_idents = Vec::with_capacity(generics.len());
935 for (idx, param) in generics.iter().enumerate() {
936 let ident = param.ident;
937 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
938 let (ord_kind, ident) = match ¶m.kind {
939 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
940 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
941 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
942 let ty = pprust::ty_to_string(ty);
943 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
946 param_idents.push((kind, ord_kind, bounds, idx, ident));
948 Some(max_param) if max_param > ord_kind => {
949 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
952 Some(_) | None => max_param = Some(ord_kind),
956 if !out_of_order.is_empty() {
957 let mut ordered_params = "<".to_string();
958 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
959 let mut first = true;
960 for (kind, _, bounds, _, ident) in param_idents {
962 ordered_params += ", ";
964 ordered_params += &ident;
966 if !bounds.is_empty() {
967 ordered_params += ": ";
968 ordered_params += &pprust::bounds_to_string(&bounds);
972 GenericParamKind::Type { default: Some(default) } => {
973 ordered_params += " = ";
974 ordered_params += &pprust::ty_to_string(default);
976 GenericParamKind::Type { default: None } => (),
977 GenericParamKind::Lifetime => (),
978 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
979 ordered_params += " = ";
980 ordered_params += &pprust::expr_to_string(&*default.value);
982 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
987 ordered_params += ">";
989 for (param_ord, (max_param, spans)) in &out_of_order {
990 let mut err = handler.struct_span_err(
993 "{} parameters must be declared prior to {} parameters",
994 param_ord, max_param,
999 "reorder the parameters: lifetimes, then consts and types",
1001 Applicability::MachineApplicable,
1008 impl<'a> Visitor<'a> for AstValidator<'a> {
1009 fn visit_attribute(&mut self, attr: &Attribute) {
1010 validate_attr::check_meta(&self.session.parse_sess, attr);
1013 fn visit_expr(&mut self, expr: &'a Expr) {
1014 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
1016 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
1017 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
1018 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
1019 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
1021 ExprKind::If(cond, then, opt_else) => {
1022 this.visit_block(then);
1023 walk_list!(this, visit_expr, opt_else);
1024 this.with_let_management(None, |this, _| this.visit_expr(cond));
1027 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
1028 this.ban_let_expr(expr, elem);
1030 ExprKind::Match(scrutinee, arms) => {
1031 this.visit_expr(scrutinee);
1033 this.visit_expr(&arm.body);
1034 this.visit_pat(&arm.pat);
1035 walk_list!(this, visit_attribute, &arm.attrs);
1036 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
1037 this.with_let_management(None, |this, _| {
1038 this.visit_expr(guard_expr)
1044 ExprKind::Paren(local_expr) => {
1045 fn has_let_expr(expr: &Expr) -> bool {
1047 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
1048 ExprKind::Let(..) => true,
1052 let local_reason = if has_let_expr(local_expr) {
1053 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
1056 forbidden_let_reason
1058 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
1060 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1061 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
1064 ExprKind::While(cond, then, opt_label) => {
1065 walk_list!(this, visit_label, opt_label);
1066 this.visit_block(then);
1067 this.with_let_management(None, |this, _| this.visit_expr(cond));
1070 _ => visit::walk_expr(this, expr),
1075 fn visit_ty(&mut self, ty: &'a Ty) {
1076 self.visit_ty_common(ty);
1080 fn visit_label(&mut self, label: &'a Label) {
1081 self.check_label(label.ident);
1082 visit::walk_label(self, label);
1085 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
1086 self.check_lifetime(lifetime.ident);
1087 visit::walk_lifetime(self, lifetime);
1090 fn visit_field_def(&mut self, s: &'a FieldDef) {
1091 visit::walk_field_def(self, s)
1094 fn visit_item(&mut self, item: &'a Item) {
1095 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1096 self.has_proc_macro_decls = true;
1099 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1100 self.check_nomangle_item_asciionly(item.ident, item.span);
1104 ItemKind::Impl(box Impl {
1110 of_trait: Some(ref t),
1114 self.with_in_trait_impl(true, Some(constness), |this| {
1115 this.invalid_visibility(&item.vis, None);
1116 if let TyKind::Err = self_ty.kind {
1120 "`impl Trait for .. {}` is an obsolete syntax",
1122 .help("use `auto trait Trait {}` instead")
1125 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1130 "negative impls cannot be unsafe"
1132 .span_label(sp, "negative because of this")
1133 .span_label(span, "unsafe because of this")
1137 this.visit_vis(&item.vis);
1138 this.visit_ident(item.ident);
1139 if let Const::Yes(_) = constness {
1140 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1142 this.visit_generics(generics);
1144 this.visit_trait_ref(t);
1145 this.visit_ty(self_ty);
1147 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1149 return; // Avoid visiting again.
1151 ItemKind::Impl(box Impl {
1161 let error = |annotation_span, annotation| {
1162 let mut err = self.err_handler().struct_span_err(
1164 &format!("inherent impls cannot be {}", annotation),
1166 err.span_label(annotation_span, &format!("{} because of this", annotation));
1167 err.span_label(self_ty.span, "inherent impl for this type");
1171 self.invalid_visibility(
1173 Some("place qualifiers on individual impl items instead"),
1175 if let Unsafe::Yes(span) = unsafety {
1176 error(span, "unsafe").code(error_code!(E0197)).emit();
1178 if let ImplPolarity::Negative(span) = polarity {
1179 error(span, "negative").emit();
1181 if let Defaultness::Default(def_span) = defaultness {
1182 error(def_span, "`default`")
1183 .note("only trait implementations may be annotated with `default`")
1186 if let Const::Yes(span) = constness {
1187 error(span, "`const`")
1188 .note("only trait implementations may be annotated with `const`")
1192 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1193 self.check_defaultness(item.span, defaultness);
1196 let msg = "free function without a body";
1197 let ext = sig.header.ext;
1199 let f = |e: &mut DiagnosticBuilder<'_, _>| {
1200 if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
1202 let start_suggestion = if let Extern::Explicit(abi, _) = ext {
1203 format!("extern \"{}\" {{", abi.symbol_unescaped)
1205 "extern {".to_owned()
1208 let end_suggestion = " }".to_owned();
1209 let end_span = item.span.shrink_to_hi();
1212 .multipart_suggestion(
1213 "if you meant to declare an externally defined function, use an `extern` block",
1214 vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
1215 Applicability::MaybeIncorrect,
1220 self.error_item_without_body_with_help(
1229 self.visit_vis(&item.vis);
1230 self.visit_ident(item.ident);
1232 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1233 self.visit_fn(kind, item.span, item.id);
1234 walk_list!(self, visit_attribute, &item.attrs);
1235 return; // Avoid visiting again.
1237 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1238 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1239 self.invalid_visibility(
1241 Some("place qualifiers on individual foreign items instead"),
1243 if let Unsafe::Yes(span) = unsafety {
1244 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1247 self.maybe_lint_missing_abi(item.span, item.id);
1249 visit::walk_item(self, item);
1250 self.extern_mod = old_item;
1251 return; // Avoid visiting again.
1253 ItemKind::Enum(ref def, _) => {
1254 for variant in &def.variants {
1255 self.invalid_visibility(&variant.vis, None);
1256 for field in variant.data.fields() {
1257 self.invalid_visibility(&field.vis, None);
1261 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1262 if is_auto == IsAuto::Yes {
1263 // Auto traits cannot have generics, super traits nor contain items.
1264 self.deny_generic_params(generics, item.ident.span);
1265 self.deny_super_traits(bounds, item.ident.span);
1266 self.deny_where_clause(&generics.where_clause, item.ident.span);
1267 self.deny_items(items, item.ident.span);
1270 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1271 // context for the supertraits.
1272 self.visit_vis(&item.vis);
1273 self.visit_ident(item.ident);
1274 self.visit_generics(generics);
1275 self.with_tilde_const_allowed(|this| {
1276 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1278 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1279 walk_list!(self, visit_attribute, &item.attrs);
1282 ItemKind::Mod(unsafety, ref mod_kind) => {
1283 if let Unsafe::Yes(span) = unsafety {
1284 self.err_handler().span_err(span, "module cannot be declared unsafe");
1286 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1287 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1288 && !self.session.contains_name(&item.attrs, sym::path)
1290 self.check_mod_file_item_asciionly(item.ident);
1293 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1294 // Duplicating the `Visitor` logic allows catching all cases
1295 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1297 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1298 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1299 // it uses `visit_ty_common`, which doesn't contain that specific check.
1300 VariantData::Struct(ref fields, ..) => {
1301 self.visit_vis(&item.vis);
1302 self.visit_ident(item.ident);
1303 self.visit_generics(generics);
1304 self.with_banned_assoc_ty_bound(|this| {
1305 walk_list!(this, visit_struct_field_def, fields);
1307 walk_list!(self, visit_attribute, &item.attrs);
1312 ItemKind::Union(ref vdata, ref generics) => {
1313 if vdata.fields().is_empty() {
1314 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1317 VariantData::Struct(ref fields, ..) => {
1318 self.visit_vis(&item.vis);
1319 self.visit_ident(item.ident);
1320 self.visit_generics(generics);
1321 self.with_banned_assoc_ty_bound(|this| {
1322 walk_list!(this, visit_struct_field_def, fields);
1324 walk_list!(self, visit_attribute, &item.attrs);
1330 ItemKind::Const(def, .., None) => {
1331 self.check_defaultness(item.span, def);
1332 let msg = "free constant item without body";
1333 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1335 ItemKind::Static(.., None) => {
1336 let msg = "free static item without body";
1337 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1339 ItemKind::TyAlias(box TyAlias {
1346 self.check_defaultness(item.span, defaultness);
1348 let msg = "free type alias without body";
1349 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1351 self.check_type_no_bounds(bounds, "this context");
1352 if where_clauses.1.0 {
1353 let mut err = self.err_handler().struct_span_err(
1355 "where clauses are not allowed after the type for type aliases",
1358 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1366 visit::walk_item(self, item);
1369 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1371 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1372 self.check_defaultness(fi.span, *defaultness);
1373 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1374 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1375 self.check_foreign_item_ascii_only(fi.ident);
1377 ForeignItemKind::TyAlias(box TyAlias {
1385 self.check_defaultness(fi.span, *defaultness);
1386 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1387 self.check_type_no_bounds(bounds, "`extern` blocks");
1388 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1389 self.check_foreign_item_ascii_only(fi.ident);
1391 ForeignItemKind::Static(_, _, body) => {
1392 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1393 self.check_foreign_item_ascii_only(fi.ident);
1395 ForeignItemKind::MacCall(..) => {}
1398 visit::walk_foreign_item(self, fi)
1401 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1402 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1403 match *generic_args {
1404 GenericArgs::AngleBracketed(ref data) => {
1405 self.check_generic_args_before_constraints(data);
1407 for arg in &data.args {
1409 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1410 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1411 // are allowed to contain nested `impl Trait`.
1412 AngleBracketedArg::Constraint(constraint) => {
1413 self.with_impl_trait(None, |this| {
1414 this.visit_assoc_constraint_from_generic_args(constraint);
1420 GenericArgs::Parenthesized(ref data) => {
1421 walk_list!(self, visit_ty, &data.inputs);
1422 if let FnRetTy::Ty(ty) = &data.output {
1423 // `-> Foo` syntax is essentially an associated type binding,
1424 // so it is also allowed to contain nested `impl Trait`.
1425 self.with_impl_trait(None, |this| this.visit_ty(ty));
1431 fn visit_generics(&mut self, generics: &'a Generics) {
1432 let mut prev_param_default = None;
1433 for param in &generics.params {
1435 GenericParamKind::Lifetime => (),
1436 GenericParamKind::Type { default: Some(_), .. }
1437 | GenericParamKind::Const { default: Some(_), .. } => {
1438 prev_param_default = Some(param.ident.span);
1440 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1441 if let Some(span) = prev_param_default {
1442 let mut err = self.err_handler().struct_span_err(
1444 "generic parameters with a default must be trailing",
1453 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1455 for predicate in &generics.where_clause.predicates {
1456 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1457 deny_equality_constraints(self, predicate, generics);
1460 walk_list!(self, visit_generic_param, &generics.params);
1461 for predicate in &generics.where_clause.predicates {
1463 WherePredicate::BoundPredicate(bound_pred) => {
1464 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1465 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1467 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1468 // binder and thus we only allow a single level of quantification. However,
1469 // the syntax of Rust permits quantification in two places in where clauses,
1470 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1471 // defined, then error.
1472 if !bound_pred.bound_generic_params.is_empty() {
1473 for bound in &bound_pred.bounds {
1475 GenericBound::Trait(t, _) => {
1476 if !t.bound_generic_params.is_empty() {
1481 "nested quantification of lifetimes"
1486 GenericBound::Outlives(_) => {}
1493 self.visit_where_predicate(predicate);
1497 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1498 if let GenericParamKind::Lifetime { .. } = param.kind {
1499 self.check_lifetime(param.ident);
1501 visit::walk_generic_param(self, param);
1504 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1505 if let GenericBound::Trait(ref poly, modify) = *bound {
1506 match (ctxt, modify) {
1507 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1510 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1511 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1512 err.note(&format!("traits are `?{}` by default", path_str));
1515 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1516 let mut err = self.err_handler().struct_span_err(
1518 "`?Trait` is not permitted in trait object types",
1522 (_, TraitBoundModifier::MaybeConst) => {
1523 if !self.is_tilde_const_allowed {
1525 .struct_span_err(bound.span(), "`~const` is not allowed here")
1526 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1530 (_, TraitBoundModifier::MaybeConstMaybe) => {
1532 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1538 visit::walk_param_bound(self, bound)
1541 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1542 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1543 visit::walk_poly_trait_ref(self, t, m);
1546 fn visit_variant_data(&mut self, s: &'a VariantData) {
1547 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1552 enum_definition: &'a EnumDef,
1553 generics: &'a Generics,
1557 self.with_banned_assoc_ty_bound(|this| {
1558 visit::walk_enum_def(this, enum_definition, generics, item_id)
1562 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1563 // Only associated `fn`s can have `self` parameters.
1564 let self_semantic = match fk.ctxt() {
1565 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1566 _ => SelfSemantic::No,
1568 self.check_fn_decl(fk.decl(), self_semantic);
1570 self.check_c_variadic_type(fk);
1572 // Functions cannot both be `const async`
1573 if let Some(FnHeader {
1574 constness: Const::Yes(cspan),
1575 asyncness: Async::Yes { span: aspan, .. },
1581 vec![*cspan, *aspan],
1582 "functions cannot be both `const` and `async`",
1584 .span_label(*cspan, "`const` because of this")
1585 .span_label(*aspan, "`async` because of this")
1586 .span_label(span, "") // Point at the fn header.
1590 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1591 self.check_late_bound_lifetime_defs(generic_params);
1597 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1603 self.maybe_lint_missing_abi(*sig_span, id);
1606 // Functions without bodies cannot have patterns.
1607 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1608 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1609 let (code, msg, label) = match ctxt {
1610 FnCtxt::Foreign => (
1612 "patterns aren't allowed in foreign function declarations",
1613 "pattern not allowed in foreign function",
1617 "patterns aren't allowed in functions without bodies",
1618 "pattern not allowed in function without body",
1621 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1622 if let Some(ident) = ident {
1623 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1624 self.lint_buffer.buffer_lint_with_diagnostic(
1625 PATTERNS_IN_FNS_WITHOUT_BODY,
1634 .struct_span_err(span, msg)
1635 .span_label(span, label)
1642 let tilde_const_allowed =
1643 matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1644 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1646 self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
1649 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1650 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1651 self.check_nomangle_item_asciionly(item.ident, item.span);
1654 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1655 self.check_defaultness(item.span, item.kind.defaultness());
1658 if ctxt == AssocCtxt::Impl {
1660 AssocItemKind::Const(_, _, body) => {
1661 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1663 AssocItemKind::Fn(box Fn { body, .. }) => {
1664 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1666 AssocItemKind::TyAlias(box TyAlias {
1669 where_predicates_split,
1674 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1675 self.check_type_no_bounds(bounds, "`impl`s");
1677 self.check_gat_where(
1679 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1688 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1689 self.invalid_visibility(&item.vis, None);
1690 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1691 self.check_trait_fn_not_const(sig.header.constness);
1692 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1696 if let AssocItemKind::Const(..) = item.kind {
1697 self.check_item_named(item.ident, "const");
1701 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1702 if ctxt == AssocCtxt::Trait =>
1704 self.visit_vis(&item.vis);
1705 self.visit_ident(item.ident);
1706 walk_list!(self, visit_attribute, &item.attrs);
1707 self.with_tilde_const_allowed(|this| {
1708 this.visit_generics(generics);
1709 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1711 walk_list!(self, visit_ty, ty);
1713 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1714 if self.in_const_trait_impl
1715 || ctxt == AssocCtxt::Trait
1716 || matches!(sig.header.constness, Const::Yes(_)) =>
1718 self.visit_vis(&item.vis);
1719 self.visit_ident(item.ident);
1720 let kind = FnKind::Fn(
1721 FnCtxt::Assoc(ctxt),
1728 self.visit_fn(kind, item.span, item.id);
1731 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1736 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1737 /// like it's setting an associated type, provide an appropriate suggestion.
1738 fn deny_equality_constraints(
1739 this: &mut AstValidator<'_>,
1740 predicate: &WhereEqPredicate,
1741 generics: &Generics,
1743 let mut err = this.err_handler().struct_span_err(
1745 "equality constraints are not yet supported in `where` clauses",
1747 err.span_label(predicate.span, "not supported");
1749 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1750 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1751 if let TyKind::Path(None, path) = &qself.ty.kind {
1752 match &path.segments[..] {
1753 [PathSegment { ident, args: None, .. }] => {
1754 for param in &generics.params {
1755 if param.ident == *ident {
1757 match &full_path.segments[qself.position..] {
1758 [PathSegment { ident, args, .. }] => {
1759 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1760 let mut assoc_path = full_path.clone();
1761 // Remove `Bar` from `Foo::Bar`.
1762 assoc_path.segments.pop();
1763 let len = assoc_path.segments.len() - 1;
1764 let gen_args = args.as_ref().map(|p| (**p).clone());
1765 // Build `<Bar = RhsTy>`.
1766 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1767 id: rustc_ast::node_id::DUMMY_NODE_ID,
1770 kind: AssocConstraintKind::Equality {
1771 term: predicate.rhs_ty.clone().into(),
1775 // Add `<Bar = RhsTy>` to `Foo`.
1776 match &mut assoc_path.segments[len].args {
1777 Some(args) => match args.deref_mut() {
1778 GenericArgs::Parenthesized(_) => continue,
1779 GenericArgs::AngleBracketed(args) => {
1780 args.args.push(arg);
1784 *empty_args = AngleBracketedArgs {
1791 err.span_suggestion_verbose(
1794 "if `{}` is an associated type you're trying to set, \
1795 use the associated type binding syntax",
1801 pprust::path_to_string(&assoc_path)
1803 Applicability::MaybeIncorrect,
1815 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1816 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1817 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1818 for param in &generics.params {
1819 if param.ident == potential_param.ident {
1820 for bound in ¶m.bounds {
1821 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1823 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1824 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1825 potential_assoc.ident,
1827 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1828 let (args, span) = match &trait_segment.args {
1829 Some(args) => match args.deref() {
1830 ast::GenericArgs::AngleBracketed(args) => {
1831 let Some(arg) = args.args.last() else {
1835 format!(", {} = {}", assoc, ty),
1836 arg.span().shrink_to_hi(),
1842 format!("<{} = {}>", assoc, ty),
1843 trait_segment.span().shrink_to_hi(),
1846 err.multipart_suggestion(
1848 "if `{}::{}` is an associated type you're trying to set, \
1849 use the associated type binding syntax",
1850 trait_segment.ident, potential_assoc.ident,
1852 vec![(span, args), (predicate.span, String::new())],
1853 Applicability::MaybeIncorrect,
1863 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1868 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1869 let mut validator = AstValidator {
1872 in_trait_impl: false,
1873 in_const_trait_impl: false,
1874 has_proc_macro_decls: false,
1875 outer_impl_trait: None,
1876 is_tilde_const_allowed: false,
1877 is_impl_trait_banned: false,
1878 is_assoc_ty_bound_banned: false,
1879 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1882 visit::walk_crate(&mut validator, krate);
1884 validator.has_proc_macro_decls
1887 /// Used to forbid `let` expressions in certain syntactic locations.
1888 #[derive(Clone, Copy)]
1889 enum ForbiddenLetReason {
1890 /// `let` is not valid and the source environment is not important
1892 /// A let chain with the `||` operator
1893 NotSupportedOr(Span),
1894 /// A let chain with invalid parentheses
1896 /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
1897 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1898 NotSupportedParentheses(Span),