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, Diagnostic};
17 use rustc_parse::validate_attr;
18 use rustc_session::lint::builtin::{
19 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
21 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
22 use rustc_session::Session;
23 use rustc_span::source_map::Spanned;
24 use rustc_span::symbol::{kw, sym, Ident};
26 use rustc_target::spec::abi;
28 use std::ops::{Deref, DerefMut};
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 self.session.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
128 before_predicates: &[WherePredicate],
129 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
131 if !before_predicates.is_empty() {
132 let mut state = State::new();
133 if !where_clauses.1.0 {
135 state.word_space("where");
137 state.word_space(",");
139 let mut first = true;
140 for p in before_predicates.iter() {
142 state.word_space(",");
145 state.print_where_predicate(p);
147 let suggestion = state.s.eof();
148 self.lint_buffer.buffer_lint_with_diagnostic(
149 DEPRECATED_WHERE_CLAUSE_LOCATION,
152 fluent::ast_passes::deprecated_where_clause_location,
153 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
154 where_clauses.1.1.shrink_to_hi(),
161 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
162 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
164 self.is_assoc_ty_bound_banned = old;
167 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
168 let old = mem::replace(&mut self.outer_impl_trait, outer);
170 self.with_banned_tilde_const(f);
174 self.outer_impl_trait = old;
177 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
178 match constraint.kind {
179 AssocConstraintKind::Equality { .. } => {}
180 AssocConstraintKind::Bound { .. } => {
181 if self.is_assoc_ty_bound_banned {
182 self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
186 self.visit_assoc_constraint(constraint);
189 // Mirrors `visit::walk_ty`, but tracks relevant state.
190 fn walk_ty(&mut self, t: &'a Ty) {
192 TyKind::ImplTrait(..) => {
193 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
195 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
196 TyKind::Path(ref qself, ref path) => {
198 // - `Option<impl Trait>`
199 // - `option::Option<impl Trait>`
200 // - `option::Option<T>::Foo<impl Trait>
203 // - `<impl Trait>::Foo`
204 // - `option::Option<impl Trait>::Foo`.
206 // To implement this, we disallow `impl Trait` from `qself`
207 // (for cases like `<impl Trait>::Foo>`)
208 // but we allow `impl Trait` in `GenericArgs`
209 // iff there are no more PathSegments.
210 if let Some(ref qself) = *qself {
211 // `impl Trait` in `qself` is always illegal
212 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
215 // Note that there should be a call to visit_path here,
216 // so if any logic is added to process `Path`s a call to it should be
217 // added both in visit_path and here. This code mirrors visit::walk_path.
218 for (i, segment) in path.segments.iter().enumerate() {
219 // Allow `impl Trait` iff we're on the final path segment
220 if i == path.segments.len() - 1 {
221 self.visit_path_segment(path.span, segment);
223 self.with_banned_impl_trait(|this| {
224 this.visit_path_segment(path.span, segment)
229 _ => visit::walk_ty(self, t),
233 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
234 if let Some(ident) = field.ident {
235 if ident.name == kw::Underscore {
236 self.visit_vis(&field.vis);
237 self.visit_ident(ident);
238 self.visit_ty_common(&field.ty);
239 self.walk_ty(&field.ty);
240 walk_list!(self, visit_attribute, &field.attrs);
244 self.visit_field_def(field);
247 fn err_handler(&self) -> &rustc_errors::Handler {
248 &self.session.diagnostic()
251 fn check_lifetime(&self, ident: Ident) {
252 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
253 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
254 self.session.emit_err(KeywordLifetime { span: ident.span });
258 fn check_label(&self, ident: Ident) {
259 if ident.without_first_quote().is_reserved() {
260 self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
264 fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
265 if let VisibilityKind::Inherited = vis.kind {
269 self.session.emit_err(InvalidVisibility {
271 implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
276 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
277 for Param { pat, .. } in &decl.inputs {
279 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
280 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
281 report_err(pat.span, Some(ident), true)
283 _ => report_err(pat.span, None, false),
288 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
289 if let Async::Yes { span, .. } = asyncness {
290 self.session.emit_err(TraitFnAsync { fn_span, span });
294 fn check_trait_fn_not_const(&self, constness: Const) {
295 if let Const::Yes(span) = constness {
296 self.session.emit_err(TraitFnConst { span });
300 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
301 // Check only lifetime parameters are present and that the lifetime
302 // parameters that are present have no bounds.
303 let non_lt_param_spans: Vec<_> = params
305 .filter_map(|param| match param.kind {
306 GenericParamKind::Lifetime { .. } => {
307 if !param.bounds.is_empty() {
308 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
309 self.session.emit_err(ForbiddenLifetimeBound { spans });
313 _ => Some(param.ident.span),
316 if !non_lt_param_spans.is_empty() {
317 self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
321 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
322 self.check_decl_num_args(fn_decl);
323 self.check_decl_cvaradic_pos(fn_decl);
324 self.check_decl_attrs(fn_decl);
325 self.check_decl_self_param(fn_decl, self_semantic);
328 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
329 /// Error is fatal to prevent errors during typechecking
330 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
331 let max_num_args: usize = u16::MAX.into();
332 if fn_decl.inputs.len() > max_num_args {
333 let Param { span, .. } = fn_decl.inputs[0];
334 self.session.emit_err(TooManyParams { span, max_num_args });
338 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
339 match &*fn_decl.inputs {
340 [Param { ty, span, .. }] => {
341 if let TyKind::CVarArgs = ty.kind {
342 self.session.emit_err(CVarArgsWithoutNamedArg { span: *span });
346 for Param { ty, span, .. } in ps {
347 if let TyKind::CVarArgs = ty.kind {
348 self.session.emit_err(CVarArgsNotLast { span: *span });
356 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
360 .flat_map(|i| i.attrs.as_ref())
371 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
374 if attr.is_doc_comment() {
378 "documentation comments cannot be applied to function parameters",
380 .span_label(attr.span, "doc comments are not allowed here")
383 self.err_handler().span_err(
385 "allow, cfg, cfg_attr, deny, expect, \
386 forbid, and warn are the only allowed built-in attributes in function parameters",
392 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
393 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
398 "`self` parameter is only allowed in associated functions",
400 .span_label(param.span, "not semantically valid as function parameter")
401 .note("associated functions are those in `impl` or `trait` definitions")
407 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
408 if let Defaultness::Default(def_span) = defaultness {
409 let span = self.session.source_map().guess_head_span(span);
411 .struct_span_err(span, "`default` is only allowed on items in trait impls")
412 .span_label(def_span, "`default` because of this")
417 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
418 self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
421 fn error_item_without_body_with_help(
427 help: impl FnOnce(&mut Diagnostic),
429 let source_map = self.session.source_map();
430 let end = source_map.end_point(sp);
431 let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
436 let mut err = self.err_handler().struct_span_err(sp, msg);
439 &format!("provide a definition for the {}", ctx),
441 Applicability::HasPlaceholders,
447 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
449 let msg = format!("associated {} in `impl` without body", ctx);
450 self.error_item_without_body(sp, ctx, &msg, sugg);
454 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
455 let span = match bounds {
458 [b0, .., bl] => b0.span().to(bl.span()),
461 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
465 fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
466 let cannot_have = |span, descr, remove_descr| {
470 &format!("`type`s inside `extern` blocks cannot have {}", descr),
474 &format!("remove the {}", remove_descr),
476 Applicability::MaybeIncorrect,
478 .span_label(self.current_extern_span(), "`extern` block begins here")
483 if !generics.params.is_empty() {
484 cannot_have(generics.span, "generic parameters", "generic parameters");
487 if !generics.where_clause.predicates.is_empty() {
488 cannot_have(where_span, "`where` clauses", "`where` clause");
492 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
493 let Some(body) = body else {
497 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
498 .span_label(ident.span, "cannot have a body")
499 .span_label(body, "the invalid body")
501 self.current_extern_span(),
503 "`extern` blocks define existing foreign {0}s and {0}s \
504 inside of them cannot have a body",
512 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
513 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
514 let Some(body) = body else {
518 .struct_span_err(ident.span, "incorrect function inside `extern` block")
519 .span_label(ident.span, "cannot have a body")
522 "remove the invalid body",
524 Applicability::MaybeIncorrect,
527 "you might have meant to write a function accessible through FFI, \
528 which can be done by writing `extern fn` outside of the `extern` block",
531 self.current_extern_span(),
532 "`extern` blocks define existing foreign functions and functions \
533 inside of them cannot have a body",
539 fn current_extern_span(&self) -> Span {
540 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
543 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
544 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
545 if header.has_qualifiers() {
547 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
548 .span_label(self.current_extern_span(), "in this `extern` block")
549 .span_suggestion_verbose(
550 span.until(ident.span.shrink_to_lo()),
551 "remove the qualifiers",
553 Applicability::MaybeIncorrect,
559 /// An item in `extern { ... }` cannot use non-ascii identifier.
560 fn check_foreign_item_ascii_only(&self, ident: Ident) {
561 if !ident.as_str().is_ascii() {
566 "items in `extern` blocks cannot use non-ascii identifiers",
568 .span_label(self.current_extern_span(), "in this `extern` block")
570 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
577 /// Reject C-variadic type unless the function is foreign,
578 /// or free and `unsafe extern "C"` semantically.
579 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
580 match (fk.ctxt(), fk.header()) {
581 (Some(FnCtxt::Foreign), _) => return,
582 (Some(FnCtxt::Free), Some(header)) => match header.ext {
583 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
584 | Extern::Implicit(_)
585 if matches!(header.unsafety, Unsafe::Yes(_)) =>
594 for Param { ty, span, .. } in &fk.decl().inputs {
595 if let TyKind::CVarArgs = ty.kind {
599 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
606 fn check_item_named(&self, ident: Ident, kind: &str) {
607 if ident.name != kw::Underscore {
611 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
612 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
616 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
617 if ident.name.as_str().is_ascii() {
620 let head_span = self.session.source_map().guess_head_span(item_span);
625 "`#[no_mangle]` requires ASCII identifier"
630 fn check_mod_file_item_asciionly(&self, ident: Ident) {
631 if ident.name.as_str().is_ascii() {
638 "trying to load file for module `{}` with non-ascii identifier name",
641 .help("consider using `#[path]` attribute to specify filesystem path")
645 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
646 if !generics.params.is_empty() {
651 "auto traits cannot have generic parameters"
653 .span_label(ident_span, "auto trait cannot have generic parameters")
656 "remove the parameters",
658 Applicability::MachineApplicable,
664 fn emit_e0568(&self, span: Span, ident_span: Span) {
669 "auto traits cannot have super traits or lifetime bounds"
671 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
674 "remove the super traits or lifetime bounds",
676 Applicability::MachineApplicable,
681 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
682 if let [.., last] = &bounds[..] {
683 let span = ident_span.shrink_to_hi().to(last.span());
684 self.emit_e0568(span, ident_span);
688 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
689 if !where_clause.predicates.is_empty() {
690 self.emit_e0568(where_clause.span, ident_span);
694 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
695 if !trait_items.is_empty() {
696 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
697 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
702 "auto traits cannot have associated items"
706 "remove these associated items",
708 Applicability::MachineApplicable,
710 .span_label(ident_span, "auto trait cannot have associated items")
715 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
716 // Lifetimes always come first.
717 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
718 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
719 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
723 let args_sugg = data.args.iter().filter_map(|a| match a {
724 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
727 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
729 // Constraints always come last.
730 let constraint_sugg = data.args.iter().filter_map(|a| match a {
731 AngleBracketedArg::Arg(_) => None,
732 AngleBracketedArg::Constraint(c) => {
733 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
738 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
742 /// Enforce generic args coming before constraints in `<...>` of a path segment.
743 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
744 // Early exit in case it's partitioned as it should be.
745 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
748 // Find all generic argument coming after the first constraint...
749 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
750 data.args.iter().partition_map(|arg| match arg {
751 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
752 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
754 let args_len = arg_spans.len();
755 let constraint_len = constraint_spans.len();
756 // ...and then error:
760 "generic arguments must come before the first constraint",
762 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
764 *arg_spans.iter().last().unwrap(),
765 &format!("generic argument{}", pluralize!(args_len)),
767 .span_labels(constraint_spans, "")
768 .span_labels(arg_spans, "")
769 .span_suggestion_verbose(
772 "move the constraint{} after the generic argument{}",
773 pluralize!(constraint_len),
776 self.correct_generic_order_suggestion(&data),
777 Applicability::MachineApplicable,
782 fn visit_ty_common(&mut self, ty: &'a Ty) {
784 TyKind::BareFn(ref bfty) => {
785 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
786 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
791 "patterns aren't allowed in function pointer types"
795 self.check_late_bound_lifetime_defs(&bfty.generic_params);
796 if let Extern::Implicit(_) = bfty.ext {
797 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
798 self.maybe_lint_missing_abi(sig_span, ty.id);
801 TyKind::TraitObject(ref bounds, ..) => {
802 let mut any_lifetime_bounds = false;
803 for bound in bounds {
804 if let GenericBound::Outlives(ref lifetime) = *bound {
805 if any_lifetime_bounds {
810 "only a single explicit lifetime bound is permitted"
815 any_lifetime_bounds = true;
819 TyKind::ImplTrait(_, ref bounds) => {
820 if self.is_impl_trait_banned {
825 "`impl Trait` is not allowed in path parameters"
830 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
835 "nested `impl Trait` is not allowed"
837 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
838 .span_label(ty.span, "nested `impl Trait` here")
842 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
843 self.err_handler().span_err(ty.span, "at least one trait must be specified");
850 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
851 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
852 // call site which do not have a macro backtrace. See #61963.
853 let is_macro_callsite = self
856 .span_to_snippet(span)
857 .map(|snippet| snippet.starts_with("#["))
859 if !is_macro_callsite {
860 self.lint_buffer.buffer_lint_with_diagnostic(
864 "extern declarations without an explicit ABI are deprecated",
865 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
871 /// Checks that generic parameters are in the correct order,
872 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
873 fn validate_generic_param_order(
874 handler: &rustc_errors::Handler,
875 generics: &[GenericParam],
878 let mut max_param: Option<ParamKindOrd> = None;
879 let mut out_of_order = FxHashMap::default();
880 let mut param_idents = Vec::with_capacity(generics.len());
882 for (idx, param) in generics.iter().enumerate() {
883 let ident = param.ident;
884 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
885 let (ord_kind, ident) = match ¶m.kind {
886 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
887 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
888 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
889 let ty = pprust::ty_to_string(ty);
890 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
893 param_idents.push((kind, ord_kind, bounds, idx, ident));
895 Some(max_param) if max_param > ord_kind => {
896 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
899 Some(_) | None => max_param = Some(ord_kind),
903 if !out_of_order.is_empty() {
904 let mut ordered_params = "<".to_string();
905 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
906 let mut first = true;
907 for (kind, _, bounds, _, ident) in param_idents {
909 ordered_params += ", ";
911 ordered_params += &ident;
913 if !bounds.is_empty() {
914 ordered_params += ": ";
915 ordered_params += &pprust::bounds_to_string(&bounds);
919 GenericParamKind::Type { default: Some(default) } => {
920 ordered_params += " = ";
921 ordered_params += &pprust::ty_to_string(default);
923 GenericParamKind::Type { default: None } => (),
924 GenericParamKind::Lifetime => (),
925 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
926 ordered_params += " = ";
927 ordered_params += &pprust::expr_to_string(&*default.value);
929 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
934 ordered_params += ">";
936 for (param_ord, (max_param, spans)) in &out_of_order {
937 let mut err = handler.struct_span_err(
940 "{} parameters must be declared prior to {} parameters",
941 param_ord, max_param,
946 "reorder the parameters: lifetimes, then consts and types",
948 Applicability::MachineApplicable,
955 impl<'a> Visitor<'a> for AstValidator<'a> {
956 fn visit_attribute(&mut self, attr: &Attribute) {
957 validate_attr::check_meta(&self.session.parse_sess, attr);
960 fn visit_expr(&mut self, expr: &'a Expr) {
961 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
963 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
964 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
965 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
966 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
968 ExprKind::If(cond, then, opt_else) => {
969 this.visit_block(then);
970 walk_list!(this, visit_expr, opt_else);
971 this.with_let_management(None, |this, _| this.visit_expr(cond));
974 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
975 this.ban_let_expr(expr, elem);
977 ExprKind::Match(scrutinee, arms) => {
978 this.visit_expr(scrutinee);
980 this.visit_expr(&arm.body);
981 this.visit_pat(&arm.pat);
982 walk_list!(this, visit_attribute, &arm.attrs);
983 if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
984 this.with_let_management(None, |this, _| {
985 this.visit_expr(guard_expr)
991 ExprKind::Paren(local_expr) => {
992 fn has_let_expr(expr: &Expr) -> bool {
994 ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
995 ExprKind::Let(..) => true,
999 let local_reason = if has_let_expr(local_expr) {
1000 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
1003 forbidden_let_reason
1005 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
1007 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1008 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
1011 ExprKind::While(cond, then, opt_label) => {
1012 walk_list!(this, visit_label, opt_label);
1013 this.visit_block(then);
1014 this.with_let_management(None, |this, _| this.visit_expr(cond));
1017 _ => visit::walk_expr(this, expr),
1022 fn visit_ty(&mut self, ty: &'a Ty) {
1023 self.visit_ty_common(ty);
1027 fn visit_label(&mut self, label: &'a Label) {
1028 self.check_label(label.ident);
1029 visit::walk_label(self, label);
1032 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
1033 self.check_lifetime(lifetime.ident);
1034 visit::walk_lifetime(self, lifetime);
1037 fn visit_field_def(&mut self, s: &'a FieldDef) {
1038 visit::walk_field_def(self, s)
1041 fn visit_item(&mut self, item: &'a Item) {
1042 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1043 self.has_proc_macro_decls = true;
1046 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1047 self.check_nomangle_item_asciionly(item.ident, item.span);
1051 ItemKind::Impl(box Impl {
1057 of_trait: Some(ref t),
1061 self.with_in_trait_impl(true, Some(constness), |this| {
1062 this.invalid_visibility(&item.vis, None);
1063 if let TyKind::Err = self_ty.kind {
1067 "`impl Trait for .. {}` is an obsolete syntax",
1069 .help("use `auto trait Trait {}` instead")
1072 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1077 "negative impls cannot be unsafe"
1079 .span_label(sp, "negative because of this")
1080 .span_label(span, "unsafe because of this")
1084 this.visit_vis(&item.vis);
1085 this.visit_ident(item.ident);
1086 if let Const::Yes(_) = constness {
1087 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1089 this.visit_generics(generics);
1091 this.visit_trait_ref(t);
1092 this.visit_ty(self_ty);
1094 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1096 return; // Avoid visiting again.
1098 ItemKind::Impl(box Impl {
1108 let error = |annotation_span, annotation| {
1109 let mut err = self.err_handler().struct_span_err(
1111 &format!("inherent impls cannot be {}", annotation),
1113 err.span_label(annotation_span, &format!("{} because of this", annotation));
1114 err.span_label(self_ty.span, "inherent impl for this type");
1118 self.invalid_visibility(
1120 Some(InvalidVisibilityNote::IndividualImplItems),
1122 if let Unsafe::Yes(span) = unsafety {
1123 error(span, "unsafe").code(error_code!(E0197)).emit();
1125 if let ImplPolarity::Negative(span) = polarity {
1126 error(span, "negative").emit();
1128 if let Defaultness::Default(def_span) = defaultness {
1129 error(def_span, "`default`")
1130 .note("only trait implementations may be annotated with `default`")
1133 if let Const::Yes(span) = constness {
1134 error(span, "`const`")
1135 .note("only trait implementations may be annotated with `const`")
1139 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1140 self.check_defaultness(item.span, defaultness);
1143 let msg = "free function without a body";
1144 let ext = sig.header.ext;
1146 let f = |e: &mut Diagnostic| {
1147 if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
1149 let start_suggestion = if let Extern::Explicit(abi, _) = ext {
1150 format!("extern \"{}\" {{", abi.symbol_unescaped)
1152 "extern {".to_owned()
1155 let end_suggestion = " }".to_owned();
1156 let end_span = item.span.shrink_to_hi();
1159 .multipart_suggestion(
1160 "if you meant to declare an externally defined function, use an `extern` block",
1161 vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
1162 Applicability::MaybeIncorrect,
1167 self.error_item_without_body_with_help(
1176 self.visit_vis(&item.vis);
1177 self.visit_ident(item.ident);
1179 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
1180 self.visit_fn(kind, item.span, item.id);
1181 walk_list!(self, visit_attribute, &item.attrs);
1182 return; // Avoid visiting again.
1184 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1185 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1186 self.invalid_visibility(
1188 Some(InvalidVisibilityNote::IndividualForeignItems),
1190 if let Unsafe::Yes(span) = unsafety {
1191 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1194 self.maybe_lint_missing_abi(item.span, item.id);
1196 visit::walk_item(self, item);
1197 self.extern_mod = old_item;
1198 return; // Avoid visiting again.
1200 ItemKind::Enum(ref def, _) => {
1201 for variant in &def.variants {
1202 self.invalid_visibility(&variant.vis, None);
1203 for field in variant.data.fields() {
1204 self.invalid_visibility(&field.vis, None);
1208 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1209 if is_auto == IsAuto::Yes {
1210 // Auto traits cannot have generics, super traits nor contain items.
1211 self.deny_generic_params(generics, item.ident.span);
1212 self.deny_super_traits(bounds, item.ident.span);
1213 self.deny_where_clause(&generics.where_clause, item.ident.span);
1214 self.deny_items(items, item.ident.span);
1217 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1218 // context for the supertraits.
1219 self.visit_vis(&item.vis);
1220 self.visit_ident(item.ident);
1221 self.visit_generics(generics);
1222 self.with_tilde_const_allowed(|this| {
1223 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1225 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1226 walk_list!(self, visit_attribute, &item.attrs);
1229 ItemKind::Mod(unsafety, ref mod_kind) => {
1230 if let Unsafe::Yes(span) = unsafety {
1231 self.err_handler().span_err(span, "module cannot be declared unsafe");
1233 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1234 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1235 && !self.session.contains_name(&item.attrs, sym::path)
1237 self.check_mod_file_item_asciionly(item.ident);
1240 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1241 // Duplicating the `Visitor` logic allows catching all cases
1242 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1244 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1245 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1246 // it uses `visit_ty_common`, which doesn't contain that specific check.
1247 VariantData::Struct(ref fields, ..) => {
1248 self.visit_vis(&item.vis);
1249 self.visit_ident(item.ident);
1250 self.visit_generics(generics);
1251 self.with_banned_assoc_ty_bound(|this| {
1252 walk_list!(this, visit_struct_field_def, fields);
1254 walk_list!(self, visit_attribute, &item.attrs);
1259 ItemKind::Union(ref vdata, ref generics) => {
1260 if vdata.fields().is_empty() {
1261 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1264 VariantData::Struct(ref fields, ..) => {
1265 self.visit_vis(&item.vis);
1266 self.visit_ident(item.ident);
1267 self.visit_generics(generics);
1268 self.with_banned_assoc_ty_bound(|this| {
1269 walk_list!(this, visit_struct_field_def, fields);
1271 walk_list!(self, visit_attribute, &item.attrs);
1277 ItemKind::Const(def, .., None) => {
1278 self.check_defaultness(item.span, def);
1279 let msg = "free constant item without body";
1280 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1282 ItemKind::Static(.., None) => {
1283 let msg = "free static item without body";
1284 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1286 ItemKind::TyAlias(box TyAlias {
1293 self.check_defaultness(item.span, defaultness);
1295 let msg = "free type alias without body";
1296 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1298 self.check_type_no_bounds(bounds, "this context");
1299 if where_clauses.1.0 {
1300 let mut err = self.err_handler().struct_span_err(
1302 "where clauses are not allowed after the type for type aliases",
1305 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1313 visit::walk_item(self, item);
1316 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1318 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1319 self.check_defaultness(fi.span, *defaultness);
1320 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1321 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1322 self.check_foreign_item_ascii_only(fi.ident);
1324 ForeignItemKind::TyAlias(box TyAlias {
1332 self.check_defaultness(fi.span, *defaultness);
1333 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1334 self.check_type_no_bounds(bounds, "`extern` blocks");
1335 self.check_foreign_ty_genericless(generics, where_clauses.0.1);
1336 self.check_foreign_item_ascii_only(fi.ident);
1338 ForeignItemKind::Static(_, _, body) => {
1339 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1340 self.check_foreign_item_ascii_only(fi.ident);
1342 ForeignItemKind::MacCall(..) => {}
1345 visit::walk_foreign_item(self, fi)
1348 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1349 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1350 match *generic_args {
1351 GenericArgs::AngleBracketed(ref data) => {
1352 self.check_generic_args_before_constraints(data);
1354 for arg in &data.args {
1356 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1357 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1358 // are allowed to contain nested `impl Trait`.
1359 AngleBracketedArg::Constraint(constraint) => {
1360 self.with_impl_trait(None, |this| {
1361 this.visit_assoc_constraint_from_generic_args(constraint);
1367 GenericArgs::Parenthesized(ref data) => {
1368 walk_list!(self, visit_ty, &data.inputs);
1369 if let FnRetTy::Ty(ty) = &data.output {
1370 // `-> Foo` syntax is essentially an associated type binding,
1371 // so it is also allowed to contain nested `impl Trait`.
1372 self.with_impl_trait(None, |this| this.visit_ty(ty));
1378 fn visit_generics(&mut self, generics: &'a Generics) {
1379 let mut prev_param_default = None;
1380 for param in &generics.params {
1382 GenericParamKind::Lifetime => (),
1383 GenericParamKind::Type { default: Some(_), .. }
1384 | GenericParamKind::Const { default: Some(_), .. } => {
1385 prev_param_default = Some(param.ident.span);
1387 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1388 if let Some(span) = prev_param_default {
1389 let mut err = self.err_handler().struct_span_err(
1391 "generic parameters with a default must be trailing",
1400 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1402 for predicate in &generics.where_clause.predicates {
1403 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1404 deny_equality_constraints(self, predicate, generics);
1407 walk_list!(self, visit_generic_param, &generics.params);
1408 for predicate in &generics.where_clause.predicates {
1410 WherePredicate::BoundPredicate(bound_pred) => {
1411 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1412 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1414 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1415 // binder and thus we only allow a single level of quantification. However,
1416 // the syntax of Rust permits quantification in two places in where clauses,
1417 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1418 // defined, then error.
1419 if !bound_pred.bound_generic_params.is_empty() {
1420 for bound in &bound_pred.bounds {
1422 GenericBound::Trait(t, _) => {
1423 if !t.bound_generic_params.is_empty() {
1428 "nested quantification of lifetimes"
1433 GenericBound::Outlives(_) => {}
1440 self.visit_where_predicate(predicate);
1444 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1445 if let GenericParamKind::Lifetime { .. } = param.kind {
1446 self.check_lifetime(param.ident);
1448 visit::walk_generic_param(self, param);
1451 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1452 if let GenericBound::Trait(ref poly, modify) = *bound {
1453 match (ctxt, modify) {
1454 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1457 .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
1458 let path_str = pprust::path_to_string(&poly.trait_ref.path);
1459 err.note(&format!("traits are `?{}` by default", path_str));
1462 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1463 let mut err = self.err_handler().struct_span_err(
1465 "`?Trait` is not permitted in trait object types",
1469 (_, TraitBoundModifier::MaybeConst) => {
1470 if !self.is_tilde_const_allowed {
1472 .struct_span_err(bound.span(), "`~const` is not allowed here")
1473 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1477 (_, TraitBoundModifier::MaybeConstMaybe) => {
1479 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1485 visit::walk_param_bound(self, bound)
1488 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1489 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1490 visit::walk_poly_trait_ref(self, t);
1493 fn visit_variant_data(&mut self, s: &'a VariantData) {
1494 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1497 fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1498 self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1501 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1502 // Only associated `fn`s can have `self` parameters.
1503 let self_semantic = match fk.ctxt() {
1504 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1505 _ => SelfSemantic::No,
1507 self.check_fn_decl(fk.decl(), self_semantic);
1509 self.check_c_variadic_type(fk);
1511 // Functions cannot both be `const async`
1512 if let Some(FnHeader {
1513 constness: Const::Yes(cspan),
1514 asyncness: Async::Yes { span: aspan, .. },
1520 vec![*cspan, *aspan],
1521 "functions cannot be both `const` and `async`",
1523 .span_label(*cspan, "`const` because of this")
1524 .span_label(*aspan, "`async` because of this")
1525 .span_label(span, "") // Point at the fn header.
1529 if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1530 self.check_late_bound_lifetime_defs(generic_params);
1536 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1542 self.maybe_lint_missing_abi(*sig_span, id);
1545 // Functions without bodies cannot have patterns.
1546 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1547 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1548 let (code, msg, label) = match ctxt {
1549 FnCtxt::Foreign => (
1551 "patterns aren't allowed in foreign function declarations",
1552 "pattern not allowed in foreign function",
1556 "patterns aren't allowed in functions without bodies",
1557 "pattern not allowed in function without body",
1560 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1561 if let Some(ident) = ident {
1562 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1563 self.lint_buffer.buffer_lint_with_diagnostic(
1564 PATTERNS_IN_FNS_WITHOUT_BODY,
1573 .struct_span_err(span, msg)
1574 .span_label(span, label)
1581 let tilde_const_allowed =
1582 matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1583 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1585 self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
1588 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1589 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1590 self.check_nomangle_item_asciionly(item.ident, item.span);
1593 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1594 self.check_defaultness(item.span, item.kind.defaultness());
1597 if ctxt == AssocCtxt::Impl {
1599 AssocItemKind::Const(_, _, body) => {
1600 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1602 AssocItemKind::Fn(box Fn { body, .. }) => {
1603 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1605 AssocItemKind::TyAlias(box TyAlias {
1608 where_predicates_split,
1613 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1614 self.check_type_no_bounds(bounds, "`impl`s");
1616 self.check_gat_where(
1618 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1627 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1628 self.invalid_visibility(&item.vis, None);
1629 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1630 self.check_trait_fn_not_const(sig.header.constness);
1631 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1635 if let AssocItemKind::Const(..) = item.kind {
1636 self.check_item_named(item.ident, "const");
1640 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1641 if ctxt == AssocCtxt::Trait =>
1643 self.visit_vis(&item.vis);
1644 self.visit_ident(item.ident);
1645 walk_list!(self, visit_attribute, &item.attrs);
1646 self.with_tilde_const_allowed(|this| {
1647 this.visit_generics(generics);
1648 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1650 walk_list!(self, visit_ty, ty);
1652 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1653 if self.in_const_trait_impl
1654 || ctxt == AssocCtxt::Trait
1655 || matches!(sig.header.constness, Const::Yes(_)) =>
1657 self.visit_vis(&item.vis);
1658 self.visit_ident(item.ident);
1659 let kind = FnKind::Fn(
1660 FnCtxt::Assoc(ctxt),
1667 self.visit_fn(kind, item.span, item.id);
1670 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1675 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1676 /// like it's setting an associated type, provide an appropriate suggestion.
1677 fn deny_equality_constraints(
1678 this: &mut AstValidator<'_>,
1679 predicate: &WhereEqPredicate,
1680 generics: &Generics,
1682 let mut err = this.err_handler().struct_span_err(
1684 "equality constraints are not yet supported in `where` clauses",
1686 err.span_label(predicate.span, "not supported");
1688 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1689 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1690 if let TyKind::Path(None, path) = &qself.ty.kind {
1691 match &path.segments[..] {
1692 [PathSegment { ident, args: None, .. }] => {
1693 for param in &generics.params {
1694 if param.ident == *ident {
1696 match &full_path.segments[qself.position..] {
1697 [PathSegment { ident, args, .. }] => {
1698 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1699 let mut assoc_path = full_path.clone();
1700 // Remove `Bar` from `Foo::Bar`.
1701 assoc_path.segments.pop();
1702 let len = assoc_path.segments.len() - 1;
1703 let gen_args = args.as_ref().map(|p| (**p).clone());
1704 // Build `<Bar = RhsTy>`.
1705 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1706 id: rustc_ast::node_id::DUMMY_NODE_ID,
1709 kind: AssocConstraintKind::Equality {
1710 term: predicate.rhs_ty.clone().into(),
1714 // Add `<Bar = RhsTy>` to `Foo`.
1715 match &mut assoc_path.segments[len].args {
1716 Some(args) => match args.deref_mut() {
1717 GenericArgs::Parenthesized(_) => continue,
1718 GenericArgs::AngleBracketed(args) => {
1719 args.args.push(arg);
1723 *empty_args = AngleBracketedArgs {
1730 err.span_suggestion_verbose(
1733 "if `{}` is an associated type you're trying to set, \
1734 use the associated type binding syntax",
1740 pprust::path_to_string(&assoc_path)
1742 Applicability::MaybeIncorrect,
1754 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1755 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1756 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1757 for param in &generics.params {
1758 if param.ident == potential_param.ident {
1759 for bound in ¶m.bounds {
1760 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1762 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1763 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1764 potential_assoc.ident,
1766 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1767 let (args, span) = match &trait_segment.args {
1768 Some(args) => match args.deref() {
1769 ast::GenericArgs::AngleBracketed(args) => {
1770 let Some(arg) = args.args.last() else {
1774 format!(", {} = {}", assoc, ty),
1775 arg.span().shrink_to_hi(),
1781 format!("<{} = {}>", assoc, ty),
1782 trait_segment.span().shrink_to_hi(),
1785 err.multipart_suggestion(
1787 "if `{}::{}` is an associated type you're trying to set, \
1788 use the associated type binding syntax",
1789 trait_segment.ident, potential_assoc.ident,
1791 vec![(span, args), (predicate.span, String::new())],
1792 Applicability::MaybeIncorrect,
1802 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1807 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1808 let mut validator = AstValidator {
1811 in_trait_impl: false,
1812 in_const_trait_impl: false,
1813 has_proc_macro_decls: false,
1814 outer_impl_trait: None,
1815 is_tilde_const_allowed: false,
1816 is_impl_trait_banned: false,
1817 is_assoc_ty_bound_banned: false,
1818 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1821 visit::walk_crate(&mut validator, krate);
1823 validator.has_proc_macro_decls
1826 /// Used to forbid `let` expressions in certain syntactic locations.
1827 #[derive(Clone, Copy)]
1828 pub(crate) enum ForbiddenLetReason {
1829 /// `let` is not valid and the source environment is not important
1831 /// A let chain with the `||` operator
1832 NotSupportedOr(Span),
1833 /// A let chain with invalid parentheses
1835 /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
1836 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1837 NotSupportedParentheses(Span),