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, span: Span, asyncness: IsAsync) {
225 if asyncness.is_async() {
226 struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`")
227 .note("`async` trait functions are not currently supported")
229 "consider using the `async-trait` crate: \
230 https://crates.io/crates/async-trait",
236 fn check_trait_fn_not_const(&self, constness: Const) {
237 if let Const::Yes(span) = constness {
238 struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const")
239 .span_label(span, "trait fns cannot be const")
244 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
245 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
246 for bound in bounds {
247 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
248 let mut err = self.err_handler().struct_span_err(
250 &format!("`?Trait` is not permitted in {}", where_),
253 let path_str = pprust::path_to_string(&poly.trait_ref.path);
254 err.note(&format!("traits are `?{}` by default", path_str));
261 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
262 /// or paths for ranges.
264 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
265 // That means making this work:
267 // ```rust,ignore (FIXME)
276 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
278 ExprKind::Lit(..) | ExprKind::Err => {}
279 ExprKind::Path(..) if allow_paths => {}
280 ExprKind::Unary(UnOp::Neg, ref inner)
281 if match inner.kind {
282 ExprKind::Lit(_) => true,
285 _ => self.err_handler().span_err(
287 "arbitrary expressions aren't allowed \
293 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
294 // Check only lifetime parameters are present and that the lifetime
295 // parameters that are present have no bounds.
296 let non_lt_param_spans: Vec<_> = params
298 .filter_map(|param| match param.kind {
299 GenericParamKind::Lifetime { .. } => {
300 if !param.bounds.is_empty() {
301 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
303 .span_err(spans, "lifetime bounds cannot be used in this context");
307 _ => Some(param.ident.span),
310 if !non_lt_param_spans.is_empty() {
311 self.err_handler().span_err(
313 "only lifetime parameters can be used in this context",
318 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
319 self.check_decl_cvaradic_pos(fn_decl);
320 self.check_decl_attrs(fn_decl);
321 self.check_decl_self_param(fn_decl, self_semantic);
324 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
325 match &*fn_decl.inputs {
326 [Param { ty, span, .. }] => {
327 if let TyKind::CVarArgs = ty.kind {
328 self.err_handler().span_err(
330 "C-variadic function must be declared with at least one named argument",
335 for Param { ty, span, .. } in ps {
336 if let TyKind::CVarArgs = ty.kind {
337 self.err_handler().span_err(
339 "`...` must be the last argument of a C-variadic function",
348 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
352 .flat_map(|i| i.attrs.as_ref())
354 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
355 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
358 if attr.is_doc_comment() {
362 "documentation comments cannot be applied to function parameters",
364 .span_label(attr.span, "doc comments are not allowed here")
367 self.err_handler().span_err(
369 "allow, cfg, cfg_attr, deny, \
370 forbid, and warn are the only allowed built-in attributes in function parameters",
376 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
377 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
382 "`self` parameter is only allowed in associated functions",
384 .span_label(param.span, "not semantically valid as function parameter")
385 .note("associated functions are those in `impl` or `trait` definitions")
391 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
392 if let Defaultness::Default = defaultness {
394 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
399 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
401 .struct_span_err(sp, msg)
403 self.session.source_map().end_point(sp),
404 &format!("provide a definition for the {}", ctx),
406 Applicability::HasPlaceholders,
411 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
413 let msg = format!("associated {} in `impl` without body", ctx);
414 self.error_item_without_body(sp, ctx, &msg, sugg);
418 fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
419 let span = match bounds {
422 [b0, .., bl] => b0.span().to(bl.span()),
425 .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
429 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
430 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
431 let body = match body {
436 .struct_span_err(ident.span, "incorrect function inside `extern` block")
437 .span_label(ident.span, "cannot have a body")
440 "remove the invalid body",
442 Applicability::MaybeIncorrect,
445 "you might have meant to write a function accessible through FFI, \
446 which can be done by writing `extern fn` outside of the `extern` block",
449 self.current_extern_span(),
450 "`extern` blocks define existing foreign functions and functions \
451 inside of them cannot have a body",
453 .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
457 fn current_extern_span(&self) -> Span {
458 self.session.source_map().def_span(self.extern_mod.unwrap().span)
461 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
462 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
463 if header.has_qualifiers() {
465 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
466 .span_label(self.current_extern_span(), "in this `extern` block")
468 span.until(ident.span.shrink_to_lo()),
469 "remove the qualifiers",
471 Applicability::MaybeIncorrect,
477 /// Reject C-varadic type unless the function is foreign,
478 /// or free and `unsafe extern "C"` semantically.
479 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
480 match (fk.ctxt(), fk.header()) {
481 (Some(FnCtxt::Foreign), _) => return,
482 (Some(FnCtxt::Free), Some(header)) => match header.ext {
483 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
484 if matches!(header.unsafety, Unsafe::Yes(_)) =>
493 for Param { ty, span, .. } in &fk.decl().inputs {
494 if let TyKind::CVarArgs = ty.kind {
498 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
505 /// We currently do not permit const generics in `const fn`,
506 /// as this is tantamount to allowing compile-time dependent typing.
508 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
509 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
510 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
511 if let Const::Yes(const_span) = sig.header.constness {
512 // Look for const generics and error if we find any.
513 for param in &generics.params {
514 if let GenericParamKind::Const { .. } = param.kind {
516 .struct_span_err(span, "const parameters are not permitted in `const fn`")
517 .span_label(const_span, "`const fn` because of this")
525 enum GenericPosition {
530 fn validate_generics_order<'a>(
532 handler: &rustc_errors::Handler,
533 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
534 pos: GenericPosition,
537 let mut max_param: Option<ParamKindOrd> = None;
538 let mut out_of_order = FxHashMap::default();
539 let mut param_idents = vec![];
540 let mut found_type = false;
541 let mut found_const = false;
543 for (kind, bounds, span, ident) in generics {
544 if let Some(ident) = ident {
545 param_idents.push((kind, bounds, param_idents.len(), ident));
547 let max_param = &mut max_param;
549 Some(max_param) if *max_param > kind => {
550 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
553 Some(_) | None => *max_param = Some(kind),
556 ParamKindOrd::Type => found_type = true,
557 ParamKindOrd::Const => found_const = true,
562 let mut ordered_params = "<".to_string();
563 if !out_of_order.is_empty() {
564 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
565 let mut first = true;
566 for (_, bounds, _, ident) in param_idents {
568 ordered_params += ", ";
570 ordered_params += &ident;
571 if let Some(bounds) = bounds {
572 if !bounds.is_empty() {
573 ordered_params += ": ";
574 ordered_params += &pprust::bounds_to_string(&bounds);
580 ordered_params += ">";
582 let pos_str = match pos {
583 GenericPosition::Param => "parameter",
584 GenericPosition::Arg => "argument",
587 for (param_ord, (max_param, spans)) in &out_of_order {
588 let mut err = handler.struct_span_err(
591 "{} {pos}s must be declared prior to {} {pos}s",
597 if let GenericPosition::Param = pos {
601 "reorder the {}s: lifetimes, then types{}",
603 if sess.features_untracked().const_generics { ", then consts" } else { "" },
605 ordered_params.clone(),
606 Applicability::MachineApplicable,
612 // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
613 // if we don't. Const parameters and type parameters can currently conflict if they
615 if !out_of_order.is_empty() && found_type && found_const {
620 impl<'a> Visitor<'a> for AstValidator<'a> {
621 fn visit_attribute(&mut self, attr: &Attribute) {
622 validate_attr::check_meta(&self.session.parse_sess, attr);
625 fn visit_expr(&mut self, expr: &'a Expr) {
627 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
632 "asm! is unsupported on this target"
639 visit::walk_expr(self, expr);
642 fn visit_ty(&mut self, ty: &'a Ty) {
644 TyKind::BareFn(ref bfty) => {
645 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
646 Self::check_decl_no_pat(&bfty.decl, |span, _| {
651 "patterns aren't allowed in function pointer types"
655 self.check_late_bound_lifetime_defs(&bfty.generic_params);
657 TyKind::TraitObject(ref bounds, ..) => {
658 let mut any_lifetime_bounds = false;
659 for bound in bounds {
660 if let GenericBound::Outlives(ref lifetime) = *bound {
661 if any_lifetime_bounds {
666 "only a single explicit lifetime bound is permitted"
671 any_lifetime_bounds = true;
674 self.no_questions_in_bounds(bounds, "trait object types", false);
676 TyKind::ImplTrait(_, ref bounds) => {
677 if self.is_impl_trait_banned {
682 "`impl Trait` is not allowed in path parameters"
687 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
692 "nested `impl Trait` is not allowed"
694 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
695 .span_label(ty.span, "nested `impl Trait` here")
701 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
703 self.err_handler().span_err(ty.span, "at least one trait must be specified");
715 fn visit_label(&mut self, label: &'a Label) {
716 self.check_label(label.ident);
717 visit::walk_label(self, label);
720 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
721 self.check_lifetime(lifetime.ident);
722 visit::walk_lifetime(self, lifetime);
725 fn visit_item(&mut self, item: &'a Item) {
726 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
727 self.has_proc_macro_decls = true;
741 self.with_in_trait_impl(true, |this| {
742 this.invalid_visibility(&item.vis, None);
743 if let TyKind::Err = self_ty.kind {
747 "`impl Trait for .. {}` is an obsolete syntax",
749 .help("use `auto trait Trait {}` instead")
752 if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
757 "negative impls cannot be unsafe"
759 .span_label(span, "unsafe because of this")
763 visit::walk_item(this, item);
765 return; // Avoid visiting again.
777 self.invalid_visibility(
779 Some("place qualifiers on individual impl items instead"),
781 if let Unsafe::Yes(span) = unsafety {
786 "inherent impls cannot be unsafe"
788 .span_label(span, "unsafe because of this")
791 if polarity == ImplPolarity::Negative {
792 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
794 if defaultness == Defaultness::Default {
796 .struct_span_err(item.span, "inherent impls cannot be default")
797 .note("only trait implementations may be annotated with default")
800 if let Const::Yes(span) = constness {
802 .struct_span_err(item.span, "inherent impls cannot be `const`")
803 .span_label(span, "`const` because of this")
804 .note("only trait implementations may be annotated with `const`")
808 ItemKind::Fn(ref sig, ref generics, ref body) => {
809 self.check_const_fn_const_generic(item.span, sig, generics);
812 let msg = "free function without a body";
813 self.error_item_without_body(item.span, "function", msg, " { <body> }");
816 ItemKind::ForeignMod(_) => {
817 let old_item = mem::replace(&mut self.extern_mod, Some(item));
818 self.invalid_visibility(
820 Some("place qualifiers on individual foreign items instead"),
822 visit::walk_item(self, item);
823 self.extern_mod = old_item;
824 return; // Avoid visiting again.
826 ItemKind::Enum(ref def, _) => {
827 for variant in &def.variants {
828 self.invalid_visibility(&variant.vis, None);
829 for field in variant.data.fields() {
830 self.invalid_visibility(&field.vis, None);
834 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
835 if is_auto == IsAuto::Yes {
836 // Auto traits cannot have generics, super traits nor contain items.
837 if !generics.params.is_empty() {
842 "auto traits cannot have generic parameters"
846 if !bounds.is_empty() {
851 "auto traits cannot have super traits"
855 if !trait_items.is_empty() {
860 "auto traits cannot have methods or associated items"
865 self.no_questions_in_bounds(bounds, "supertraits", true);
867 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
868 // context for the supertraits.
869 self.visit_vis(&item.vis);
870 self.visit_ident(item.ident);
871 self.visit_generics(generics);
872 self.with_bound_context(BoundContext::TraitBounds, |this| {
873 walk_list!(this, visit_param_bound, bounds);
875 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
876 walk_list!(self, visit_attribute, &item.attrs);
879 ItemKind::Mod(_) => {
880 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
881 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
883 ItemKind::Union(ref vdata, _) => {
884 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
886 .span_err(item.span, "tuple and unit unions are not permitted");
888 if vdata.fields().is_empty() {
889 self.err_handler().span_err(item.span, "unions cannot have zero fields");
895 visit::walk_item(self, item)
898 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
900 ForeignItemKind::Fn(sig, _, body) => {
901 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
902 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
904 ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
907 visit::walk_foreign_item(self, fi)
910 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
911 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
912 match *generic_args {
913 GenericArgs::AngleBracketed(ref data) => {
914 walk_list!(self, visit_generic_arg, &data.args);
915 validate_generics_order(
918 data.args.iter().map(|arg| {
921 GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
922 GenericArg::Type(..) => ParamKindOrd::Type,
923 GenericArg::Const(..) => ParamKindOrd::Const,
930 GenericPosition::Arg,
934 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
935 // are allowed to contain nested `impl Trait`.
936 self.with_impl_trait(None, |this| {
939 visit_assoc_ty_constraint_from_generic_args,
944 GenericArgs::Parenthesized(ref data) => {
945 walk_list!(self, visit_ty, &data.inputs);
946 if let FunctionRetTy::Ty(ty) = &data.output {
947 // `-> Foo` syntax is essentially an associated type binding,
948 // so it is also allowed to contain nested `impl Trait`.
949 self.with_impl_trait(None, |this| this.visit_ty(ty));
955 fn visit_generics(&mut self, generics: &'a Generics) {
956 let mut prev_ty_default = None;
957 for param in &generics.params {
958 if let GenericParamKind::Type { ref default, .. } = param.kind {
959 if default.is_some() {
960 prev_ty_default = Some(param.ident.span);
961 } else if let Some(span) = prev_ty_default {
963 .span_err(span, "type parameters with a default must be trailing");
969 validate_generics_order(
972 generics.params.iter().map(|param| {
973 let ident = Some(param.ident.to_string());
974 let (kind, ident) = match ¶m.kind {
975 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
976 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
977 GenericParamKind::Const { ref ty } => {
978 let ty = pprust::ty_to_string(ty);
979 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
982 (kind, Some(&*param.bounds), param.ident.span, ident)
984 GenericPosition::Param,
988 for predicate in &generics.where_clause.predicates {
989 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
993 "equality constraints are not yet supported in `where` clauses",
995 .span_label(predicate.span, "not supported")
997 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
998 for more information",
1004 visit::walk_generics(self, generics)
1007 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1008 if let GenericParamKind::Lifetime { .. } = param.kind {
1009 self.check_lifetime(param.ident);
1011 visit::walk_generic_param(self, param);
1014 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1016 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1017 if let Some(ctx) = self.bound_context {
1018 let msg = format!("`?const` is not permitted in {}", ctx.description());
1019 self.err_handler().span_err(bound.span(), &msg);
1023 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1025 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1031 visit::walk_param_bound(self, bound)
1034 fn visit_pat(&mut self, pat: &'a Pat) {
1036 PatKind::Lit(ref expr) => {
1037 self.check_expr_within_pat(expr, false);
1039 PatKind::Range(ref start, ref end, _) => {
1040 if let Some(expr) = start {
1041 self.check_expr_within_pat(expr, true);
1043 if let Some(expr) = end {
1044 self.check_expr_within_pat(expr, true);
1050 visit::walk_pat(self, pat)
1053 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1054 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1055 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1056 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1058 visit::walk_where_predicate(self, p);
1061 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1062 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1063 visit::walk_poly_trait_ref(self, t, m);
1066 fn visit_variant_data(&mut self, s: &'a VariantData) {
1067 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1072 enum_definition: &'a EnumDef,
1073 generics: &'a Generics,
1077 self.with_banned_assoc_ty_bound(|this| {
1078 visit::walk_enum_def(this, enum_definition, generics, item_id)
1082 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1083 // Only associated `fn`s can have `self` parameters.
1084 let self_semantic = match fk.ctxt() {
1085 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1086 _ => SelfSemantic::No,
1088 self.check_fn_decl(fk.decl(), self_semantic);
1090 self.check_c_varadic_type(fk);
1092 // Functions without bodies cannot have patterns.
1093 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1094 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1095 let (code, msg, label) = match ctxt {
1096 FnCtxt::Foreign => (
1098 "patterns aren't allowed in foreign function declarations",
1099 "pattern not allowed in foreign function",
1103 "patterns aren't allowed in functions without bodies",
1104 "pattern not allowed in function without body",
1107 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1108 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1111 .struct_span_err(span, msg)
1112 .span_label(span, label)
1119 visit::walk_fn(self, fk, span);
1122 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1123 if ctxt == AssocCtxt::Trait {
1124 self.check_defaultness(item.span, item.defaultness);
1127 if ctxt == AssocCtxt::Impl {
1129 AssocItemKind::Const(_, body) => {
1130 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1132 AssocItemKind::Fn(_, body) => {
1133 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1135 AssocItemKind::TyAlias(bounds, body) => {
1136 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1137 self.check_impl_assoc_type_no_bounds(bounds);
1143 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1144 self.invalid_visibility(&item.vis, None);
1145 if let AssocItemKind::Fn(sig, _) = &item.kind {
1146 self.check_trait_fn_not_const(sig.header.constness);
1147 self.check_trait_fn_not_async(item.span, sig.header.asyncness.node);
1151 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1155 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1156 let mut validator = AstValidator {
1159 in_trait_impl: false,
1160 has_proc_macro_decls: false,
1161 outer_impl_trait: None,
1162 bound_context: None,
1163 is_impl_trait_banned: false,
1164 is_assoc_ty_bound_banned: false,
1167 visit::walk_crate(&mut validator, krate);
1169 validator.has_proc_macro_decls