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 rustc_ast_pretty::pprust;
10 use rustc_data_structures::fx::FxHashMap;
11 use rustc_errors::{error_code, struct_span_err, Applicability, FatalError};
12 use rustc_parse::validate_attr;
13 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
14 use rustc_session::lint::LintBuffer;
15 use rustc_session::Session;
16 use rustc_span::symbol::{kw, sym};
21 use syntax::expand::is_proc_macro_attr;
22 use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
23 use syntax::walk_list;
25 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
31 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
32 #[derive(Clone, Copy)]
40 fn description(&self) -> &'static str {
42 Self::ImplTrait => "`impl Trait`",
43 Self::TraitBounds => "supertraits",
44 Self::TraitObject => "trait objects",
49 struct AstValidator<'a> {
52 /// The span of the `extern` in an `extern { ... }` block, if any.
53 extern_mod: Option<&'a Item>,
55 /// Are we inside a trait impl?
58 has_proc_macro_decls: bool,
60 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
61 /// Nested `impl Trait` _is_ allowed in associated type position,
62 /// e.g., `impl Iterator<Item = impl Debug>`.
63 outer_impl_trait: Option<Span>,
65 /// Keeps track of the `BoundContext` as we recurse.
67 /// This is used to forbid `?const Trait` bounds in, e.g.,
68 /// `impl Iterator<Item = Box<dyn ?const Trait>`.
69 bound_context: Option<BoundContext>,
71 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
72 /// or `Foo::Bar<impl Trait>`
73 is_impl_trait_banned: bool,
75 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
76 /// certain positions.
77 is_assoc_ty_bound_banned: bool,
79 lint_buffer: &'a mut LintBuffer,
82 impl<'a> AstValidator<'a> {
83 fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
84 let old = mem::replace(&mut self.in_trait_impl, is_in);
86 self.in_trait_impl = old;
89 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
90 let old = mem::replace(&mut self.is_impl_trait_banned, true);
92 self.is_impl_trait_banned = old;
95 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
96 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
98 self.is_assoc_ty_bound_banned = old;
101 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
102 let old = mem::replace(&mut self.outer_impl_trait, outer);
104 self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
108 self.outer_impl_trait = old;
111 fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
112 let old = self.bound_context.replace(ctx);
114 self.bound_context = old;
117 fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
118 match constraint.kind {
119 AssocTyConstraintKind::Equality { .. } => {}
120 AssocTyConstraintKind::Bound { .. } => {
121 if self.is_assoc_ty_bound_banned {
122 self.err_handler().span_err(
124 "associated type bounds are not allowed within structs, enums, or unions",
129 self.visit_assoc_ty_constraint(constraint);
132 // Mirrors `visit::walk_ty`, but tracks relevant state.
133 fn walk_ty(&mut self, t: &'a Ty) {
135 TyKind::ImplTrait(..) => {
136 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
138 TyKind::TraitObject(..) => {
139 self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
141 TyKind::Path(ref qself, ref path) => {
143 // - `Option<impl Trait>`
144 // - `option::Option<impl Trait>`
145 // - `option::Option<T>::Foo<impl Trait>
148 // - `<impl Trait>::Foo`
149 // - `option::Option<impl Trait>::Foo`.
151 // To implement this, we disallow `impl Trait` from `qself`
152 // (for cases like `<impl Trait>::Foo>`)
153 // but we allow `impl Trait` in `GenericArgs`
154 // iff there are no more PathSegments.
155 if let Some(ref qself) = *qself {
156 // `impl Trait` in `qself` is always illegal
157 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
160 // Note that there should be a call to visit_path here,
161 // so if any logic is added to process `Path`s a call to it should be
162 // added both in visit_path and here. This code mirrors visit::walk_path.
163 for (i, segment) in path.segments.iter().enumerate() {
164 // Allow `impl Trait` iff we're on the final path segment
165 if i == path.segments.len() - 1 {
166 self.visit_path_segment(path.span, segment);
168 self.with_banned_impl_trait(|this| {
169 this.visit_path_segment(path.span, segment)
174 _ => visit::walk_ty(self, t),
178 fn err_handler(&self) -> &rustc_errors::Handler {
179 &self.session.diagnostic()
182 fn check_lifetime(&self, ident: Ident) {
183 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
184 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
185 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
189 fn check_label(&self, ident: Ident) {
190 if ident.without_first_quote().is_reserved() {
192 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
196 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
197 if let VisibilityKind::Inherited = vis.node {
202 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
203 if vis.node.is_pub() {
204 err.span_label(vis.span, "`pub` not permitted here because it's implied");
206 if let Some(note) = note {
212 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
213 for Param { pat, .. } in &decl.inputs {
215 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
216 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
217 report_err(pat.span, true)
219 _ => report_err(pat.span, false),
224 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
225 if let Async::Yes { span, .. } = asyncness {
230 "functions in traits cannot be declared `async`"
232 .span_label(span, "`async` because of this")
233 .note("`async` trait functions are not currently supported")
234 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
239 fn check_trait_fn_not_const(&self, constness: Const) {
240 if let Const::Yes(span) = constness {
245 "functions in traits cannot be declared const"
247 .span_label(span, "functions in traits cannot be const")
252 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
253 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
254 for bound in bounds {
255 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
256 let mut err = self.err_handler().struct_span_err(
258 &format!("`?Trait` is not permitted in {}", where_),
261 let path_str = pprust::path_to_string(&poly.trait_ref.path);
262 err.note(&format!("traits are `?{}` by default", path_str));
269 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
270 /// or paths for ranges.
272 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
273 // That means making this work:
275 // ```rust,ignore (FIXME)
284 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
286 ExprKind::Lit(..) | ExprKind::Err => {}
287 ExprKind::Path(..) if allow_paths => {}
288 ExprKind::Unary(UnOp::Neg, ref inner)
289 if match inner.kind {
290 ExprKind::Lit(_) => true,
293 _ => self.err_handler().span_err(
295 "arbitrary expressions aren't allowed \
301 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
302 // Check only lifetime parameters are present and that the lifetime
303 // parameters that are present have no bounds.
304 let non_lt_param_spans: Vec<_> = params
306 .filter_map(|param| match param.kind {
307 GenericParamKind::Lifetime { .. } => {
308 if !param.bounds.is_empty() {
309 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
311 .span_err(spans, "lifetime bounds cannot be used in this context");
315 _ => Some(param.ident.span),
318 if !non_lt_param_spans.is_empty() {
319 self.err_handler().span_err(
321 "only lifetime parameters can be used in this context",
326 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
327 self.check_decl_cvaradic_pos(fn_decl);
328 self.check_decl_attrs(fn_decl);
329 self.check_decl_self_param(fn_decl, self_semantic);
332 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
333 match &*fn_decl.inputs {
334 [Param { ty, span, .. }] => {
335 if let TyKind::CVarArgs = ty.kind {
336 self.err_handler().span_err(
338 "C-variadic function must be declared with at least one named argument",
343 for Param { ty, span, .. } in ps {
344 if let TyKind::CVarArgs = ty.kind {
345 self.err_handler().span_err(
347 "`...` must be the last argument of a C-variadic function",
356 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
360 .flat_map(|i| i.attrs.as_ref())
362 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
363 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
366 if attr.is_doc_comment() {
370 "documentation comments cannot be applied to function parameters",
372 .span_label(attr.span, "doc comments are not allowed here")
375 self.err_handler().span_err(
377 "allow, cfg, cfg_attr, deny, \
378 forbid, and warn are the only allowed built-in attributes in function parameters",
384 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
385 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
390 "`self` parameter is only allowed in associated functions",
392 .span_label(param.span, "not semantically valid as function parameter")
393 .note("associated functions are those in `impl` or `trait` definitions")
399 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
400 if let Defaultness::Default = defaultness {
402 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
407 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
409 .struct_span_err(sp, msg)
411 self.session.source_map().end_point(sp),
412 &format!("provide a definition for the {}", ctx),
414 Applicability::HasPlaceholders,
419 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
421 let msg = format!("associated {} in `impl` without body", ctx);
422 self.error_item_without_body(sp, ctx, &msg, sugg);
426 fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
427 let span = match bounds {
430 [b0, .., bl] => b0.span().to(bl.span()),
433 .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
437 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
438 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
439 let body = match body {
444 .struct_span_err(ident.span, "incorrect function inside `extern` block")
445 .span_label(ident.span, "cannot have a body")
448 "remove the invalid body",
450 Applicability::MaybeIncorrect,
453 "you might have meant to write a function accessible through FFI, \
454 which can be done by writing `extern fn` outside of the `extern` block",
457 self.current_extern_span(),
458 "`extern` blocks define existing foreign functions and functions \
459 inside of them cannot have a body",
461 .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
465 fn current_extern_span(&self) -> Span {
466 self.session.source_map().def_span(self.extern_mod.unwrap().span)
469 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
470 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
471 if header.has_qualifiers() {
473 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
474 .span_label(self.current_extern_span(), "in this `extern` block")
476 span.until(ident.span.shrink_to_lo()),
477 "remove the qualifiers",
479 Applicability::MaybeIncorrect,
485 /// Reject C-varadic type unless the function is foreign,
486 /// or free and `unsafe extern "C"` semantically.
487 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
488 match (fk.ctxt(), fk.header()) {
489 (Some(FnCtxt::Foreign), _) => return,
490 (Some(FnCtxt::Free), Some(header)) => match header.ext {
491 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
492 if matches!(header.unsafety, Unsafe::Yes(_)) =>
501 for Param { ty, span, .. } in &fk.decl().inputs {
502 if let TyKind::CVarArgs = ty.kind {
506 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
513 /// We currently do not permit const generics in `const fn`,
514 /// as this is tantamount to allowing compile-time dependent typing.
516 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
517 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
518 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
519 if let Const::Yes(const_span) = sig.header.constness {
520 // Look for const generics and error if we find any.
521 for param in &generics.params {
522 if let GenericParamKind::Const { .. } = param.kind {
526 "const parameters are not permitted in const functions",
528 .span_label(const_span, "`const` because of this")
536 enum GenericPosition {
541 fn validate_generics_order<'a>(
543 handler: &rustc_errors::Handler,
544 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
545 pos: GenericPosition,
548 let mut max_param: Option<ParamKindOrd> = None;
549 let mut out_of_order = FxHashMap::default();
550 let mut param_idents = vec![];
551 let mut found_type = false;
552 let mut found_const = false;
554 for (kind, bounds, span, ident) in generics {
555 if let Some(ident) = ident {
556 param_idents.push((kind, bounds, param_idents.len(), ident));
558 let max_param = &mut max_param;
560 Some(max_param) if *max_param > kind => {
561 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
564 Some(_) | None => *max_param = Some(kind),
567 ParamKindOrd::Type => found_type = true,
568 ParamKindOrd::Const => found_const = true,
573 let mut ordered_params = "<".to_string();
574 if !out_of_order.is_empty() {
575 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
576 let mut first = true;
577 for (_, bounds, _, ident) in param_idents {
579 ordered_params += ", ";
581 ordered_params += &ident;
582 if let Some(bounds) = bounds {
583 if !bounds.is_empty() {
584 ordered_params += ": ";
585 ordered_params += &pprust::bounds_to_string(&bounds);
591 ordered_params += ">";
593 let pos_str = match pos {
594 GenericPosition::Param => "parameter",
595 GenericPosition::Arg => "argument",
598 for (param_ord, (max_param, spans)) in &out_of_order {
599 let mut err = handler.struct_span_err(
602 "{} {pos}s must be declared prior to {} {pos}s",
608 if let GenericPosition::Param = pos {
612 "reorder the {}s: lifetimes, then types{}",
614 if sess.features_untracked().const_generics { ", then consts" } else { "" },
616 ordered_params.clone(),
617 Applicability::MachineApplicable,
623 // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
624 // if we don't. Const parameters and type parameters can currently conflict if they
626 if !out_of_order.is_empty() && found_type && found_const {
631 impl<'a> Visitor<'a> for AstValidator<'a> {
632 fn visit_attribute(&mut self, attr: &Attribute) {
633 validate_attr::check_meta(&self.session.parse_sess, attr);
636 fn visit_expr(&mut self, expr: &'a Expr) {
638 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
643 "asm! is unsupported on this target"
650 visit::walk_expr(self, expr);
653 fn visit_ty(&mut self, ty: &'a Ty) {
655 TyKind::BareFn(ref bfty) => {
656 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
657 Self::check_decl_no_pat(&bfty.decl, |span, _| {
662 "patterns aren't allowed in function pointer types"
666 self.check_late_bound_lifetime_defs(&bfty.generic_params);
668 TyKind::TraitObject(ref bounds, ..) => {
669 let mut any_lifetime_bounds = false;
670 for bound in bounds {
671 if let GenericBound::Outlives(ref lifetime) = *bound {
672 if any_lifetime_bounds {
677 "only a single explicit lifetime bound is permitted"
682 any_lifetime_bounds = true;
685 self.no_questions_in_bounds(bounds, "trait object types", false);
687 TyKind::ImplTrait(_, ref bounds) => {
688 if self.is_impl_trait_banned {
693 "`impl Trait` is not allowed in path parameters"
698 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
703 "nested `impl Trait` is not allowed"
705 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
706 .span_label(ty.span, "nested `impl Trait` here")
712 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
714 self.err_handler().span_err(ty.span, "at least one trait must be specified");
726 fn visit_label(&mut self, label: &'a Label) {
727 self.check_label(label.ident);
728 visit::walk_label(self, label);
731 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
732 self.check_lifetime(lifetime.ident);
733 visit::walk_lifetime(self, lifetime);
736 fn visit_item(&mut self, item: &'a Item) {
737 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
738 self.has_proc_macro_decls = true;
752 self.with_in_trait_impl(true, |this| {
753 this.invalid_visibility(&item.vis, None);
754 if let TyKind::Err = self_ty.kind {
758 "`impl Trait for .. {}` is an obsolete syntax",
760 .help("use `auto trait Trait {}` instead")
763 if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
768 "negative impls cannot be unsafe"
770 .span_label(span, "unsafe because of this")
774 visit::walk_item(this, item);
776 return; // Avoid visiting again.
788 self.invalid_visibility(
790 Some("place qualifiers on individual impl items instead"),
792 if let Unsafe::Yes(span) = unsafety {
797 "inherent impls cannot be unsafe"
799 .span_label(span, "unsafe because of this")
802 if polarity == ImplPolarity::Negative {
803 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
805 if defaultness == Defaultness::Default {
807 .struct_span_err(item.span, "inherent impls cannot be default")
808 .note("only trait implementations may be annotated with default")
811 if let Const::Yes(span) = constness {
813 .struct_span_err(item.span, "inherent impls cannot be `const`")
814 .span_label(span, "`const` because of this")
815 .note("only trait implementations may be annotated with `const`")
819 ItemKind::Fn(ref sig, ref generics, ref body) => {
820 self.check_const_fn_const_generic(item.span, sig, generics);
823 let msg = "free function without a body";
824 self.error_item_without_body(item.span, "function", msg, " { <body> }");
827 ItemKind::ForeignMod(_) => {
828 let old_item = mem::replace(&mut self.extern_mod, Some(item));
829 self.invalid_visibility(
831 Some("place qualifiers on individual foreign items instead"),
833 visit::walk_item(self, item);
834 self.extern_mod = old_item;
835 return; // Avoid visiting again.
837 ItemKind::Enum(ref def, _) => {
838 for variant in &def.variants {
839 self.invalid_visibility(&variant.vis, None);
840 for field in variant.data.fields() {
841 self.invalid_visibility(&field.vis, None);
845 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
846 if is_auto == IsAuto::Yes {
847 // Auto traits cannot have generics, super traits nor contain items.
848 if !generics.params.is_empty() {
853 "auto traits cannot have generic parameters"
857 if !bounds.is_empty() {
862 "auto traits cannot have super traits"
866 if !trait_items.is_empty() {
871 "auto traits cannot have methods or associated items"
876 self.no_questions_in_bounds(bounds, "supertraits", true);
878 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
879 // context for the supertraits.
880 self.visit_vis(&item.vis);
881 self.visit_ident(item.ident);
882 self.visit_generics(generics);
883 self.with_bound_context(BoundContext::TraitBounds, |this| {
884 walk_list!(this, visit_param_bound, bounds);
886 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
887 walk_list!(self, visit_attribute, &item.attrs);
890 ItemKind::Mod(_) => {
891 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
892 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
894 ItemKind::Union(ref vdata, _) => {
895 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
897 .span_err(item.span, "tuple and unit unions are not permitted");
899 if vdata.fields().is_empty() {
900 self.err_handler().span_err(item.span, "unions cannot have zero fields");
906 visit::walk_item(self, item)
909 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
911 ForeignItemKind::Fn(sig, _, body) => {
912 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
913 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
915 ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
918 visit::walk_foreign_item(self, fi)
921 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
922 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
923 match *generic_args {
924 GenericArgs::AngleBracketed(ref data) => {
925 walk_list!(self, visit_generic_arg, &data.args);
926 validate_generics_order(
929 data.args.iter().map(|arg| {
932 GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
933 GenericArg::Type(..) => ParamKindOrd::Type,
934 GenericArg::Const(..) => ParamKindOrd::Const,
941 GenericPosition::Arg,
945 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
946 // are allowed to contain nested `impl Trait`.
947 self.with_impl_trait(None, |this| {
950 visit_assoc_ty_constraint_from_generic_args,
955 GenericArgs::Parenthesized(ref data) => {
956 walk_list!(self, visit_ty, &data.inputs);
957 if let FnRetTy::Ty(ty) = &data.output {
958 // `-> Foo` syntax is essentially an associated type binding,
959 // so it is also allowed to contain nested `impl Trait`.
960 self.with_impl_trait(None, |this| this.visit_ty(ty));
966 fn visit_generics(&mut self, generics: &'a Generics) {
967 let mut prev_ty_default = None;
968 for param in &generics.params {
969 if let GenericParamKind::Type { ref default, .. } = param.kind {
970 if default.is_some() {
971 prev_ty_default = Some(param.ident.span);
972 } else if let Some(span) = prev_ty_default {
974 .span_err(span, "type parameters with a default must be trailing");
980 validate_generics_order(
983 generics.params.iter().map(|param| {
984 let ident = Some(param.ident.to_string());
985 let (kind, ident) = match ¶m.kind {
986 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
987 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
988 GenericParamKind::Const { ref ty } => {
989 let ty = pprust::ty_to_string(ty);
990 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
993 (kind, Some(&*param.bounds), param.ident.span, ident)
995 GenericPosition::Param,
999 for predicate in &generics.where_clause.predicates {
1000 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1004 "equality constraints are not yet supported in `where` clauses",
1006 .span_label(predicate.span, "not supported")
1008 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1009 for more information",
1015 visit::walk_generics(self, generics)
1018 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1019 if let GenericParamKind::Lifetime { .. } = param.kind {
1020 self.check_lifetime(param.ident);
1022 visit::walk_generic_param(self, param);
1025 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1027 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1028 if let Some(ctx) = self.bound_context {
1029 let msg = format!("`?const` is not permitted in {}", ctx.description());
1030 self.err_handler().span_err(bound.span(), &msg);
1034 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1036 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1042 visit::walk_param_bound(self, bound)
1045 fn visit_pat(&mut self, pat: &'a Pat) {
1047 PatKind::Lit(ref expr) => {
1048 self.check_expr_within_pat(expr, false);
1050 PatKind::Range(ref start, ref end, _) => {
1051 if let Some(expr) = start {
1052 self.check_expr_within_pat(expr, true);
1054 if let Some(expr) = end {
1055 self.check_expr_within_pat(expr, true);
1061 visit::walk_pat(self, pat)
1064 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1065 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1066 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1067 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1069 visit::walk_where_predicate(self, p);
1072 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1073 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1074 visit::walk_poly_trait_ref(self, t, m);
1077 fn visit_variant_data(&mut self, s: &'a VariantData) {
1078 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1083 enum_definition: &'a EnumDef,
1084 generics: &'a Generics,
1088 self.with_banned_assoc_ty_bound(|this| {
1089 visit::walk_enum_def(this, enum_definition, generics, item_id)
1093 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1094 // Only associated `fn`s can have `self` parameters.
1095 let self_semantic = match fk.ctxt() {
1096 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1097 _ => SelfSemantic::No,
1099 self.check_fn_decl(fk.decl(), self_semantic);
1101 self.check_c_varadic_type(fk);
1103 // Functions cannot both be `const async`
1104 if let Some(FnHeader {
1105 constness: Const::Yes(cspan),
1106 asyncness: Async::Yes { span: aspan, .. },
1111 .struct_span_err(span, "functions cannot be both `const` and `async`")
1112 .span_label(*cspan, "`const` because of this")
1113 .span_label(*aspan, "`async` because of this")
1117 // Functions without bodies cannot have patterns.
1118 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1119 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1120 let (code, msg, label) = match ctxt {
1121 FnCtxt::Foreign => (
1123 "patterns aren't allowed in foreign function declarations",
1124 "pattern not allowed in foreign function",
1128 "patterns aren't allowed in functions without bodies",
1129 "pattern not allowed in function without body",
1132 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1133 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1136 .struct_span_err(span, msg)
1137 .span_label(span, label)
1144 visit::walk_fn(self, fk, span);
1147 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1148 if ctxt == AssocCtxt::Trait {
1149 self.check_defaultness(item.span, item.defaultness);
1152 if ctxt == AssocCtxt::Impl {
1154 AssocItemKind::Const(_, body) => {
1155 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1157 AssocItemKind::Fn(_, body) => {
1158 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1160 AssocItemKind::TyAlias(bounds, body) => {
1161 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1162 self.check_impl_assoc_type_no_bounds(bounds);
1168 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1169 self.invalid_visibility(&item.vis, None);
1170 if let AssocItemKind::Fn(sig, _) = &item.kind {
1171 self.check_trait_fn_not_const(sig.header.constness);
1172 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1176 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1180 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1181 let mut validator = AstValidator {
1184 in_trait_impl: false,
1185 has_proc_macro_decls: false,
1186 outer_impl_trait: None,
1187 bound_context: None,
1188 is_impl_trait_banned: false,
1189 is_assoc_ty_bound_banned: false,
1192 visit::walk_crate(&mut validator, krate);
1194 validator.has_proc_macro_decls