1 // Validate AST before lowering it to HIR.
3 // This pass is supposed to catch things that fit into AST data structures,
4 // but not permitted by the language. It runs after expansion when AST is frozen,
5 // so it can check for erroneous constructions produced by syntax extensions.
6 // This pass is supposed to perform only simple checks not requiring name resolution
7 // or type checking or some other kind of complex analysis.
9 use itertools::{Either, Itertools};
10 use rustc_ast::ptr::P;
11 use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
12 use rustc_ast::walk_list;
14 use rustc_ast_pretty::pprust::{self, State};
15 use rustc_data_structures::fx::FxHashMap;
16 use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
17 use rustc_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};
32 const MORE_EXTERN: &str =
33 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
35 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
41 struct AstValidator<'a> {
44 /// The span of the `extern` in an `extern { ... }` block, if any.
45 extern_mod: Option<&'a Item>,
47 /// Are we inside a trait impl?
50 in_const_trait_impl: bool,
52 has_proc_macro_decls: bool,
54 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
55 /// Nested `impl Trait` _is_ allowed in associated type position,
56 /// e.g., `impl Iterator<Item = impl Debug>`.
57 outer_impl_trait: Option<Span>,
59 is_tilde_const_allowed: bool,
61 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
62 /// or `Foo::Bar<impl Trait>`
63 is_impl_trait_banned: bool,
65 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
66 /// certain positions.
67 is_assoc_ty_bound_banned: bool,
69 /// See [ForbiddenLetReason]
70 forbidden_let_reason: Option<ForbiddenLetReason>,
72 lint_buffer: &'a mut LintBuffer,
75 impl<'a> AstValidator<'a> {
76 fn with_in_trait_impl(
79 constness: Option<Const>,
80 f: impl FnOnce(&mut Self),
82 let old = mem::replace(&mut self.in_trait_impl, is_in);
84 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
86 self.in_trait_impl = old;
87 self.in_const_trait_impl = old_const;
90 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
91 let old = mem::replace(&mut self.is_impl_trait_banned, true);
93 self.is_impl_trait_banned = old;
96 fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
97 let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
99 self.is_tilde_const_allowed = old;
102 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
103 self.with_tilde_const(true, f)
106 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
107 self.with_tilde_const(false, f)
110 fn with_let_management(
112 forbidden_let_reason: Option<ForbiddenLetReason>,
113 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
115 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
117 self.forbidden_let_reason = old;
120 /// Emits an error banning the `let` expression provided in the given location.
121 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
122 let sess = &self.session;
123 if sess.opts.unstable_features.is_nightly_build() {
124 sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
126 sess.emit_err(ForbiddenLetStable { span: expr.span });
133 before_predicates: &[WherePredicate],
134 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
136 if !before_predicates.is_empty() {
137 let mut state = State::new();
138 if !where_clauses.1.0 {
140 state.word_space("where");
142 state.word_space(",");
144 let mut first = true;
145 for p in before_predicates.iter() {
147 state.word_space(",");
150 state.print_where_predicate(p);
152 let suggestion = state.s.eof();
153 self.lint_buffer.buffer_lint_with_diagnostic(
154 DEPRECATED_WHERE_CLAUSE_LOCATION,
157 fluent::ast_passes::deprecated_where_clause_location,
158 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
159 where_clauses.1.1.shrink_to_hi(),
166 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
167 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
169 self.is_assoc_ty_bound_banned = old;
172 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
173 let old = mem::replace(&mut self.outer_impl_trait, outer);
175 self.with_banned_tilde_const(f);
179 self.outer_impl_trait = old;
182 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
183 match constraint.kind {
184 AssocConstraintKind::Equality { .. } => {}
185 AssocConstraintKind::Bound { .. } => {
186 if self.is_assoc_ty_bound_banned {
187 self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
191 self.visit_assoc_constraint(constraint);
194 // Mirrors `visit::walk_ty`, but tracks relevant state.
195 fn walk_ty(&mut self, t: &'a Ty) {
197 TyKind::ImplTrait(..) => {
198 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
200 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
201 TyKind::Path(ref qself, ref path) => {
203 // - `Option<impl Trait>`
204 // - `option::Option<impl Trait>`
205 // - `option::Option<T>::Foo<impl Trait>
208 // - `<impl Trait>::Foo`
209 // - `option::Option<impl Trait>::Foo`.
211 // To implement this, we disallow `impl Trait` from `qself`
212 // (for cases like `<impl Trait>::Foo>`)
213 // but we allow `impl Trait` in `GenericArgs`
214 // iff there are no more PathSegments.
215 if let Some(ref qself) = *qself {
216 // `impl Trait` in `qself` is always illegal
217 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
220 // Note that there should be a call to visit_path here,
221 // so if any logic is added to process `Path`s a call to it should be
222 // added both in visit_path and here. This code mirrors visit::walk_path.
223 for (i, segment) in path.segments.iter().enumerate() {
224 // Allow `impl Trait` iff we're on the final path segment
225 if i == path.segments.len() - 1 {
226 self.visit_path_segment(path.span, segment);
228 self.with_banned_impl_trait(|this| {
229 this.visit_path_segment(path.span, segment)
234 _ => visit::walk_ty(self, t),
238 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
239 if let Some(ident) = field.ident {
240 if ident.name == kw::Underscore {
241 self.visit_vis(&field.vis);
242 self.visit_ident(ident);
243 self.visit_ty_common(&field.ty);
244 self.walk_ty(&field.ty);
245 walk_list!(self, visit_attribute, &field.attrs);
249 self.visit_field_def(field);
252 fn err_handler(&self) -> &rustc_errors::Handler {
253 &self.session.diagnostic()
256 fn check_lifetime(&self, ident: Ident) {
257 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
258 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
259 self.session.emit_err(KeywordLifetime { span: ident.span });
263 fn check_label(&self, ident: Ident) {
264 if ident.without_first_quote().is_reserved() {
265 self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
269 fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
270 if let VisibilityKind::Inherited = vis.kind {
274 self.session.emit_err(InvalidVisibility {
276 implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
281 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
282 for Param { pat, .. } in &decl.inputs {
284 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
285 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
286 report_err(pat.span, Some(ident), true)
288 _ => report_err(pat.span, None, false),
293 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
294 if let Async::Yes { span, .. } = asyncness {
295 self.session.emit_err(TraitFnAsync { fn_span, span });
299 fn check_trait_fn_not_const(&self, constness: Const) {
300 if let Const::Yes(span) = constness {
301 self.session.emit_err(TraitFnConst { span });
305 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
306 // Check only lifetime parameters are present and that the lifetime
307 // parameters that are present have no bounds.
308 let non_lt_param_spans: Vec<_> = params
310 .filter_map(|param| match param.kind {
311 GenericParamKind::Lifetime { .. } => {
312 if !param.bounds.is_empty() {
313 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
314 self.session.emit_err(ForbiddenLifetimeBound { spans });
318 _ => Some(param.ident.span),
321 if !non_lt_param_spans.is_empty() {
322 self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
326 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
327 self.check_decl_num_args(fn_decl);
328 self.check_decl_cvaradic_pos(fn_decl);
329 self.check_decl_attrs(fn_decl);
330 self.check_decl_self_param(fn_decl, self_semantic);
333 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
334 /// Error is fatal to prevent errors during typechecking
335 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
336 let max_num_args: usize = u16::MAX.into();
337 if fn_decl.inputs.len() > max_num_args {
338 let Param { span, .. } = fn_decl.inputs[0];
339 self.session.emit_fatal(FnParamTooMany { span, max_num_args });
343 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
344 match &*fn_decl.inputs {
345 [Param { ty, span, .. }] => {
346 if let TyKind::CVarArgs = ty.kind {
347 self.session.emit_err(FnParamCVarArgsOnly { span: *span });
351 for Param { ty, span, .. } in ps {
352 if let TyKind::CVarArgs = ty.kind {
353 self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
361 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
365 .flat_map(|i| i.attrs.as_ref())
376 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
379 if attr.is_doc_comment() {
380 self.session.emit_err(FnParamDocComment { span: attr.span });
382 self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
387 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
388 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
390 self.session.emit_err(FnParamForbiddenSelf { span: param.span });
395 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
396 if let Defaultness::Default(def_span) = defaultness {
397 let span = self.session.source_map().guess_head_span(span);
398 self.session.emit_err(ForbiddenDefault { span, def_span });
402 /// If `sp` ends with a semicolon, returns it as a `Span`
403 /// Otherwise, returns `sp.shrink_to_hi()`
404 fn ending_semi_or_hi(&self, sp: Span) -> Span {
405 let source_map = self.session.source_map();
406 let end = source_map.end_point(sp);
408 if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
415 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
416 let span = match bounds {
419 [b0, .., bl] => b0.span().to(bl.span()),
422 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
426 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
427 let cannot_have = |span, descr, remove_descr| {
431 &format!("`type`s inside `extern` blocks cannot have {}", descr),
435 &format!("remove the {}", remove_descr),
437 Applicability::MaybeIncorrect,
439 .span_label(self.current_extern_span(), "`extern` block begins here")
444 if !generics.params.is_empty() {
445 cannot_have(generics.span, "generic parameters", "generic parameters");
448 if !generics.where_clause.predicates.is_empty() {
449 cannot_have(where_span, "`where` clauses", "`where` clause");
453 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
454 let Some(body) = body else {
458 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
459 .span_label(ident.span, "cannot have a body")
460 .span_label(body, "the invalid body")
462 self.current_extern_span(),
464 "`extern` blocks define existing foreign {0}s and {0}s \
465 inside of them cannot have a body",
473 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
474 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
475 let Some(body) = body else {
479 .struct_span_err(ident.span, "incorrect function inside `extern` block")
480 .span_label(ident.span, "cannot have a body")
483 "remove the invalid body",
485 Applicability::MaybeIncorrect,
488 "you might have meant to write a function accessible through FFI, \
489 which can be done by writing `extern fn` outside of the `extern` block",
492 self.current_extern_span(),
493 "`extern` blocks define existing foreign functions and functions \
494 inside of them cannot have a body",
500 fn current_extern_span(&self) -> Span {
501 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
504 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
505 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
506 if header.has_qualifiers() {
508 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
509 .span_label(self.current_extern_span(), "in this `extern` block")
510 .span_suggestion_verbose(
511 span.until(ident.span.shrink_to_lo()),
512 "remove the qualifiers",
514 Applicability::MaybeIncorrect,
520 /// An item in `extern { ... }` cannot use non-ascii identifier.
521 fn check_foreign_item_ascii_only(&self, ident: Ident) {
522 if !ident.as_str().is_ascii() {
527 "items in `extern` blocks cannot use non-ascii identifiers",
529 .span_label(self.current_extern_span(), "in this `extern` block")
531 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
538 /// Reject C-variadic type unless the function is foreign,
539 /// or free and `unsafe extern "C"` semantically.
540 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
541 match (fk.ctxt(), fk.header()) {
542 (Some(FnCtxt::Foreign), _) => return,
543 (Some(FnCtxt::Free), Some(header)) => match header.ext {
544 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
545 | Extern::Implicit(_)
546 if matches!(header.unsafety, Unsafe::Yes(_)) =>
555 for Param { ty, span, .. } in &fk.decl().inputs {
556 if let TyKind::CVarArgs = ty.kind {
560 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
567 fn check_item_named(&self, ident: Ident, kind: &str) {
568 if ident.name != kw::Underscore {
572 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
573 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
577 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
578 if ident.name.as_str().is_ascii() {
581 let head_span = self.session.source_map().guess_head_span(item_span);
586 "`#[no_mangle]` requires ASCII identifier"
591 fn check_mod_file_item_asciionly(&self, ident: Ident) {
592 if ident.name.as_str().is_ascii() {
599 "trying to load file for module `{}` with non-ascii identifier name",
602 .help("consider using `#[path]` attribute to specify filesystem path")
606 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
607 if !generics.params.is_empty() {
612 "auto traits cannot have generic parameters"
614 .span_label(ident_span, "auto trait cannot have generic parameters")
617 "remove the parameters",
619 Applicability::MachineApplicable,
625 fn emit_e0568(&self, span: Span, ident_span: Span) {
630 "auto traits cannot have super traits or lifetime bounds"
632 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
635 "remove the super traits or lifetime bounds",
637 Applicability::MachineApplicable,
642 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
643 if let [.., last] = &bounds[..] {
644 let span = ident_span.shrink_to_hi().to(last.span());
645 self.emit_e0568(span, ident_span);
649 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
650 if !where_clause.predicates.is_empty() {
651 self.emit_e0568(where_clause.span, ident_span);
655 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
656 if !trait_items.is_empty() {
657 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
658 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
663 "auto traits cannot have associated items"
667 "remove these associated items",
669 Applicability::MachineApplicable,
671 .span_label(ident_span, "auto trait cannot have associated items")
676 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
677 // Lifetimes always come first.
678 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
679 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
680 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
684 let args_sugg = data.args.iter().filter_map(|a| match a {
685 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
688 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
690 // Constraints always come last.
691 let constraint_sugg = data.args.iter().filter_map(|a| match a {
692 AngleBracketedArg::Arg(_) => None,
693 AngleBracketedArg::Constraint(c) => {
694 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
699 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
703 /// Enforce generic args coming before constraints in `<...>` of a path segment.
704 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
705 // Early exit in case it's partitioned as it should be.
706 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
709 // Find all generic argument coming after the first constraint...
710 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
711 data.args.iter().partition_map(|arg| match arg {
712 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
713 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
715 let args_len = arg_spans.len();
716 let constraint_len = constraint_spans.len();
717 // ...and then error:
721 "generic arguments must come before the first constraint",
723 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
725 *arg_spans.iter().last().unwrap(),
726 &format!("generic argument{}", pluralize!(args_len)),
728 .span_labels(constraint_spans, "")
729 .span_labels(arg_spans, "")
730 .span_suggestion_verbose(
733 "move the constraint{} after the generic argument{}",
734 pluralize!(constraint_len),
737 self.correct_generic_order_suggestion(&data),
738 Applicability::MachineApplicable,
743 fn visit_ty_common(&mut self, ty: &'a Ty) {
745 TyKind::BareFn(ref bfty) => {
746 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
747 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
752 "patterns aren't allowed in function pointer types"
756 self.check_late_bound_lifetime_defs(&bfty.generic_params);
757 if let Extern::Implicit(_) = bfty.ext {
758 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
759 self.maybe_lint_missing_abi(sig_span, ty.id);
762 TyKind::TraitObject(ref bounds, ..) => {
763 let mut any_lifetime_bounds = false;
764 for bound in bounds {
765 if let GenericBound::Outlives(ref lifetime) = *bound {
766 if any_lifetime_bounds {
771 "only a single explicit lifetime bound is permitted"
776 any_lifetime_bounds = true;
780 TyKind::ImplTrait(_, ref bounds) => {
781 if self.is_impl_trait_banned {
786 "`impl Trait` is not allowed in path parameters"
791 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
796 "nested `impl Trait` is not allowed"
798 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
799 .span_label(ty.span, "nested `impl Trait` here")
803 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
804 self.err_handler().span_err(ty.span, "at least one trait must be specified");
811 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
812 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
813 // call site which do not have a macro backtrace. See #61963.
814 let is_macro_callsite = self
817 .span_to_snippet(span)
818 .map(|snippet| snippet.starts_with("#["))
820 if !is_macro_callsite {
821 self.lint_buffer.buffer_lint_with_diagnostic(
825 "extern declarations without an explicit ABI are deprecated",
826 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
832 /// Checks that generic parameters are in the correct order,
833 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
834 fn validate_generic_param_order(
835 handler: &rustc_errors::Handler,
836 generics: &[GenericParam],
839 let mut max_param: Option<ParamKindOrd> = None;
840 let mut out_of_order = FxHashMap::default();
841 let mut param_idents = Vec::with_capacity(generics.len());
843 for (idx, param) in generics.iter().enumerate() {
844 let ident = param.ident;
845 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
846 let (ord_kind, ident) = match ¶m.kind {
847 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
848 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
849 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
850 let ty = pprust::ty_to_string(ty);
851 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
854 param_idents.push((kind, ord_kind, bounds, idx, ident));
856 Some(max_param) if max_param > ord_kind => {
857 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
860 Some(_) | None => max_param = Some(ord_kind),
864 if !out_of_order.is_empty() {
865 let mut ordered_params = "<".to_string();
866 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
867 let mut first = true;
868 for (kind, _, bounds, _, ident) in param_idents {
870 ordered_params += ", ";
872 ordered_params += &ident;
874 if !bounds.is_empty() {
875 ordered_params += ": ";
876 ordered_params += &pprust::bounds_to_string(&bounds);
880 GenericParamKind::Type { default: Some(default) } => {
881 ordered_params += " = ";
882 ordered_params += &pprust::ty_to_string(default);
884 GenericParamKind::Type { default: None } => (),
885 GenericParamKind::Lifetime => (),
886 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
887 ordered_params += " = ";
888 ordered_params += &pprust::expr_to_string(&*default.value);
890 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
895 ordered_params += ">";
897 for (param_ord, (max_param, spans)) in &out_of_order {
898 let mut err = handler.struct_span_err(
901 "{} parameters must be declared prior to {} parameters",
902 param_ord, max_param,
907 "reorder the parameters: lifetimes, then consts and types",
909 Applicability::MachineApplicable,
916 impl<'a> Visitor<'a> for AstValidator<'a> {
917 fn visit_attribute(&mut self, attr: &Attribute) {
918 validate_attr::check_meta(&self.session.parse_sess, attr);
921 fn visit_expr(&mut self, expr: &'a Expr) {
922 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
924 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
925 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
926 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
927 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
929 ExprKind::If(cond, then, opt_else) => {
930 this.visit_block(then);
931 walk_list!(this, visit_expr, opt_else);
932 this.with_let_management(None, |this, _| this.visit_expr(cond));
935 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
936 this.ban_let_expr(expr, elem);
938 ExprKind::Match(scrutinee, arms) => {
939 this.visit_expr(scrutinee);
941 this.visit_expr(&arm.body);
942 this.visit_pat(&arm.pat);
943 walk_list!(this, visit_attribute, &arm.attrs);
944 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
945 this.with_let_management(None, |this, _| {
946 this.visit_expr(guard_expr)
952 ExprKind::Paren(local_expr) => {
953 fn has_let_expr(expr: &Expr) -> bool {
955 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
956 ExprKind::Let(..) => true,
960 let local_reason = if has_let_expr(local_expr) {
961 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
966 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
968 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
969 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
972 ExprKind::While(cond, then, opt_label) => {
973 walk_list!(this, visit_label, opt_label);
974 this.visit_block(then);
975 this.with_let_management(None, |this, _| this.visit_expr(cond));
978 _ => visit::walk_expr(this, expr),
983 fn visit_ty(&mut self, ty: &'a Ty) {
984 self.visit_ty_common(ty);
988 fn visit_label(&mut self, label: &'a Label) {
989 self.check_label(label.ident);
990 visit::walk_label(self, label);
993 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
994 self.check_lifetime(lifetime.ident);
995 visit::walk_lifetime(self, lifetime);
998 fn visit_field_def(&mut self, s: &'a FieldDef) {
999 visit::walk_field_def(self, s)
1002 fn visit_item(&mut self, item: &'a Item) {
1003 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1004 self.has_proc_macro_decls = true;
1007 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1008 self.check_nomangle_item_asciionly(item.ident, item.span);
1012 ItemKind::Impl(box Impl {
1018 of_trait: Some(ref t),
1022 self.with_in_trait_impl(true, Some(constness), |this| {
1023 this.invalid_visibility(&item.vis, None);
1024 if let TyKind::Err = self_ty.kind {
1028 "`impl Trait for .. {}` is an obsolete syntax",
1030 .help("use `auto trait Trait {}` instead")
1033 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1038 "negative impls cannot be unsafe"
1040 .span_label(sp, "negative because of this")
1041 .span_label(span, "unsafe because of this")
1045 this.visit_vis(&item.vis);
1046 this.visit_ident(item.ident);
1047 if let Const::Yes(_) = constness {
1048 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1050 this.visit_generics(generics);
1052 this.visit_trait_ref(t);
1053 this.visit_ty(self_ty);
1055 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1057 return; // Avoid visiting again.
1059 ItemKind::Impl(box Impl {
1069 let error = |annotation_span, annotation| {
1070 let mut err = self.err_handler().struct_span_err(
1072 &format!("inherent impls cannot be {}", annotation),
1074 err.span_label(annotation_span, &format!("{} because of this", annotation));
1075 err.span_label(self_ty.span, "inherent impl for this type");
1079 self.invalid_visibility(
1081 Some(InvalidVisibilityNote::IndividualImplItems),
1083 if let Unsafe::Yes(span) = unsafety {
1084 error(span, "unsafe").code(error_code!(E0197)).emit();
1086 if let ImplPolarity::Negative(span) = polarity {
1087 error(span, "negative").emit();
1089 if let Defaultness::Default(def_span) = defaultness {
1090 error(def_span, "`default`")
1091 .note("only trait implementations may be annotated with `default`")
1094 if let Const::Yes(span) = constness {
1095 error(span, "`const`")
1096 .note("only trait implementations may be annotated with `const`")
1100 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1101 self.check_defaultness(item.span, defaultness);
1104 self.session.emit_err(FnWithoutBody {
1106 replace_span: self.ending_semi_or_hi(item.span),
1107 extern_block_suggestion: match sig.header.ext {
1108 Extern::None => None,
1109 Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1111 end_span: item.span.shrink_to_hi(),
1114 Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1116 end_span: item.span.shrink_to_hi(),
1117 abi: Some(abi.symbol_unescaped),
1123 self.visit_vis(&item.vis);
1124 self.visit_ident(item.ident);
1126 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1127 self.visit_fn(kind, item.span, item.id);
1128 walk_list!(self, visit_attribute, &item.attrs);
1129 return; // Avoid visiting again.
1131 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1132 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1133 self.invalid_visibility(
1135 Some(InvalidVisibilityNote::IndividualForeignItems),
1137 if let Unsafe::Yes(span) = unsafety {
1138 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1141 self.maybe_lint_missing_abi(item.span, item.id);
1143 visit::walk_item(self, item);
1144 self.extern_mod = old_item;
1145 return; // Avoid visiting again.
1147 ItemKind::Enum(ref def, _) => {
1148 for variant in &def.variants {
1149 self.invalid_visibility(&variant.vis, None);
1150 for field in variant.data.fields() {
1151 self.invalid_visibility(&field.vis, None);
1155 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1156 if is_auto == IsAuto::Yes {
1157 // Auto traits cannot have generics, super traits nor contain items.
1158 self.deny_generic_params(generics, item.ident.span);
1159 self.deny_super_traits(bounds, item.ident.span);
1160 self.deny_where_clause(&generics.where_clause, item.ident.span);
1161 self.deny_items(items, item.ident.span);
1164 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1165 // context for the supertraits.
1166 self.visit_vis(&item.vis);
1167 self.visit_ident(item.ident);
1168 self.visit_generics(generics);
1169 self.with_tilde_const_allowed(|this| {
1170 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1172 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1173 walk_list!(self, visit_attribute, &item.attrs);
1176 ItemKind::Mod(unsafety, ref mod_kind) => {
1177 if let Unsafe::Yes(span) = unsafety {
1178 self.err_handler().span_err(span, "module cannot be declared unsafe");
1180 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1181 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1182 && !self.session.contains_name(&item.attrs, sym::path)
1184 self.check_mod_file_item_asciionly(item.ident);
1187 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1188 // Duplicating the `Visitor` logic allows catching all cases
1189 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1191 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1192 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1193 // it uses `visit_ty_common`, which doesn't contain that specific check.
1194 VariantData::Struct(ref fields, ..) => {
1195 self.visit_vis(&item.vis);
1196 self.visit_ident(item.ident);
1197 self.visit_generics(generics);
1198 self.with_banned_assoc_ty_bound(|this| {
1199 walk_list!(this, visit_struct_field_def, fields);
1201 walk_list!(self, visit_attribute, &item.attrs);
1206 ItemKind::Union(ref vdata, ref generics) => {
1207 if vdata.fields().is_empty() {
1208 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1211 VariantData::Struct(ref fields, ..) => {
1212 self.visit_vis(&item.vis);
1213 self.visit_ident(item.ident);
1214 self.visit_generics(generics);
1215 self.with_banned_assoc_ty_bound(|this| {
1216 walk_list!(this, visit_struct_field_def, fields);
1218 walk_list!(self, visit_attribute, &item.attrs);
1224 ItemKind::Const(def, .., None) => {
1225 self.check_defaultness(item.span, def);
1226 self.session.emit_err(ConstWithoutBody {
1228 replace_span: self.ending_semi_or_hi(item.span),
1231 ItemKind::Static(.., None) => {
1232 self.session.emit_err(StaticWithoutBody {
1234 replace_span: self.ending_semi_or_hi(item.span),
1237 ItemKind::TyAlias(box TyAlias {
1244 self.check_defaultness(item.span, defaultness);
1246 self.session.emit_err(TyAliasWithoutBody {
1248 replace_span: self.ending_semi_or_hi(item.span),
1251 self.check_type_no_bounds(bounds, "this context");
1252 if where_clauses.1.0 {
1253 let mut err = self.err_handler().struct_span_err(
1255 "where clauses are not allowed after the type for type aliases",
1258 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1266 visit::walk_item(self, item);
1269 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1271 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1272 self.check_defaultness(fi.span, *defaultness);
1273 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1274 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1275 self.check_foreign_item_ascii_only(fi.ident);
1277 ForeignItemKind::TyAlias(box TyAlias {
1285 self.check_defaultness(fi.span, *defaultness);
1286 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1287 self.check_type_no_bounds(bounds, "`extern` blocks");
1288 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1289 self.check_foreign_item_ascii_only(fi.ident);
1291 ForeignItemKind::Static(_, _, body) => {
1292 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1293 self.check_foreign_item_ascii_only(fi.ident);
1295 ForeignItemKind::MacCall(..) => {}
1298 visit::walk_foreign_item(self, fi)
1301 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1302 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1303 match *generic_args {
1304 GenericArgs::AngleBracketed(ref data) => {
1305 self.check_generic_args_before_constraints(data);
1307 for arg in &data.args {
1309 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1310 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1311 // are allowed to contain nested `impl Trait`.
1312 AngleBracketedArg::Constraint(constraint) => {
1313 self.with_impl_trait(None, |this| {
1314 this.visit_assoc_constraint_from_generic_args(constraint);
1320 GenericArgs::Parenthesized(ref data) => {
1321 walk_list!(self, visit_ty, &data.inputs);
1322 if let FnRetTy::Ty(ty) = &data.output {
1323 // `-> Foo` syntax is essentially an associated type binding,
1324 // so it is also allowed to contain nested `impl Trait`.
1325 self.with_impl_trait(None, |this| this.visit_ty(ty));
1331 fn visit_generics(&mut self, generics: &'a Generics) {
1332 let mut prev_param_default = None;
1333 for param in &generics.params {
1335 GenericParamKind::Lifetime => (),
1336 GenericParamKind::Type { default: Some(_), .. }
1337 | GenericParamKind::Const { default: Some(_), .. } => {
1338 prev_param_default = Some(param.ident.span);
1340 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1341 if let Some(span) = prev_param_default {
1342 let mut err = self.err_handler().struct_span_err(
1344 "generic parameters with a default must be trailing",
1353 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1355 for predicate in &generics.where_clause.predicates {
1356 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1357 deny_equality_constraints(self, predicate, generics);
1360 walk_list!(self, visit_generic_param, &generics.params);
1361 for predicate in &generics.where_clause.predicates {
1363 WherePredicate::BoundPredicate(bound_pred) => {
1364 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1365 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1367 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1368 // binder and thus we only allow a single level of quantification. However,
1369 // the syntax of Rust permits quantification in two places in where clauses,
1370 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1371 // defined, then error.
1372 if !bound_pred.bound_generic_params.is_empty() {
1373 for bound in &bound_pred.bounds {
1375 GenericBound::Trait(t, _) => {
1376 if !t.bound_generic_params.is_empty() {
1381 "nested quantification of lifetimes"
1386 GenericBound::Outlives(_) => {}
1393 self.visit_where_predicate(predicate);
1397 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1398 if let GenericParamKind::Lifetime { .. } = param.kind {
1399 self.check_lifetime(param.ident);
1401 visit::walk_generic_param(self, param);
1404 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1405 if let GenericBound::Trait(ref poly, modify) = *bound {
1406 match (ctxt, modify) {
1407 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1410 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1411 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1412 err.note(&format!("traits are `?{}` by default", path_str));
1415 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1416 let mut err = self.err_handler().struct_span_err(
1418 "`?Trait` is not permitted in trait object types",
1422 (_, TraitBoundModifier::MaybeConst) => {
1423 if !self.is_tilde_const_allowed {
1425 .struct_span_err(bound.span(), "`~const` is not allowed here")
1426 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1430 (_, TraitBoundModifier::MaybeConstMaybe) => {
1432 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1438 visit::walk_param_bound(self, bound)
1441 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1442 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1443 visit::walk_poly_trait_ref(self, t);
1446 fn visit_variant_data(&mut self, s: &'a VariantData) {
1447 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1450 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1451 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1454 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1455 // Only associated `fn`s can have `self` parameters.
1456 let self_semantic = match fk.ctxt() {
1457 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1458 _ => SelfSemantic::No,
1460 self.check_fn_decl(fk.decl(), self_semantic);
1462 self.check_c_variadic_type(fk);
1464 // Functions cannot both be `const async`
1465 if let Some(FnHeader {
1466 constness: Const::Yes(cspan),
1467 asyncness: Async::Yes { span: aspan, .. },
1473 vec![*cspan, *aspan],
1474 "functions cannot be both `const` and `async`",
1476 .span_label(*cspan, "`const` because of this")
1477 .span_label(*aspan, "`async` because of this")
1478 .span_label(span, "") // Point at the fn header.
1482 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1483 self.check_late_bound_lifetime_defs(generic_params);
1489 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1495 self.maybe_lint_missing_abi(*sig_span, id);
1498 // Functions without bodies cannot have patterns.
1499 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1500 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1501 let (code, msg, label) = match ctxt {
1502 FnCtxt::Foreign => (
1504 "patterns aren't allowed in foreign function declarations",
1505 "pattern not allowed in foreign function",
1509 "patterns aren't allowed in functions without bodies",
1510 "pattern not allowed in function without body",
1513 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1514 if let Some(ident) = ident {
1515 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1516 self.lint_buffer.buffer_lint_with_diagnostic(
1517 PATTERNS_IN_FNS_WITHOUT_BODY,
1526 .struct_span_err(span, msg)
1527 .span_label(span, label)
1534 let tilde_const_allowed =
1535 matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1536 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1538 self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
1541 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1542 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1543 self.check_nomangle_item_asciionly(item.ident, item.span);
1546 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1547 self.check_defaultness(item.span, item.kind.defaultness());
1550 if ctxt == AssocCtxt::Impl {
1552 AssocItemKind::Const(_, _, body) => {
1554 self.session.emit_err(AssocConstWithoutBody {
1556 replace_span: self.ending_semi_or_hi(item.span),
1560 AssocItemKind::Fn(box Fn { body, .. }) => {
1562 self.session.emit_err(AssocFnWithoutBody {
1564 replace_span: self.ending_semi_or_hi(item.span),
1568 AssocItemKind::TyAlias(box TyAlias {
1571 where_predicates_split,
1577 self.session.emit_err(AssocTypeWithoutBody {
1579 replace_span: self.ending_semi_or_hi(item.span),
1582 self.check_type_no_bounds(bounds, "`impl`s");
1584 self.check_gat_where(
1586 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1595 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1596 self.invalid_visibility(&item.vis, None);
1597 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1598 self.check_trait_fn_not_const(sig.header.constness);
1599 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1603 if let AssocItemKind::Const(..) = item.kind {
1604 self.check_item_named(item.ident, "const");
1608 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1609 if ctxt == AssocCtxt::Trait =>
1611 self.visit_vis(&item.vis);
1612 self.visit_ident(item.ident);
1613 walk_list!(self, visit_attribute, &item.attrs);
1614 self.with_tilde_const_allowed(|this| {
1615 this.visit_generics(generics);
1616 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1618 walk_list!(self, visit_ty, ty);
1620 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1621 if self.in_const_trait_impl
1622 || ctxt == AssocCtxt::Trait
1623 || matches!(sig.header.constness, Const::Yes(_)) =>
1625 self.visit_vis(&item.vis);
1626 self.visit_ident(item.ident);
1627 let kind = FnKind::Fn(
1628 FnCtxt::Assoc(ctxt),
1635 self.visit_fn(kind, item.span, item.id);
1638 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1643 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1644 /// like it's setting an associated type, provide an appropriate suggestion.
1645 fn deny_equality_constraints(
1646 this: &mut AstValidator<'_>,
1647 predicate: &WhereEqPredicate,
1648 generics: &Generics,
1650 let mut err = this.err_handler().struct_span_err(
1652 "equality constraints are not yet supported in `where` clauses",
1654 err.span_label(predicate.span, "not supported");
1656 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1657 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1658 if let TyKind::Path(None, path) = &qself.ty.kind {
1659 match &path.segments[..] {
1660 [PathSegment { ident, args: None, .. }] => {
1661 for param in &generics.params {
1662 if param.ident == *ident {
1664 match &full_path.segments[qself.position..] {
1665 [PathSegment { ident, args, .. }] => {
1666 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1667 let mut assoc_path = full_path.clone();
1668 // Remove `Bar` from `Foo::Bar`.
1669 assoc_path.segments.pop();
1670 let len = assoc_path.segments.len() - 1;
1671 let gen_args = args.as_ref().map(|p| (**p).clone());
1672 // Build `<Bar = RhsTy>`.
1673 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1674 id: rustc_ast::node_id::DUMMY_NODE_ID,
1677 kind: AssocConstraintKind::Equality {
1678 term: predicate.rhs_ty.clone().into(),
1682 // Add `<Bar = RhsTy>` to `Foo`.
1683 match &mut assoc_path.segments[len].args {
1684 Some(args) => match args.deref_mut() {
1685 GenericArgs::Parenthesized(_) => continue,
1686 GenericArgs::AngleBracketed(args) => {
1687 args.args.push(arg);
1691 *empty_args = AngleBracketedArgs {
1698 err.span_suggestion_verbose(
1701 "if `{}` is an associated type you're trying to set, \
1702 use the associated type binding syntax",
1708 pprust::path_to_string(&assoc_path)
1710 Applicability::MaybeIncorrect,
1722 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1723 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1724 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1725 for param in &generics.params {
1726 if param.ident == potential_param.ident {
1727 for bound in ¶m.bounds {
1728 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1730 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1731 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1732 potential_assoc.ident,
1734 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1735 let (args, span) = match &trait_segment.args {
1736 Some(args) => match args.deref() {
1737 ast::GenericArgs::AngleBracketed(args) => {
1738 let Some(arg) = args.args.last() else {
1742 format!(", {} = {}", assoc, ty),
1743 arg.span().shrink_to_hi(),
1749 format!("<{} = {}>", assoc, ty),
1750 trait_segment.span().shrink_to_hi(),
1753 err.multipart_suggestion(
1755 "if `{}::{}` is an associated type you're trying to set, \
1756 use the associated type binding syntax",
1757 trait_segment.ident, potential_assoc.ident,
1759 vec![(span, args), (predicate.span, String::new())],
1760 Applicability::MaybeIncorrect,
1770 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1775 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1776 let mut validator = AstValidator {
1779 in_trait_impl: false,
1780 in_const_trait_impl: false,
1781 has_proc_macro_decls: false,
1782 outer_impl_trait: None,
1783 is_tilde_const_allowed: false,
1784 is_impl_trait_banned: false,
1785 is_assoc_ty_bound_banned: false,
1786 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1789 visit::walk_crate(&mut validator, krate);
1791 validator.has_proc_macro_decls
1794 /// Used to forbid `let` expressions in certain syntactic locations.
1795 #[derive(Clone, Copy)]
1796 pub(crate) enum ForbiddenLetReason {
1797 /// `let` is not valid and the source environment is not important
1799 /// A let chain with the `||` operator
1800 NotSupportedOr(Span),
1801 /// A let chain with invalid parentheses
1803 /// For example, `let 1 = 1 && (expr && expr)` is allowed
1804 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1805 NotSupportedParentheses(Span),