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::source_map::Spanned;
17 use rustc_span::symbol::{kw, sym};
22 use syntax::expand::is_proc_macro_attr;
23 use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
24 use syntax::walk_list;
26 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
32 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
33 #[derive(Clone, Copy)]
41 fn description(&self) -> &'static str {
43 Self::ImplTrait => "`impl Trait`",
44 Self::TraitBounds => "supertraits",
45 Self::TraitObject => "trait objects",
50 struct AstValidator<'a> {
53 /// The span of the `extern` in an `extern { ... }` block, if any.
54 extern_mod: Option<&'a Item>,
56 /// Are we inside a trait impl?
59 has_proc_macro_decls: bool,
61 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
62 /// Nested `impl Trait` _is_ allowed in associated type position,
63 /// e.g., `impl Iterator<Item = impl Debug>`.
64 outer_impl_trait: Option<Span>,
66 /// Keeps track of the `BoundContext` as we recurse.
68 /// This is used to forbid `?const Trait` bounds in, e.g.,
69 /// `impl Iterator<Item = Box<dyn ?const Trait>`.
70 bound_context: Option<BoundContext>,
72 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
73 /// or `Foo::Bar<impl Trait>`
74 is_impl_trait_banned: bool,
76 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
77 /// certain positions.
78 is_assoc_ty_bound_banned: bool,
80 lint_buffer: &'a mut LintBuffer,
83 impl<'a> AstValidator<'a> {
84 fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
85 let old = mem::replace(&mut self.in_trait_impl, is_in);
87 self.in_trait_impl = old;
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_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
97 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
99 self.is_assoc_ty_bound_banned = old;
102 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
103 let old = mem::replace(&mut self.outer_impl_trait, outer);
105 self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
109 self.outer_impl_trait = old;
112 fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
113 let old = self.bound_context.replace(ctx);
115 self.bound_context = old;
118 fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
119 match constraint.kind {
120 AssocTyConstraintKind::Equality { .. } => {}
121 AssocTyConstraintKind::Bound { .. } => {
122 if self.is_assoc_ty_bound_banned {
123 self.err_handler().span_err(
125 "associated type bounds are not allowed within structs, enums, or unions",
130 self.visit_assoc_ty_constraint(constraint);
133 // Mirrors `visit::walk_ty`, but tracks relevant state.
134 fn walk_ty(&mut self, t: &'a Ty) {
136 TyKind::ImplTrait(..) => {
137 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
139 TyKind::TraitObject(..) => {
140 self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
142 TyKind::Path(ref qself, ref path) => {
144 // - `Option<impl Trait>`
145 // - `option::Option<impl Trait>`
146 // - `option::Option<T>::Foo<impl Trait>
149 // - `<impl Trait>::Foo`
150 // - `option::Option<impl Trait>::Foo`.
152 // To implement this, we disallow `impl Trait` from `qself`
153 // (for cases like `<impl Trait>::Foo>`)
154 // but we allow `impl Trait` in `GenericArgs`
155 // iff there are no more PathSegments.
156 if let Some(ref qself) = *qself {
157 // `impl Trait` in `qself` is always illegal
158 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
161 // Note that there should be a call to visit_path here,
162 // so if any logic is added to process `Path`s a call to it should be
163 // added both in visit_path and here. This code mirrors visit::walk_path.
164 for (i, segment) in path.segments.iter().enumerate() {
165 // Allow `impl Trait` iff we're on the final path segment
166 if i == path.segments.len() - 1 {
167 self.visit_path_segment(path.span, segment);
169 self.with_banned_impl_trait(|this| {
170 this.visit_path_segment(path.span, segment)
175 _ => visit::walk_ty(self, t),
179 fn err_handler(&self) -> &rustc_errors::Handler {
180 &self.session.diagnostic()
183 fn check_lifetime(&self, ident: Ident) {
184 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
185 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
186 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
190 fn check_label(&self, ident: Ident) {
191 if ident.without_first_quote().is_reserved() {
193 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
197 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
198 if let VisibilityKind::Inherited = vis.node {
203 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
204 if vis.node.is_pub() {
205 err.span_label(vis.span, "`pub` not permitted here because it's implied");
207 if let Some(note) = note {
213 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
214 for Param { pat, .. } in &decl.inputs {
216 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
217 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
218 report_err(pat.span, true)
220 _ => report_err(pat.span, false),
225 fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
226 if asyncness.is_async() {
227 struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`")
228 .note("`async` trait functions are not currently supported")
230 "consider using the `async-trait` crate: \
231 https://crates.io/crates/async-trait",
237 fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
238 if constness.node == Constness::Const {
243 "trait fns cannot be declared const"
245 .span_label(constness.span, "trait fns cannot be const")
250 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
251 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
252 for bound in bounds {
253 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
254 let mut err = self.err_handler().struct_span_err(
256 &format!("`?Trait` is not permitted in {}", where_),
259 let path_str = pprust::path_to_string(&poly.trait_ref.path);
260 err.note(&format!("traits are `?{}` by default", path_str));
267 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
268 /// or paths for ranges.
270 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
271 // That means making this work:
273 // ```rust,ignore (FIXME)
282 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
284 ExprKind::Lit(..) | ExprKind::Err => {}
285 ExprKind::Path(..) if allow_paths => {}
286 ExprKind::Unary(UnOp::Neg, ref inner)
287 if match inner.kind {
288 ExprKind::Lit(_) => true,
291 _ => self.err_handler().span_err(
293 "arbitrary expressions aren't allowed \
299 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
300 // Check only lifetime parameters are present and that the lifetime
301 // parameters that are present have no bounds.
302 let non_lt_param_spans: Vec<_> = params
304 .filter_map(|param| match param.kind {
305 GenericParamKind::Lifetime { .. } => {
306 if !param.bounds.is_empty() {
307 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
309 .span_err(spans, "lifetime bounds cannot be used in this context");
313 _ => Some(param.ident.span),
316 if !non_lt_param_spans.is_empty() {
317 self.err_handler().span_err(
319 "only lifetime parameters can be used in this context",
324 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
325 self.check_decl_cvaradic_pos(fn_decl);
326 self.check_decl_attrs(fn_decl);
327 self.check_decl_self_param(fn_decl, self_semantic);
330 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
331 match &*fn_decl.inputs {
332 [Param { ty, span, .. }] => {
333 if let TyKind::CVarArgs = ty.kind {
334 self.err_handler().span_err(
336 "C-variadic function must be declared with at least one named argument",
341 for Param { ty, span, .. } in ps {
342 if let TyKind::CVarArgs = ty.kind {
343 self.err_handler().span_err(
345 "`...` must be the last argument of a C-variadic function",
354 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
358 .flat_map(|i| i.attrs.as_ref())
360 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
361 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
364 if attr.is_doc_comment() {
368 "documentation comments cannot be applied to function parameters",
370 .span_label(attr.span, "doc comments are not allowed here")
373 self.err_handler().span_err(
375 "allow, cfg, cfg_attr, deny, \
376 forbid, and warn are the only allowed built-in attributes in function parameters",
382 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
383 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
388 "`self` parameter is only allowed in associated functions",
390 .span_label(param.span, "not semantically valid as function parameter")
391 .note("associated functions are those in `impl` or `trait` definitions")
397 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
398 if let Defaultness::Default = defaultness {
400 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
405 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
407 .struct_span_err(sp, msg)
409 self.session.source_map().end_point(sp),
410 &format!("provide a definition for the {}", ctx),
412 Applicability::HasPlaceholders,
417 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
419 let msg = format!("associated {} in `impl` without body", ctx);
420 self.error_item_without_body(sp, ctx, &msg, sugg);
424 fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
425 let span = match bounds {
428 [b0, .., bl] => b0.span().to(bl.span()),
431 .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
435 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
436 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
437 let body = match body {
442 .struct_span_err(ident.span, "incorrect function inside `extern` block")
443 .span_label(ident.span, "cannot have a body")
446 "remove the invalid body",
448 Applicability::MaybeIncorrect,
451 "you might have meant to write a function accessible through FFI, \
452 which can be done by writing `extern fn` outside of the `extern` block",
455 self.current_extern_span(),
456 "`extern` blocks define existing foreign functions and functions \
457 inside of them cannot have a body",
459 .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
463 fn current_extern_span(&self) -> Span {
464 self.session.source_map().def_span(self.extern_mod.unwrap().span)
467 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
468 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
469 if header.has_qualifiers() {
471 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
472 .span_label(self.current_extern_span(), "in this `extern` block")
474 span.until(ident.span.shrink_to_lo()),
475 "remove the qualifiers",
477 Applicability::MaybeIncorrect,
483 /// Reject C-varadic type unless the function is foreign,
484 /// or free and `unsafe extern "C"` semantically.
485 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
486 match (fk.ctxt(), fk.header()) {
487 (Some(FnCtxt::Foreign), _) => return,
488 (Some(FnCtxt::Free), Some(header)) => match header.ext {
489 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
490 if header.unsafety == Unsafety::Unsafe =>
499 for Param { ty, span, .. } in &fk.decl().inputs {
500 if let TyKind::CVarArgs = ty.kind {
504 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
511 /// We currently do not permit const generics in `const fn`,
512 /// as this is tantamount to allowing compile-time dependent typing.
514 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
515 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
516 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
517 if sig.header.constness.node == Constness::Const {
518 // Look for const generics and error if we find any.
519 for param in &generics.params {
520 if let GenericParamKind::Const { .. } = param.kind {
522 .struct_span_err(span, "const parameters are not permitted in `const fn`")
530 enum GenericPosition {
535 fn validate_generics_order<'a>(
537 handler: &rustc_errors::Handler,
538 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
539 pos: GenericPosition,
542 let mut max_param: Option<ParamKindOrd> = None;
543 let mut out_of_order = FxHashMap::default();
544 let mut param_idents = vec![];
545 let mut found_type = false;
546 let mut found_const = false;
548 for (kind, bounds, span, ident) in generics {
549 if let Some(ident) = ident {
550 param_idents.push((kind, bounds, param_idents.len(), ident));
552 let max_param = &mut max_param;
554 Some(max_param) if *max_param > kind => {
555 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
558 Some(_) | None => *max_param = Some(kind),
561 ParamKindOrd::Type => found_type = true,
562 ParamKindOrd::Const => found_const = true,
567 let mut ordered_params = "<".to_string();
568 if !out_of_order.is_empty() {
569 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
570 let mut first = true;
571 for (_, bounds, _, ident) in param_idents {
573 ordered_params += ", ";
575 ordered_params += &ident;
576 if let Some(bounds) = bounds {
577 if !bounds.is_empty() {
578 ordered_params += ": ";
579 ordered_params += &pprust::bounds_to_string(&bounds);
585 ordered_params += ">";
587 let pos_str = match pos {
588 GenericPosition::Param => "parameter",
589 GenericPosition::Arg => "argument",
592 for (param_ord, (max_param, spans)) in &out_of_order {
593 let mut err = handler.struct_span_err(
596 "{} {pos}s must be declared prior to {} {pos}s",
602 if let GenericPosition::Param = pos {
606 "reorder the {}s: lifetimes, then types{}",
608 if sess.features_untracked().const_generics { ", then consts" } else { "" },
610 ordered_params.clone(),
611 Applicability::MachineApplicable,
617 // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
618 // if we don't. Const parameters and type parameters can currently conflict if they
620 if !out_of_order.is_empty() && found_type && found_const {
625 impl<'a> Visitor<'a> for AstValidator<'a> {
626 fn visit_attribute(&mut self, attr: &Attribute) {
627 validate_attr::check_meta(&self.session.parse_sess, attr);
630 fn visit_expr(&mut self, expr: &'a Expr) {
632 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
637 "asm! is unsupported on this target"
644 visit::walk_expr(self, expr);
647 fn visit_ty(&mut self, ty: &'a Ty) {
649 TyKind::BareFn(ref bfty) => {
650 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
651 Self::check_decl_no_pat(&bfty.decl, |span, _| {
656 "patterns aren't allowed in function pointer types"
660 self.check_late_bound_lifetime_defs(&bfty.generic_params);
662 TyKind::TraitObject(ref bounds, ..) => {
663 let mut any_lifetime_bounds = false;
664 for bound in bounds {
665 if let GenericBound::Outlives(ref lifetime) = *bound {
666 if any_lifetime_bounds {
671 "only a single explicit lifetime bound is permitted"
676 any_lifetime_bounds = true;
679 self.no_questions_in_bounds(bounds, "trait object types", false);
681 TyKind::ImplTrait(_, ref bounds) => {
682 if self.is_impl_trait_banned {
687 "`impl Trait` is not allowed in path parameters"
692 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
697 "nested `impl Trait` is not allowed"
699 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
700 .span_label(ty.span, "nested `impl Trait` here")
706 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
708 self.err_handler().span_err(ty.span, "at least one trait must be specified");
720 fn visit_label(&mut self, label: &'a Label) {
721 self.check_label(label.ident);
722 visit::walk_label(self, label);
725 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
726 self.check_lifetime(lifetime.ident);
727 visit::walk_lifetime(self, lifetime);
730 fn visit_item(&mut self, item: &'a Item) {
731 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
732 self.has_proc_macro_decls = true;
746 self.with_in_trait_impl(true, |this| {
747 this.invalid_visibility(&item.vis, None);
748 if let TyKind::Err = self_ty.kind {
752 "`impl Trait for .. {}` is an obsolete syntax",
754 .help("use `auto trait Trait {}` instead")
757 if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
762 "negative impls cannot be unsafe"
767 visit::walk_item(this, item);
769 return; // Avoid visiting again.
781 self.invalid_visibility(
783 Some("place qualifiers on individual impl items instead"),
785 if unsafety == Unsafety::Unsafe {
790 "inherent impls cannot be unsafe"
794 if polarity == ImplPolarity::Negative {
795 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
797 if defaultness == Defaultness::Default {
799 .struct_span_err(item.span, "inherent impls cannot be default")
800 .note("only trait implementations may be annotated with default")
803 if constness == Constness::Const {
805 .struct_span_err(item.span, "inherent impls cannot be `const`")
806 .note("only trait implementations may be annotated with `const`")
810 ItemKind::Fn(ref sig, ref generics, ref body) => {
811 self.check_const_fn_const_generic(item.span, sig, generics);
814 let msg = "free function without a body";
815 self.error_item_without_body(item.span, "function", msg, " { <body> }");
818 ItemKind::ForeignMod(_) => {
819 let old_item = mem::replace(&mut self.extern_mod, Some(item));
820 self.invalid_visibility(
822 Some("place qualifiers on individual foreign items instead"),
824 visit::walk_item(self, item);
825 self.extern_mod = old_item;
826 return; // Avoid visiting again.
828 ItemKind::Enum(ref def, _) => {
829 for variant in &def.variants {
830 self.invalid_visibility(&variant.vis, None);
831 for field in variant.data.fields() {
832 self.invalid_visibility(&field.vis, None);
836 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
837 if is_auto == IsAuto::Yes {
838 // Auto traits cannot have generics, super traits nor contain items.
839 if !generics.params.is_empty() {
844 "auto traits cannot have generic parameters"
848 if !bounds.is_empty() {
853 "auto traits cannot have super traits"
857 if !trait_items.is_empty() {
862 "auto traits cannot have methods or associated items"
867 self.no_questions_in_bounds(bounds, "supertraits", true);
869 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
870 // context for the supertraits.
871 self.visit_vis(&item.vis);
872 self.visit_ident(item.ident);
873 self.visit_generics(generics);
874 self.with_bound_context(BoundContext::TraitBounds, |this| {
875 walk_list!(this, visit_param_bound, bounds);
877 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
878 walk_list!(self, visit_attribute, &item.attrs);
881 ItemKind::Mod(_) => {
882 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
883 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
885 ItemKind::Union(ref vdata, _) => {
886 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
888 .span_err(item.span, "tuple and unit unions are not permitted");
890 if vdata.fields().is_empty() {
891 self.err_handler().span_err(item.span, "unions cannot have zero fields");
897 visit::walk_item(self, item)
900 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
902 ForeignItemKind::Fn(sig, _, body) => {
903 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
904 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
906 ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
909 visit::walk_foreign_item(self, fi)
912 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
913 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
914 match *generic_args {
915 GenericArgs::AngleBracketed(ref data) => {
916 walk_list!(self, visit_generic_arg, &data.args);
917 validate_generics_order(
920 data.args.iter().map(|arg| {
923 GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
924 GenericArg::Type(..) => ParamKindOrd::Type,
925 GenericArg::Const(..) => ParamKindOrd::Const,
932 GenericPosition::Arg,
936 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
937 // are allowed to contain nested `impl Trait`.
938 self.with_impl_trait(None, |this| {
941 visit_assoc_ty_constraint_from_generic_args,
946 GenericArgs::Parenthesized(ref data) => {
947 walk_list!(self, visit_ty, &data.inputs);
948 if let FunctionRetTy::Ty(ty) = &data.output {
949 // `-> Foo` syntax is essentially an associated type binding,
950 // so it is also allowed to contain nested `impl Trait`.
951 self.with_impl_trait(None, |this| this.visit_ty(ty));
957 fn visit_generics(&mut self, generics: &'a Generics) {
958 let mut prev_ty_default = None;
959 for param in &generics.params {
960 if let GenericParamKind::Type { ref default, .. } = param.kind {
961 if default.is_some() {
962 prev_ty_default = Some(param.ident.span);
963 } else if let Some(span) = prev_ty_default {
965 .span_err(span, "type parameters with a default must be trailing");
971 validate_generics_order(
974 generics.params.iter().map(|param| {
975 let ident = Some(param.ident.to_string());
976 let (kind, ident) = match ¶m.kind {
977 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
978 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
979 GenericParamKind::Const { ref ty } => {
980 let ty = pprust::ty_to_string(ty);
981 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
984 (kind, Some(&*param.bounds), param.ident.span, ident)
986 GenericPosition::Param,
990 for predicate in &generics.where_clause.predicates {
991 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
995 "equality constraints are not yet supported in `where` clauses",
997 .span_label(predicate.span, "not supported")
999 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1000 for more information",
1006 visit::walk_generics(self, generics)
1009 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1010 if let GenericParamKind::Lifetime { .. } = param.kind {
1011 self.check_lifetime(param.ident);
1013 visit::walk_generic_param(self, param);
1016 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1018 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1019 if let Some(ctx) = self.bound_context {
1020 let msg = format!("`?const` is not permitted in {}", ctx.description());
1021 self.err_handler().span_err(bound.span(), &msg);
1025 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1027 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1033 visit::walk_param_bound(self, bound)
1036 fn visit_pat(&mut self, pat: &'a Pat) {
1038 PatKind::Lit(ref expr) => {
1039 self.check_expr_within_pat(expr, false);
1041 PatKind::Range(ref start, ref end, _) => {
1042 if let Some(expr) = start {
1043 self.check_expr_within_pat(expr, true);
1045 if let Some(expr) = end {
1046 self.check_expr_within_pat(expr, true);
1052 visit::walk_pat(self, pat)
1055 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1056 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1057 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1058 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1060 visit::walk_where_predicate(self, p);
1063 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1064 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1065 visit::walk_poly_trait_ref(self, t, m);
1068 fn visit_variant_data(&mut self, s: &'a VariantData) {
1069 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1074 enum_definition: &'a EnumDef,
1075 generics: &'a Generics,
1079 self.with_banned_assoc_ty_bound(|this| {
1080 visit::walk_enum_def(this, enum_definition, generics, item_id)
1084 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1085 // Only associated `fn`s can have `self` parameters.
1086 let self_semantic = match fk.ctxt() {
1087 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1088 _ => SelfSemantic::No,
1090 self.check_fn_decl(fk.decl(), self_semantic);
1092 self.check_c_varadic_type(fk);
1094 // Functions without bodies cannot have patterns.
1095 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1096 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1097 let (code, msg, label) = match ctxt {
1098 FnCtxt::Foreign => (
1100 "patterns aren't allowed in foreign function declarations",
1101 "pattern not allowed in foreign function",
1105 "patterns aren't allowed in functions without bodies",
1106 "pattern not allowed in function without body",
1109 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1110 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1113 .struct_span_err(span, msg)
1114 .span_label(span, label)
1121 visit::walk_fn(self, fk, span);
1124 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1125 if ctxt == AssocCtxt::Trait {
1126 self.check_defaultness(item.span, item.defaultness);
1129 if ctxt == AssocCtxt::Impl {
1131 AssocItemKind::Const(_, body) => {
1132 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1134 AssocItemKind::Fn(_, body) => {
1135 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1137 AssocItemKind::TyAlias(bounds, body) => {
1138 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1139 self.check_impl_assoc_type_no_bounds(bounds);
1145 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1146 self.invalid_visibility(&item.vis, None);
1147 if let AssocItemKind::Fn(sig, _) = &item.kind {
1148 self.check_trait_fn_not_const(sig.header.constness);
1149 self.check_trait_fn_not_async(item.span, sig.header.asyncness.node);
1153 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1157 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1158 let mut validator = AstValidator {
1161 in_trait_impl: false,
1162 has_proc_macro_decls: false,
1163 outer_impl_trait: None,
1164 bound_context: None,
1165 is_impl_trait_banned: false,
1166 is_assoc_ty_bound_banned: false,
1169 visit::walk_crate(&mut validator, krate);
1171 validator.has_proc_macro_decls