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, 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};
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_allowed(&mut self, f: impl FnOnce(&mut Self)) {
95 let old = mem::replace(&mut self.is_tilde_const_allowed, true);
97 self.is_tilde_const_allowed = old;
100 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
101 let old = mem::replace(&mut self.is_tilde_const_allowed, false);
103 self.is_tilde_const_allowed = old;
106 fn with_let_management(
108 forbidden_let_reason: Option<ForbiddenLetReason>,
109 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
111 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
113 self.forbidden_let_reason = old;
116 /// Emits an error banning the `let` expression provided in the given location.
117 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
118 let sess = &self.session;
119 if sess.opts.unstable_features.is_nightly_build() {
120 let err = "`let` expressions are not supported here";
121 let mut diag = sess.struct_span_err(expr.span, err);
122 diag.note("only supported directly in conditions of `if` and `while` expressions");
123 diag.note("as well as when nested within `&&` and parentheses in those conditions");
124 if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
127 "`||` operators are not currently supported in let chain expressions",
132 sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
133 .note("variable declaration using `let` is a statement")
141 before_predicates: &[WherePredicate],
142 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
144 if !before_predicates.is_empty() {
145 let mut state = State::new();
146 if !where_clauses.1.0 {
148 state.word_space("where");
150 state.word_space(",");
152 let mut first = true;
153 for p in before_predicates.iter() {
155 state.word_space(",");
158 state.print_where_predicate(p);
160 let suggestion = state.s.eof();
161 self.lint_buffer.buffer_lint_with_diagnostic(
162 DEPRECATED_WHERE_CLAUSE_LOCATION,
165 "where clause not allowed here",
166 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
167 where_clauses.1.1.shrink_to_hi(),
174 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
175 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
177 self.is_assoc_ty_bound_banned = old;
180 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
181 let old = mem::replace(&mut self.outer_impl_trait, outer);
183 self.with_banned_tilde_const(f);
187 self.outer_impl_trait = old;
190 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
191 match constraint.kind {
192 AssocConstraintKind::Equality { .. } => {}
193 AssocConstraintKind::Bound { .. } => {
194 if self.is_assoc_ty_bound_banned {
195 self.err_handler().span_err(
197 "associated type bounds are not allowed within structs, enums, or unions",
202 self.visit_assoc_constraint(constraint);
205 // Mirrors `visit::walk_ty`, but tracks relevant state.
206 fn walk_ty(&mut self, t: &'a Ty) {
208 TyKind::ImplTrait(..) => {
209 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
211 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
212 TyKind::Path(ref qself, ref path) => {
214 // - `Option<impl Trait>`
215 // - `option::Option<impl Trait>`
216 // - `option::Option<T>::Foo<impl Trait>
219 // - `<impl Trait>::Foo`
220 // - `option::Option<impl Trait>::Foo`.
222 // To implement this, we disallow `impl Trait` from `qself`
223 // (for cases like `<impl Trait>::Foo>`)
224 // but we allow `impl Trait` in `GenericArgs`
225 // iff there are no more PathSegments.
226 if let Some(ref qself) = *qself {
227 // `impl Trait` in `qself` is always illegal
228 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
231 // Note that there should be a call to visit_path here,
232 // so if any logic is added to process `Path`s a call to it should be
233 // added both in visit_path and here. This code mirrors visit::walk_path.
234 for (i, segment) in path.segments.iter().enumerate() {
235 // Allow `impl Trait` iff we're on the final path segment
236 if i == path.segments.len() - 1 {
237 self.visit_path_segment(path.span, segment);
239 self.with_banned_impl_trait(|this| {
240 this.visit_path_segment(path.span, segment)
245 _ => visit::walk_ty(self, t),
249 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
250 if let Some(ident) = field.ident {
251 if ident.name == kw::Underscore {
252 self.visit_vis(&field.vis);
253 self.visit_ident(ident);
254 self.visit_ty_common(&field.ty);
255 self.walk_ty(&field.ty);
256 walk_list!(self, visit_attribute, &field.attrs);
260 self.visit_field_def(field);
263 fn err_handler(&self) -> &rustc_errors::Handler {
264 &self.session.diagnostic()
267 fn check_lifetime(&self, ident: Ident) {
268 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
269 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
270 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
274 fn check_label(&self, ident: Ident) {
275 if ident.without_first_quote().is_reserved() {
277 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
281 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
282 if let VisibilityKind::Inherited = vis.kind {
287 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
288 if vis.kind.is_pub() {
289 err.span_label(vis.span, "`pub` not permitted here because it's implied");
291 if let Some(note) = note {
297 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
298 for Param { pat, .. } in &decl.inputs {
300 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
301 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
302 report_err(pat.span, Some(ident), true)
304 _ => report_err(pat.span, None, false),
309 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
310 if let Async::Yes { span, .. } = asyncness {
315 "functions in traits cannot be declared `async`"
317 .span_label(span, "`async` because of this")
318 .note("`async` trait functions are not currently supported")
319 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
324 fn check_trait_fn_not_const(&self, constness: Const) {
325 if let Const::Yes(span) = constness {
330 "functions in traits cannot be declared const"
332 .span_label(span, "functions in traits cannot be const")
337 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
338 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
339 for bound in bounds {
340 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
341 let mut err = self.err_handler().struct_span_err(
343 &format!("`?Trait` is not permitted in {}", where_),
346 let path_str = pprust::path_to_string(&poly.trait_ref.path);
347 err.note(&format!("traits are `?{}` by default", path_str));
354 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
355 // Check only lifetime parameters are present and that the lifetime
356 // parameters that are present have no bounds.
357 let non_lt_param_spans: Vec<_> = params
359 .filter_map(|param| match param.kind {
360 GenericParamKind::Lifetime { .. } => {
361 if !param.bounds.is_empty() {
362 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
364 .span_err(spans, "lifetime bounds cannot be used in this context");
368 _ => Some(param.ident.span),
371 if !non_lt_param_spans.is_empty() {
372 self.err_handler().span_err(
374 "only lifetime parameters can be used in this context",
379 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
380 self.check_decl_num_args(fn_decl);
381 self.check_decl_cvaradic_pos(fn_decl);
382 self.check_decl_attrs(fn_decl);
383 self.check_decl_self_param(fn_decl, self_semantic);
386 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
387 /// Error is fatal to prevent errors during typechecking
388 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
389 let max_num_args: usize = u16::MAX.into();
390 if fn_decl.inputs.len() > max_num_args {
391 let Param { span, .. } = fn_decl.inputs[0];
392 self.err_handler().span_fatal(
394 &format!("function can not have more than {} arguments", max_num_args),
399 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
400 match &*fn_decl.inputs {
401 [Param { ty, span, .. }] => {
402 if let TyKind::CVarArgs = ty.kind {
403 self.err_handler().span_err(
405 "C-variadic function must be declared with at least one named argument",
410 for Param { ty, span, .. } in ps {
411 if let TyKind::CVarArgs = ty.kind {
412 self.err_handler().span_err(
414 "`...` must be the last argument of a C-variadic function",
423 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
427 .flat_map(|i| i.attrs.as_ref())
429 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
430 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
433 if attr.is_doc_comment() {
437 "documentation comments cannot be applied to function parameters",
439 .span_label(attr.span, "doc comments are not allowed here")
442 self.err_handler().span_err(
444 "allow, cfg, cfg_attr, deny, \
445 forbid, and warn are the only allowed built-in attributes in function parameters",
451 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
452 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
457 "`self` parameter is only allowed in associated functions",
459 .span_label(param.span, "not semantically valid as function parameter")
460 .note("associated functions are those in `impl` or `trait` definitions")
466 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
467 if let Defaultness::Default(def_span) = defaultness {
468 let span = self.session.source_map().guess_head_span(span);
470 .struct_span_err(span, "`default` is only allowed on items in trait impls")
471 .span_label(def_span, "`default` because of this")
476 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
477 let source_map = self.session.source_map();
478 let end = source_map.end_point(sp);
479 let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
485 .struct_span_err(sp, msg)
488 &format!("provide a definition for the {}", ctx),
490 Applicability::HasPlaceholders,
495 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
497 let msg = format!("associated {} in `impl` without body", ctx);
498 self.error_item_without_body(sp, ctx, &msg, sugg);
502 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
503 let span = match bounds {
506 [b0, .., bl] => b0.span().to(bl.span()),
509 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
513 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
514 let cannot_have = |span, descr, remove_descr| {
518 &format!("`type`s inside `extern` blocks cannot have {}", descr),
522 &format!("remove the {}", remove_descr),
524 Applicability::MaybeIncorrect,
526 .span_label(self.current_extern_span(), "`extern` block begins here")
531 if !generics.params.is_empty() {
532 cannot_have(generics.span, "generic parameters", "generic parameters");
535 if !generics.where_clause.predicates.is_empty() {
536 cannot_have(where_span, "`where` clauses", "`where` clause");
540 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
541 let Some(body) = body else {
545 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
546 .span_label(ident.span, "cannot have a body")
547 .span_label(body, "the invalid body")
549 self.current_extern_span(),
551 "`extern` blocks define existing foreign {0}s and {0}s \
552 inside of them cannot have a body",
560 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
561 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
562 let Some(body) = body else {
566 .struct_span_err(ident.span, "incorrect function inside `extern` block")
567 .span_label(ident.span, "cannot have a body")
570 "remove the invalid body",
572 Applicability::MaybeIncorrect,
575 "you might have meant to write a function accessible through FFI, \
576 which can be done by writing `extern fn` outside of the `extern` block",
579 self.current_extern_span(),
580 "`extern` blocks define existing foreign functions and functions \
581 inside of them cannot have a body",
587 fn current_extern_span(&self) -> Span {
588 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
591 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
592 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
593 if header.has_qualifiers() {
595 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
596 .span_label(self.current_extern_span(), "in this `extern` block")
597 .span_suggestion_verbose(
598 span.until(ident.span.shrink_to_lo()),
599 "remove the qualifiers",
601 Applicability::MaybeIncorrect,
607 /// An item in `extern { ... }` cannot use non-ascii identifier.
608 fn check_foreign_item_ascii_only(&self, ident: Ident) {
609 if !ident.as_str().is_ascii() {
614 "items in `extern` blocks cannot use non-ascii identifiers",
616 .span_label(self.current_extern_span(), "in this `extern` block")
618 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
625 /// Reject C-variadic type unless the function is foreign,
626 /// or free and `unsafe extern "C"` semantically.
627 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
628 match (fk.ctxt(), fk.header()) {
629 (Some(FnCtxt::Foreign), _) => return,
630 (Some(FnCtxt::Free), Some(header)) => match header.ext {
631 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
632 if matches!(header.unsafety, Unsafe::Yes(_)) =>
641 for Param { ty, span, .. } in &fk.decl().inputs {
642 if let TyKind::CVarArgs = ty.kind {
646 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
653 fn check_item_named(&self, ident: Ident, kind: &str) {
654 if ident.name != kw::Underscore {
658 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
659 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
663 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
664 if ident.name.as_str().is_ascii() {
667 let head_span = self.session.source_map().guess_head_span(item_span);
672 "`#[no_mangle]` requires ASCII identifier"
677 fn check_mod_file_item_asciionly(&self, ident: Ident) {
678 if ident.name.as_str().is_ascii() {
685 "trying to load file for module `{}` with non-ascii identifier name",
688 .help("consider using `#[path]` attribute to specify filesystem path")
692 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
693 if !generics.params.is_empty() {
698 "auto traits cannot have generic parameters"
700 .span_label(ident_span, "auto trait cannot have generic parameters")
703 "remove the parameters",
705 Applicability::MachineApplicable,
711 fn emit_e0568(&self, span: Span, ident_span: Span) {
716 "auto traits cannot have super traits or lifetime bounds"
718 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
721 "remove the super traits or lifetime bounds",
723 Applicability::MachineApplicable,
728 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
729 if let [.., last] = &bounds[..] {
730 let span = ident_span.shrink_to_hi().to(last.span());
731 self.emit_e0568(span, ident_span);
735 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
736 if !where_clause.predicates.is_empty() {
737 self.emit_e0568(where_clause.span, ident_span);
741 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
742 if !trait_items.is_empty() {
743 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
744 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
749 "auto traits cannot have associated items"
753 "remove these associated items",
755 Applicability::MachineApplicable,
757 .span_label(ident_span, "auto trait cannot have associated items")
762 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
763 // Lifetimes always come first.
764 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
765 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
766 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
770 let args_sugg = data.args.iter().filter_map(|a| match a {
771 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
774 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
776 // Constraints always come last.
777 let constraint_sugg = data.args.iter().filter_map(|a| match a {
778 AngleBracketedArg::Arg(_) => None,
779 AngleBracketedArg::Constraint(c) => {
780 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
785 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
789 /// Enforce generic args coming before constraints in `<...>` of a path segment.
790 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
791 // Early exit in case it's partitioned as it should be.
792 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
795 // Find all generic argument coming after the first constraint...
796 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
797 data.args.iter().partition_map(|arg| match arg {
798 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
799 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
801 let args_len = arg_spans.len();
802 let constraint_len = constraint_spans.len();
803 // ...and then error:
807 "generic arguments must come before the first constraint",
809 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
811 *arg_spans.iter().last().unwrap(),
812 &format!("generic argument{}", pluralize!(args_len)),
814 .span_labels(constraint_spans, "")
815 .span_labels(arg_spans, "")
816 .span_suggestion_verbose(
819 "move the constraint{} after the generic argument{}",
820 pluralize!(constraint_len),
823 self.correct_generic_order_suggestion(&data),
824 Applicability::MachineApplicable,
829 fn visit_ty_common(&mut self, ty: &'a Ty) {
831 TyKind::BareFn(ref bfty) => {
832 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
833 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
838 "patterns aren't allowed in function pointer types"
842 self.check_late_bound_lifetime_defs(&bfty.generic_params);
843 if let Extern::Implicit = bfty.ext {
844 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
845 self.maybe_lint_missing_abi(sig_span, ty.id);
848 TyKind::TraitObject(ref bounds, ..) => {
849 let mut any_lifetime_bounds = false;
850 for bound in bounds {
851 if let GenericBound::Outlives(ref lifetime) = *bound {
852 if any_lifetime_bounds {
857 "only a single explicit lifetime bound is permitted"
862 any_lifetime_bounds = true;
865 self.no_questions_in_bounds(bounds, "trait object types", false);
867 TyKind::ImplTrait(_, ref bounds) => {
868 if self.is_impl_trait_banned {
873 "`impl Trait` is not allowed in path parameters"
878 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
883 "nested `impl Trait` is not allowed"
885 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
886 .span_label(ty.span, "nested `impl Trait` here")
890 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
891 self.err_handler().span_err(ty.span, "at least one trait must be specified");
898 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
899 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
900 // call site which do not have a macro backtrace. See #61963.
901 let is_macro_callsite = self
904 .span_to_snippet(span)
905 .map(|snippet| snippet.starts_with("#["))
907 if !is_macro_callsite {
908 self.lint_buffer.buffer_lint_with_diagnostic(
912 "extern declarations without an explicit ABI are deprecated",
913 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
919 /// Checks that generic parameters are in the correct order,
920 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
921 fn validate_generic_param_order(
922 handler: &rustc_errors::Handler,
923 generics: &[GenericParam],
926 let mut max_param: Option<ParamKindOrd> = None;
927 let mut out_of_order = FxHashMap::default();
928 let mut param_idents = Vec::with_capacity(generics.len());
930 for (idx, param) in generics.iter().enumerate() {
931 let ident = param.ident;
932 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
933 let (ord_kind, ident) = match ¶m.kind {
934 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
935 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
936 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
937 let ty = pprust::ty_to_string(ty);
938 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
941 param_idents.push((kind, ord_kind, bounds, idx, ident));
943 Some(max_param) if max_param > ord_kind => {
944 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
947 Some(_) | None => max_param = Some(ord_kind),
951 if !out_of_order.is_empty() {
952 let mut ordered_params = "<".to_string();
953 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
954 let mut first = true;
955 for (kind, _, bounds, _, ident) in param_idents {
957 ordered_params += ", ";
959 ordered_params += &ident;
961 if !bounds.is_empty() {
962 ordered_params += ": ";
963 ordered_params += &pprust::bounds_to_string(&bounds);
967 GenericParamKind::Type { default: Some(default) } => {
968 ordered_params += " = ";
969 ordered_params += &pprust::ty_to_string(default);
971 GenericParamKind::Type { default: None } => (),
972 GenericParamKind::Lifetime => (),
973 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
974 ordered_params += " = ";
975 ordered_params += &pprust::expr_to_string(&*default.value);
977 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
982 ordered_params += ">";
984 for (param_ord, (max_param, spans)) in &out_of_order {
985 let mut err = handler.struct_span_err(
988 "{} parameters must be declared prior to {} parameters",
989 param_ord, max_param,
994 "reorder the parameters: lifetimes, then consts and types",
995 ordered_params.clone(),
996 Applicability::MachineApplicable,
1003 impl<'a> Visitor<'a> for AstValidator<'a> {
1004 fn visit_attribute(&mut self, attr: &Attribute) {
1005 validate_attr::check_meta(&self.session.parse_sess, attr);
1008 fn visit_expr(&mut self, expr: &'a Expr) {
1009 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
1011 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
1012 let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
1013 this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
1014 this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
1016 ExprKind::If(cond, then, opt_else) => {
1017 this.visit_block(then);
1018 walk_list!(this, visit_expr, opt_else);
1019 this.with_let_management(None, |this, _| this.visit_expr(cond));
1022 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
1023 this.ban_let_expr(expr, elem);
1025 ExprKind::Match(scrutinee, arms) => {
1026 this.visit_expr(scrutinee);
1028 this.visit_expr(&arm.body);
1029 this.visit_pat(&arm.pat);
1030 walk_list!(this, visit_attribute, &arm.attrs);
1031 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
1032 this.with_let_management(None, |this, _| {
1033 this.visit_expr(guard_expr)
1039 ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1040 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
1043 ExprKind::While(cond, then, opt_label) => {
1044 walk_list!(this, visit_label, opt_label);
1045 this.visit_block(then);
1046 this.with_let_management(None, |this, _| this.visit_expr(cond));
1049 _ => visit::walk_expr(this, expr),
1054 fn visit_ty(&mut self, ty: &'a Ty) {
1055 self.visit_ty_common(ty);
1059 fn visit_label(&mut self, label: &'a Label) {
1060 self.check_label(label.ident);
1061 visit::walk_label(self, label);
1064 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
1065 self.check_lifetime(lifetime.ident);
1066 visit::walk_lifetime(self, lifetime);
1069 fn visit_field_def(&mut self, s: &'a FieldDef) {
1070 visit::walk_field_def(self, s)
1073 fn visit_item(&mut self, item: &'a Item) {
1074 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1075 self.has_proc_macro_decls = true;
1078 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1079 self.check_nomangle_item_asciionly(item.ident, item.span);
1083 ItemKind::Impl(box Impl {
1089 of_trait: Some(ref t),
1093 self.with_in_trait_impl(true, Some(constness), |this| {
1094 this.invalid_visibility(&item.vis, None);
1095 if let TyKind::Err = self_ty.kind {
1099 "`impl Trait for .. {}` is an obsolete syntax",
1101 .help("use `auto trait Trait {}` instead")
1104 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1109 "negative impls cannot be unsafe"
1111 .span_label(sp, "negative because of this")
1112 .span_label(span, "unsafe because of this")
1116 this.visit_vis(&item.vis);
1117 this.visit_ident(item.ident);
1118 if let Const::Yes(_) = constness {
1119 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1121 this.visit_generics(generics);
1123 this.visit_trait_ref(t);
1124 this.visit_ty(self_ty);
1126 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1128 return; // Avoid visiting again.
1130 ItemKind::Impl(box Impl {
1140 let error = |annotation_span, annotation| {
1141 let mut err = self.err_handler().struct_span_err(
1143 &format!("inherent impls cannot be {}", annotation),
1145 err.span_label(annotation_span, &format!("{} because of this", annotation));
1146 err.span_label(self_ty.span, "inherent impl for this type");
1150 self.invalid_visibility(
1152 Some("place qualifiers on individual impl items instead"),
1154 if let Unsafe::Yes(span) = unsafety {
1155 error(span, "unsafe").code(error_code!(E0197)).emit();
1157 if let ImplPolarity::Negative(span) = polarity {
1158 error(span, "negative").emit();
1160 if let Defaultness::Default(def_span) = defaultness {
1161 error(def_span, "`default`")
1162 .note("only trait implementations may be annotated with `default`")
1165 if let Const::Yes(span) = constness {
1166 error(span, "`const`")
1167 .note("only trait implementations may be annotated with `const`")
1171 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1172 self.check_defaultness(item.span, defaultness);
1175 let msg = "free function without a body";
1176 self.error_item_without_body(item.span, "function", msg, " { <body> }");
1178 self.visit_vis(&item.vis);
1179 self.visit_ident(item.ident);
1180 if let Const::Yes(_) = sig.header.constness {
1181 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1183 self.visit_generics(generics);
1185 let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
1186 self.visit_fn(kind, item.span, item.id);
1187 walk_list!(self, visit_attribute, &item.attrs);
1188 return; // Avoid visiting again.
1190 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1191 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1192 self.invalid_visibility(
1194 Some("place qualifiers on individual foreign items instead"),
1196 if let Unsafe::Yes(span) = unsafety {
1197 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1200 self.maybe_lint_missing_abi(item.span, item.id);
1202 visit::walk_item(self, item);
1203 self.extern_mod = old_item;
1204 return; // Avoid visiting again.
1206 ItemKind::Enum(ref def, _) => {
1207 for variant in &def.variants {
1208 self.invalid_visibility(&variant.vis, None);
1209 for field in variant.data.fields() {
1210 self.invalid_visibility(&field.vis, None);
1214 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1215 if is_auto == IsAuto::Yes {
1216 // Auto traits cannot have generics, super traits nor contain items.
1217 self.deny_generic_params(generics, item.ident.span);
1218 self.deny_super_traits(bounds, item.ident.span);
1219 self.deny_where_clause(&generics.where_clause, item.ident.span);
1220 self.deny_items(items, item.ident.span);
1222 self.no_questions_in_bounds(bounds, "supertraits", true);
1224 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1225 // context for the supertraits.
1226 self.visit_vis(&item.vis);
1227 self.visit_ident(item.ident);
1228 self.visit_generics(generics);
1229 self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
1230 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1231 walk_list!(self, visit_attribute, &item.attrs);
1234 ItemKind::Mod(unsafety, ref mod_kind) => {
1235 if let Unsafe::Yes(span) = unsafety {
1236 self.err_handler().span_err(span, "module cannot be declared unsafe");
1238 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1239 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1240 && !self.session.contains_name(&item.attrs, sym::path)
1242 self.check_mod_file_item_asciionly(item.ident);
1245 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1246 // Duplicating the `Visitor` logic allows catching all cases
1247 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1249 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1250 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1251 // it uses `visit_ty_common`, which doesn't contain that specific check.
1252 VariantData::Struct(ref fields, ..) => {
1253 self.visit_vis(&item.vis);
1254 self.visit_ident(item.ident);
1255 self.visit_generics(generics);
1256 self.with_banned_assoc_ty_bound(|this| {
1257 walk_list!(this, visit_struct_field_def, fields);
1259 walk_list!(self, visit_attribute, &item.attrs);
1264 ItemKind::Union(ref vdata, ref generics) => {
1265 if vdata.fields().is_empty() {
1266 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1269 VariantData::Struct(ref fields, ..) => {
1270 self.visit_vis(&item.vis);
1271 self.visit_ident(item.ident);
1272 self.visit_generics(generics);
1273 self.with_banned_assoc_ty_bound(|this| {
1274 walk_list!(this, visit_struct_field_def, fields);
1276 walk_list!(self, visit_attribute, &item.attrs);
1282 ItemKind::Const(def, .., None) => {
1283 self.check_defaultness(item.span, def);
1284 let msg = "free constant item without body";
1285 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1287 ItemKind::Static(.., None) => {
1288 let msg = "free static item without body";
1289 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1291 ItemKind::TyAlias(box TyAlias {
1298 self.check_defaultness(item.span, defaultness);
1300 let msg = "free type alias without body";
1301 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1303 self.check_type_no_bounds(bounds, "this context");
1304 if where_clauses.1.0 {
1305 let mut err = self.err_handler().struct_span_err(
1307 "where clauses are not allowed after the type for type aliases",
1310 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1318 visit::walk_item(self, item);
1321 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1323 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1324 self.check_defaultness(fi.span, *defaultness);
1325 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1326 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1327 self.check_foreign_item_ascii_only(fi.ident);
1329 ForeignItemKind::TyAlias(box TyAlias {
1337 self.check_defaultness(fi.span, *defaultness);
1338 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1339 self.check_type_no_bounds(bounds, "`extern` blocks");
1340 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1341 self.check_foreign_item_ascii_only(fi.ident);
1343 ForeignItemKind::Static(_, _, body) => {
1344 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1345 self.check_foreign_item_ascii_only(fi.ident);
1347 ForeignItemKind::MacCall(..) => {}
1350 visit::walk_foreign_item(self, fi)
1353 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1354 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1355 match *generic_args {
1356 GenericArgs::AngleBracketed(ref data) => {
1357 self.check_generic_args_before_constraints(data);
1359 for arg in &data.args {
1361 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1362 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1363 // are allowed to contain nested `impl Trait`.
1364 AngleBracketedArg::Constraint(constraint) => {
1365 self.with_impl_trait(None, |this| {
1366 this.visit_assoc_constraint_from_generic_args(constraint);
1372 GenericArgs::Parenthesized(ref data) => {
1373 walk_list!(self, visit_ty, &data.inputs);
1374 if let FnRetTy::Ty(ty) = &data.output {
1375 // `-> Foo` syntax is essentially an associated type binding,
1376 // so it is also allowed to contain nested `impl Trait`.
1377 self.with_impl_trait(None, |this| this.visit_ty(ty));
1383 fn visit_generics(&mut self, generics: &'a Generics) {
1384 let mut prev_param_default = None;
1385 for param in &generics.params {
1387 GenericParamKind::Lifetime => (),
1388 GenericParamKind::Type { default: Some(_), .. }
1389 | GenericParamKind::Const { default: Some(_), .. } => {
1390 prev_param_default = Some(param.ident.span);
1392 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1393 if let Some(span) = prev_param_default {
1394 let mut err = self.err_handler().struct_span_err(
1396 "generic parameters with a default must be trailing",
1405 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1407 for predicate in &generics.where_clause.predicates {
1408 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1409 deny_equality_constraints(self, predicate, generics);
1412 walk_list!(self, visit_generic_param, &generics.params);
1413 for predicate in &generics.where_clause.predicates {
1415 WherePredicate::BoundPredicate(bound_pred) => {
1416 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1417 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1419 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1420 // binder and thus we only allow a single level of quantification. However,
1421 // the syntax of Rust permits quantification in two places in where clauses,
1422 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1423 // defined, then error.
1424 if !bound_pred.bound_generic_params.is_empty() {
1425 for bound in &bound_pred.bounds {
1427 GenericBound::Trait(t, _) => {
1428 if !t.bound_generic_params.is_empty() {
1433 "nested quantification of lifetimes"
1438 GenericBound::Outlives(_) => {}
1445 self.visit_where_predicate(predicate);
1449 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1450 if let GenericParamKind::Lifetime { .. } = param.kind {
1451 self.check_lifetime(param.ident);
1453 visit::walk_generic_param(self, param);
1456 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1458 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1459 if !self.is_tilde_const_allowed {
1461 .struct_span_err(bound.span(), "`~const` is not allowed here")
1462 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1467 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1469 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1475 visit::walk_param_bound(self, bound)
1478 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1479 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1480 visit::walk_poly_trait_ref(self, t, m);
1483 fn visit_variant_data(&mut self, s: &'a VariantData) {
1484 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1489 enum_definition: &'a EnumDef,
1490 generics: &'a Generics,
1494 self.with_banned_assoc_ty_bound(|this| {
1495 visit::walk_enum_def(this, enum_definition, generics, item_id)
1499 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1500 // Only associated `fn`s can have `self` parameters.
1501 let self_semantic = match fk.ctxt() {
1502 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1503 _ => SelfSemantic::No,
1505 self.check_fn_decl(fk.decl(), self_semantic);
1507 self.check_c_variadic_type(fk);
1509 // Functions cannot both be `const async`
1510 if let Some(FnHeader {
1511 constness: Const::Yes(cspan),
1512 asyncness: Async::Yes { span: aspan, .. },
1518 vec![*cspan, *aspan],
1519 "functions cannot be both `const` and `async`",
1521 .span_label(*cspan, "`const` because of this")
1522 .span_label(*aspan, "`async` because of this")
1523 .span_label(span, "") // Point at the fn header.
1530 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
1535 self.maybe_lint_missing_abi(*sig_span, id);
1538 // Functions without bodies cannot have patterns.
1539 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1540 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1541 let (code, msg, label) = match ctxt {
1542 FnCtxt::Foreign => (
1544 "patterns aren't allowed in foreign function declarations",
1545 "pattern not allowed in foreign function",
1549 "patterns aren't allowed in functions without bodies",
1550 "pattern not allowed in function without body",
1553 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1554 if let Some(ident) = ident {
1555 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1556 self.lint_buffer.buffer_lint_with_diagnostic(
1557 PATTERNS_IN_FNS_WITHOUT_BODY,
1566 .struct_span_err(span, msg)
1567 .span_label(span, label)
1574 visit::walk_fn(self, fk, span);
1577 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1578 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1579 self.check_nomangle_item_asciionly(item.ident, item.span);
1582 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1583 self.check_defaultness(item.span, item.kind.defaultness());
1586 if ctxt == AssocCtxt::Impl {
1588 AssocItemKind::Const(_, _, body) => {
1589 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1591 AssocItemKind::Fn(box Fn { body, .. }) => {
1592 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1594 AssocItemKind::TyAlias(box TyAlias {
1597 where_predicates_split,
1602 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1603 self.check_type_no_bounds(bounds, "`impl`s");
1605 self.check_gat_where(
1607 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1616 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1617 self.invalid_visibility(&item.vis, None);
1618 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1619 self.check_trait_fn_not_const(sig.header.constness);
1620 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1624 if let AssocItemKind::Const(..) = item.kind {
1625 self.check_item_named(item.ident, "const");
1629 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1630 if ctxt == AssocCtxt::Trait =>
1632 self.visit_vis(&item.vis);
1633 self.visit_ident(item.ident);
1634 walk_list!(self, visit_attribute, &item.attrs);
1635 self.with_tilde_const_allowed(|this| {
1636 this.visit_generics(generics);
1637 walk_list!(this, visit_param_bound, bounds);
1639 walk_list!(self, visit_ty, ty);
1641 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1642 if self.in_const_trait_impl
1643 || ctxt == AssocCtxt::Trait
1644 || matches!(sig.header.constness, Const::Yes(_)) =>
1646 self.visit_vis(&item.vis);
1647 self.visit_ident(item.ident);
1648 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1650 FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
1651 self.visit_fn(kind, item.span, item.id);
1654 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1659 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1660 /// like it's setting an associated type, provide an appropriate suggestion.
1661 fn deny_equality_constraints(
1662 this: &mut AstValidator<'_>,
1663 predicate: &WhereEqPredicate,
1664 generics: &Generics,
1666 let mut err = this.err_handler().struct_span_err(
1668 "equality constraints are not yet supported in `where` clauses",
1670 err.span_label(predicate.span, "not supported");
1672 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1673 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1674 if let TyKind::Path(None, path) = &qself.ty.kind {
1675 match &path.segments[..] {
1676 [PathSegment { ident, args: None, .. }] => {
1677 for param in &generics.params {
1678 if param.ident == *ident {
1680 match &full_path.segments[qself.position..] {
1681 [PathSegment { ident, args, .. }] => {
1682 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1683 let mut assoc_path = full_path.clone();
1684 // Remove `Bar` from `Foo::Bar`.
1685 assoc_path.segments.pop();
1686 let len = assoc_path.segments.len() - 1;
1687 let gen_args = args.as_ref().map(|p| (**p).clone());
1688 // Build `<Bar = RhsTy>`.
1689 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1690 id: rustc_ast::node_id::DUMMY_NODE_ID,
1693 kind: AssocConstraintKind::Equality {
1694 term: predicate.rhs_ty.clone().into(),
1698 // Add `<Bar = RhsTy>` to `Foo`.
1699 match &mut assoc_path.segments[len].args {
1700 Some(args) => match args.deref_mut() {
1701 GenericArgs::Parenthesized(_) => continue,
1702 GenericArgs::AngleBracketed(args) => {
1703 args.args.push(arg);
1707 *empty_args = AngleBracketedArgs {
1714 err.span_suggestion_verbose(
1717 "if `{}` is an associated type you're trying to set, \
1718 use the associated type binding syntax",
1724 pprust::path_to_string(&assoc_path)
1726 Applicability::MaybeIncorrect,
1738 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1739 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1740 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1741 for param in &generics.params {
1742 if param.ident == potential_param.ident {
1743 for bound in ¶m.bounds {
1744 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1746 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1747 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1748 potential_assoc.ident,
1750 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1751 let (args, span) = match &trait_segment.args {
1752 Some(args) => match args.deref() {
1753 ast::GenericArgs::AngleBracketed(args) => {
1754 let Some(arg) = args.args.last() else {
1758 format!(", {} = {}", assoc, ty),
1759 arg.span().shrink_to_hi(),
1765 format!("<{} = {}>", assoc, ty),
1766 trait_segment.span().shrink_to_hi(),
1769 err.multipart_suggestion(
1771 "if `{}::{}` is an associated type you're trying to set, \
1772 use the associated type binding syntax",
1773 trait_segment.ident, potential_assoc.ident,
1775 vec![(span, args), (predicate.span, String::new())],
1776 Applicability::MaybeIncorrect,
1786 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1791 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1792 let mut validator = AstValidator {
1795 in_trait_impl: false,
1796 in_const_trait_impl: false,
1797 has_proc_macro_decls: false,
1798 outer_impl_trait: None,
1799 is_tilde_const_allowed: false,
1800 is_impl_trait_banned: false,
1801 is_assoc_ty_bound_banned: false,
1802 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1805 visit::walk_crate(&mut validator, krate);
1807 validator.has_proc_macro_decls
1810 /// Used to forbid `let` expressions in certain syntactic locations.
1811 #[derive(Clone, Copy)]
1812 enum ForbiddenLetReason {
1813 /// A let chain with the `||` operator
1814 ForbiddenWithOr(Span),
1815 /// `let` is not valid and the source environment is not important