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};
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 const MORE_EXTERN: &str =
26 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
28 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
34 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
35 #[derive(Clone, Copy)]
43 fn description(&self) -> &'static str {
45 Self::ImplTrait => "`impl Trait`",
46 Self::TraitBounds => "supertraits",
47 Self::TraitObject => "trait objects",
52 struct AstValidator<'a> {
55 /// The span of the `extern` in an `extern { ... }` block, if any.
56 extern_mod: Option<&'a Item>,
58 /// Are we inside a trait impl?
61 has_proc_macro_decls: bool,
63 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
64 /// Nested `impl Trait` _is_ allowed in associated type position,
65 /// e.g., `impl Iterator<Item = impl Debug>`.
66 outer_impl_trait: Option<Span>,
68 /// Keeps track of the `BoundContext` as we recurse.
70 /// This is used to forbid `?const Trait` bounds in, e.g.,
71 /// `impl Iterator<Item = Box<dyn ?const Trait>`.
72 bound_context: Option<BoundContext>,
74 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
75 /// or `Foo::Bar<impl Trait>`
76 is_impl_trait_banned: bool,
78 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
79 /// certain positions.
80 is_assoc_ty_bound_banned: bool,
82 lint_buffer: &'a mut LintBuffer,
85 impl<'a> AstValidator<'a> {
86 fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
87 let old = mem::replace(&mut self.in_trait_impl, is_in);
89 self.in_trait_impl = old;
92 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
93 let old = mem::replace(&mut self.is_impl_trait_banned, true);
95 self.is_impl_trait_banned = old;
98 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
99 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
101 self.is_assoc_ty_bound_banned = old;
104 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
105 let old = mem::replace(&mut self.outer_impl_trait, outer);
107 self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
111 self.outer_impl_trait = old;
114 fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
115 let old = self.bound_context.replace(ctx);
117 self.bound_context = old;
120 fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
121 match constraint.kind {
122 AssocTyConstraintKind::Equality { .. } => {}
123 AssocTyConstraintKind::Bound { .. } => {
124 if self.is_assoc_ty_bound_banned {
125 self.err_handler().span_err(
127 "associated type bounds are not allowed within structs, enums, or unions",
132 self.visit_assoc_ty_constraint(constraint);
135 // Mirrors `visit::walk_ty`, but tracks relevant state.
136 fn walk_ty(&mut self, t: &'a Ty) {
138 TyKind::ImplTrait(..) => {
139 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
141 TyKind::TraitObject(..) => {
142 self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
144 TyKind::Path(ref qself, ref path) => {
146 // - `Option<impl Trait>`
147 // - `option::Option<impl Trait>`
148 // - `option::Option<T>::Foo<impl Trait>
151 // - `<impl Trait>::Foo`
152 // - `option::Option<impl Trait>::Foo`.
154 // To implement this, we disallow `impl Trait` from `qself`
155 // (for cases like `<impl Trait>::Foo>`)
156 // but we allow `impl Trait` in `GenericArgs`
157 // iff there are no more PathSegments.
158 if let Some(ref qself) = *qself {
159 // `impl Trait` in `qself` is always illegal
160 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
163 // Note that there should be a call to visit_path here,
164 // so if any logic is added to process `Path`s a call to it should be
165 // added both in visit_path and here. This code mirrors visit::walk_path.
166 for (i, segment) in path.segments.iter().enumerate() {
167 // Allow `impl Trait` iff we're on the final path segment
168 if i == path.segments.len() - 1 {
169 self.visit_path_segment(path.span, segment);
171 self.with_banned_impl_trait(|this| {
172 this.visit_path_segment(path.span, segment)
177 _ => visit::walk_ty(self, t),
181 fn err_handler(&self) -> &rustc_errors::Handler {
182 &self.session.diagnostic()
185 fn check_lifetime(&self, ident: Ident) {
186 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
187 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
188 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
192 fn check_label(&self, ident: Ident) {
193 if ident.without_first_quote().is_reserved() {
195 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
199 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
200 if let VisibilityKind::Inherited = vis.node {
205 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
206 if vis.node.is_pub() {
207 err.span_label(vis.span, "`pub` not permitted here because it's implied");
209 if let Some(note) = note {
215 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
216 for Param { pat, .. } in &decl.inputs {
218 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
219 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
220 report_err(pat.span, true)
222 _ => report_err(pat.span, false),
227 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
228 if let Async::Yes { span, .. } = asyncness {
233 "functions in traits cannot be declared `async`"
235 .span_label(span, "`async` because of this")
236 .note("`async` trait functions are not currently supported")
237 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
242 fn check_trait_fn_not_const(&self, constness: Const) {
243 if let Const::Yes(span) = constness {
248 "functions in traits cannot be declared const"
250 .span_label(span, "functions in traits cannot be const")
255 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
256 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
257 for bound in bounds {
258 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
259 let mut err = self.err_handler().struct_span_err(
261 &format!("`?Trait` is not permitted in {}", where_),
264 let path_str = pprust::path_to_string(&poly.trait_ref.path);
265 err.note(&format!("traits are `?{}` by default", path_str));
272 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
273 /// or paths for ranges.
275 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
276 // That means making this work:
278 // ```rust,ignore (FIXME)
287 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
289 ExprKind::Lit(..) | ExprKind::Err => {}
290 ExprKind::Path(..) if allow_paths => {}
291 ExprKind::Unary(UnOp::Neg, ref inner)
292 if match inner.kind {
293 ExprKind::Lit(_) => true,
296 _ => self.err_handler().span_err(
298 "arbitrary expressions aren't allowed \
304 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
305 // Check only lifetime parameters are present and that the lifetime
306 // parameters that are present have no bounds.
307 let non_lt_param_spans: Vec<_> = params
309 .filter_map(|param| match param.kind {
310 GenericParamKind::Lifetime { .. } => {
311 if !param.bounds.is_empty() {
312 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
314 .span_err(spans, "lifetime bounds cannot be used in this context");
318 _ => Some(param.ident.span),
321 if !non_lt_param_spans.is_empty() {
322 self.err_handler().span_err(
324 "only lifetime parameters can be used in this context",
329 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
330 self.check_decl_cvaradic_pos(fn_decl);
331 self.check_decl_attrs(fn_decl);
332 self.check_decl_self_param(fn_decl, self_semantic);
335 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
336 match &*fn_decl.inputs {
337 [Param { ty, span, .. }] => {
338 if let TyKind::CVarArgs = ty.kind {
339 self.err_handler().span_err(
341 "C-variadic function must be declared with at least one named argument",
346 for Param { ty, span, .. } in ps {
347 if let TyKind::CVarArgs = ty.kind {
348 self.err_handler().span_err(
350 "`...` must be the last argument of a C-variadic function",
359 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
363 .flat_map(|i| i.attrs.as_ref())
365 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
366 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
369 if attr.is_doc_comment() {
373 "documentation comments cannot be applied to function parameters",
375 .span_label(attr.span, "doc comments are not allowed here")
378 self.err_handler().span_err(
380 "allow, cfg, cfg_attr, deny, \
381 forbid, and warn are the only allowed built-in attributes in function parameters",
387 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
388 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
393 "`self` parameter is only allowed in associated functions",
395 .span_label(param.span, "not semantically valid as function parameter")
396 .note("associated functions are those in `impl` or `trait` definitions")
402 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
403 if let Defaultness::Default = defaultness {
405 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
410 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
412 .struct_span_err(sp, msg)
414 self.session.source_map().end_point(sp),
415 &format!("provide a definition for the {}", ctx),
417 Applicability::HasPlaceholders,
422 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
424 let msg = format!("associated {} in `impl` without body", ctx);
425 self.error_item_without_body(sp, ctx, &msg, sugg);
429 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
430 let span = match bounds {
433 [b0, .., bl] => b0.span().to(bl.span()),
436 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
440 fn check_foreign_ty_genericless(&self, generics: &Generics) {
441 let cannot_have = |span, descr, remove_descr| {
445 &format!("`type`s inside `extern` blocks cannot have {}", descr),
449 &format!("remove the {}", remove_descr),
451 Applicability::MaybeIncorrect,
453 .span_label(self.current_extern_span(), "`extern` block begins here")
458 if !generics.params.is_empty() {
459 cannot_have(generics.span, "generic parameters", "generic parameters");
462 if !generics.where_clause.predicates.is_empty() {
463 cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
467 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
468 let body = match body {
473 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
474 .span_label(ident.span, "cannot have a body")
475 .span_label(body, "the invalid body")
477 self.current_extern_span(),
479 "`extern` blocks define existing foreign {0}s and {0}s \
480 inside of them cannot have a body",
488 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
489 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
490 let body = match body {
495 .struct_span_err(ident.span, "incorrect function inside `extern` block")
496 .span_label(ident.span, "cannot have a body")
499 "remove the invalid body",
501 Applicability::MaybeIncorrect,
504 "you might have meant to write a function accessible through FFI, \
505 which can be done by writing `extern fn` outside of the `extern` block",
508 self.current_extern_span(),
509 "`extern` blocks define existing foreign functions and functions \
510 inside of them cannot have a body",
516 fn current_extern_span(&self) -> Span {
517 self.session.source_map().def_span(self.extern_mod.unwrap().span)
520 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
521 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
522 if header.has_qualifiers() {
524 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
525 .span_label(self.current_extern_span(), "in this `extern` block")
527 span.until(ident.span.shrink_to_lo()),
528 "remove the qualifiers",
530 Applicability::MaybeIncorrect,
536 /// Reject C-varadic type unless the function is foreign,
537 /// or free and `unsafe extern "C"` semantically.
538 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
539 match (fk.ctxt(), fk.header()) {
540 (Some(FnCtxt::Foreign), _) => return,
541 (Some(FnCtxt::Free), Some(header)) => match header.ext {
542 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
543 if matches!(header.unsafety, Unsafe::Yes(_)) =>
552 for Param { ty, span, .. } in &fk.decl().inputs {
553 if let TyKind::CVarArgs = ty.kind {
557 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
564 /// We currently do not permit const generics in `const fn`,
565 /// as this is tantamount to allowing compile-time dependent typing.
567 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
568 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
569 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
570 if let Const::Yes(const_span) = sig.header.constness {
571 // Look for const generics and error if we find any.
572 for param in &generics.params {
573 if let GenericParamKind::Const { .. } = param.kind {
577 "const parameters are not permitted in const functions",
579 .span_label(const_span, "`const` because of this")
586 fn check_item_named(&self, ident: Ident, kind: &str) {
587 if ident.name != kw::Underscore {
591 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
592 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
597 fn validate_generic_param_order<'a>(
599 handler: &rustc_errors::Handler,
600 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
603 let mut max_param: Option<ParamKindOrd> = None;
604 let mut out_of_order = FxHashMap::default();
605 let mut param_idents = vec![];
607 for (kind, bounds, span, ident) in generics {
608 if let Some(ident) = ident {
609 param_idents.push((kind, bounds, param_idents.len(), ident));
611 let max_param = &mut max_param;
613 Some(max_param) if *max_param > kind => {
614 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
617 Some(_) | None => *max_param = Some(kind),
621 let mut ordered_params = "<".to_string();
622 if !out_of_order.is_empty() {
623 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
624 let mut first = true;
625 for (_, bounds, _, ident) in param_idents {
627 ordered_params += ", ";
629 ordered_params += &ident;
630 if let Some(bounds) = bounds {
631 if !bounds.is_empty() {
632 ordered_params += ": ";
633 ordered_params += &pprust::bounds_to_string(&bounds);
639 ordered_params += ">";
641 for (param_ord, (max_param, spans)) in &out_of_order {
643 handler.struct_span_err(
646 "{} parameters must be declared prior to {} parameters",
647 param_ord, max_param,
653 "reorder the parameters: lifetimes, then types{}",
654 if sess.features_untracked().const_generics { ", then consts" } else { "" },
656 ordered_params.clone(),
657 Applicability::MachineApplicable,
663 impl<'a> Visitor<'a> for AstValidator<'a> {
664 fn visit_attribute(&mut self, attr: &Attribute) {
665 validate_attr::check_meta(&self.session.parse_sess, attr);
668 fn visit_expr(&mut self, expr: &'a Expr) {
670 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
675 "asm! is unsupported on this target"
682 visit::walk_expr(self, expr);
685 fn visit_ty(&mut self, ty: &'a Ty) {
687 TyKind::BareFn(ref bfty) => {
688 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
689 Self::check_decl_no_pat(&bfty.decl, |span, _| {
694 "patterns aren't allowed in function pointer types"
698 self.check_late_bound_lifetime_defs(&bfty.generic_params);
700 TyKind::TraitObject(ref bounds, ..) => {
701 let mut any_lifetime_bounds = false;
702 for bound in bounds {
703 if let GenericBound::Outlives(ref lifetime) = *bound {
704 if any_lifetime_bounds {
709 "only a single explicit lifetime bound is permitted"
714 any_lifetime_bounds = true;
717 self.no_questions_in_bounds(bounds, "trait object types", false);
719 TyKind::ImplTrait(_, ref bounds) => {
720 if self.is_impl_trait_banned {
725 "`impl Trait` is not allowed in path parameters"
730 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
735 "nested `impl Trait` is not allowed"
737 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
738 .span_label(ty.span, "nested `impl Trait` here")
744 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
746 self.err_handler().span_err(ty.span, "at least one trait must be specified");
758 fn visit_label(&mut self, label: &'a Label) {
759 self.check_label(label.ident);
760 visit::walk_label(self, label);
763 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
764 self.check_lifetime(lifetime.ident);
765 visit::walk_lifetime(self, lifetime);
768 fn visit_item(&mut self, item: &'a Item) {
769 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
770 self.has_proc_macro_decls = true;
784 self.with_in_trait_impl(true, |this| {
785 this.invalid_visibility(&item.vis, None);
786 if let TyKind::Err = self_ty.kind {
790 "`impl Trait for .. {}` is an obsolete syntax",
792 .help("use `auto trait Trait {}` instead")
795 if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
800 "negative impls cannot be unsafe"
802 .span_label(span, "unsafe because of this")
806 visit::walk_item(this, item);
808 return; // Avoid visiting again.
820 self.invalid_visibility(
822 Some("place qualifiers on individual impl items instead"),
824 if let Unsafe::Yes(span) = unsafety {
829 "inherent impls cannot be unsafe"
831 .span_label(span, "unsafe because of this")
834 if polarity == ImplPolarity::Negative {
835 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
837 if defaultness == Defaultness::Default {
839 .struct_span_err(item.span, "inherent impls cannot be default")
840 .note("only trait implementations may be annotated with default")
843 if let Const::Yes(span) = constness {
845 .struct_span_err(item.span, "inherent impls cannot be `const`")
846 .span_label(span, "`const` because of this")
847 .note("only trait implementations may be annotated with `const`")
851 ItemKind::Fn(ref sig, ref generics, ref body) => {
852 self.check_const_fn_const_generic(item.span, sig, generics);
855 let msg = "free function without a body";
856 self.error_item_without_body(item.span, "function", msg, " { <body> }");
859 ItemKind::ForeignMod(_) => {
860 let old_item = mem::replace(&mut self.extern_mod, Some(item));
861 self.invalid_visibility(
863 Some("place qualifiers on individual foreign items instead"),
865 visit::walk_item(self, item);
866 self.extern_mod = old_item;
867 return; // Avoid visiting again.
869 ItemKind::Enum(ref def, _) => {
870 for variant in &def.variants {
871 self.invalid_visibility(&variant.vis, None);
872 for field in variant.data.fields() {
873 self.invalid_visibility(&field.vis, None);
877 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
878 if is_auto == IsAuto::Yes {
879 // Auto traits cannot have generics, super traits nor contain items.
880 if !generics.params.is_empty() {
885 "auto traits cannot have generic parameters"
889 if !bounds.is_empty() {
894 "auto traits cannot have super traits"
898 if !trait_items.is_empty() {
903 "auto traits cannot have methods or associated items"
908 self.no_questions_in_bounds(bounds, "supertraits", true);
910 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
911 // context for the supertraits.
912 self.visit_vis(&item.vis);
913 self.visit_ident(item.ident);
914 self.visit_generics(generics);
915 self.with_bound_context(BoundContext::TraitBounds, |this| {
916 walk_list!(this, visit_param_bound, bounds);
918 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
919 walk_list!(self, visit_attribute, &item.attrs);
922 ItemKind::Mod(_) => {
923 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
924 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
926 ItemKind::Union(ref vdata, _) => {
927 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
929 .span_err(item.span, "tuple and unit unions are not permitted");
931 if vdata.fields().is_empty() {
932 self.err_handler().span_err(item.span, "unions cannot have zero fields");
935 ItemKind::Const(.., None) => {
936 let msg = "free constant item without body";
937 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
939 ItemKind::Static(.., None) => {
940 let msg = "free static item without body";
941 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
946 visit::walk_item(self, item)
949 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
951 ForeignItemKind::Fn(sig, _, body) => {
952 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
953 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
955 ForeignItemKind::TyAlias(generics, bounds, body) => {
956 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
957 self.check_type_no_bounds(bounds, "`extern` blocks");
958 self.check_foreign_ty_genericless(generics);
960 ForeignItemKind::Static(_, _, body) => {
961 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
963 ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
966 visit::walk_foreign_item(self, fi)
969 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
970 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
971 match *generic_args {
972 GenericArgs::AngleBracketed(ref data) => {
973 walk_list!(self, visit_generic_arg, &data.args);
975 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
976 // are allowed to contain nested `impl Trait`.
977 self.with_impl_trait(None, |this| {
980 visit_assoc_ty_constraint_from_generic_args,
985 GenericArgs::Parenthesized(ref data) => {
986 walk_list!(self, visit_ty, &data.inputs);
987 if let FnRetTy::Ty(ty) = &data.output {
988 // `-> Foo` syntax is essentially an associated type binding,
989 // so it is also allowed to contain nested `impl Trait`.
990 self.with_impl_trait(None, |this| this.visit_ty(ty));
996 fn visit_generics(&mut self, generics: &'a Generics) {
997 let mut prev_ty_default = None;
998 for param in &generics.params {
999 if let GenericParamKind::Type { ref default, .. } = param.kind {
1000 if default.is_some() {
1001 prev_ty_default = Some(param.ident.span);
1002 } else if let Some(span) = prev_ty_default {
1004 .span_err(span, "type parameters with a default must be trailing");
1010 validate_generic_param_order(
1013 generics.params.iter().map(|param| {
1014 let ident = Some(param.ident.to_string());
1015 let (kind, ident) = match ¶m.kind {
1016 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1017 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1018 GenericParamKind::Const { ref ty } => {
1019 let ty = pprust::ty_to_string(ty);
1020 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1023 (kind, Some(&*param.bounds), param.ident.span, ident)
1028 for predicate in &generics.where_clause.predicates {
1029 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1033 "equality constraints are not yet supported in `where` clauses",
1035 .span_label(predicate.span, "not supported")
1037 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1038 for more information",
1044 visit::walk_generics(self, generics)
1047 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1048 if let GenericParamKind::Lifetime { .. } = param.kind {
1049 self.check_lifetime(param.ident);
1051 visit::walk_generic_param(self, param);
1054 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1056 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1057 if let Some(ctx) = self.bound_context {
1058 let msg = format!("`?const` is not permitted in {}", ctx.description());
1059 self.err_handler().span_err(bound.span(), &msg);
1063 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1065 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1071 visit::walk_param_bound(self, bound)
1074 fn visit_pat(&mut self, pat: &'a Pat) {
1076 PatKind::Lit(ref expr) => {
1077 self.check_expr_within_pat(expr, false);
1079 PatKind::Range(ref start, ref end, _) => {
1080 if let Some(expr) = start {
1081 self.check_expr_within_pat(expr, true);
1083 if let Some(expr) = end {
1084 self.check_expr_within_pat(expr, true);
1090 visit::walk_pat(self, pat)
1093 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1094 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1095 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1096 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1098 visit::walk_where_predicate(self, p);
1101 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1102 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1103 visit::walk_poly_trait_ref(self, t, m);
1106 fn visit_variant_data(&mut self, s: &'a VariantData) {
1107 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1112 enum_definition: &'a EnumDef,
1113 generics: &'a Generics,
1117 self.with_banned_assoc_ty_bound(|this| {
1118 visit::walk_enum_def(this, enum_definition, generics, item_id)
1122 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1123 // Only associated `fn`s can have `self` parameters.
1124 let self_semantic = match fk.ctxt() {
1125 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1126 _ => SelfSemantic::No,
1128 self.check_fn_decl(fk.decl(), self_semantic);
1130 self.check_c_varadic_type(fk);
1132 // Functions cannot both be `const async`
1133 if let Some(FnHeader {
1134 constness: Const::Yes(cspan),
1135 asyncness: Async::Yes { span: aspan, .. },
1140 .struct_span_err(span, "functions cannot be both `const` and `async`")
1141 .span_label(*cspan, "`const` because of this")
1142 .span_label(*aspan, "`async` because of this")
1146 // Functions without bodies cannot have patterns.
1147 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1148 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1149 let (code, msg, label) = match ctxt {
1150 FnCtxt::Foreign => (
1152 "patterns aren't allowed in foreign function declarations",
1153 "pattern not allowed in foreign function",
1157 "patterns aren't allowed in functions without bodies",
1158 "pattern not allowed in function without body",
1161 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1162 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1165 .struct_span_err(span, msg)
1166 .span_label(span, label)
1173 visit::walk_fn(self, fk, span);
1176 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1177 if ctxt == AssocCtxt::Trait {
1178 self.check_defaultness(item.span, item.defaultness);
1181 if ctxt == AssocCtxt::Impl {
1183 AssocItemKind::Const(_, body) => {
1184 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1186 AssocItemKind::Fn(_, _, body) => {
1187 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1189 AssocItemKind::TyAlias(_, bounds, body) => {
1190 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1191 self.check_type_no_bounds(bounds, "`impl`s");
1197 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1198 self.invalid_visibility(&item.vis, None);
1199 if let AssocItemKind::Fn(sig, _, _) = &item.kind {
1200 self.check_trait_fn_not_const(sig.header.constness);
1201 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1205 if let AssocItemKind::Const(..) = item.kind {
1206 self.check_item_named(item.ident, "const");
1209 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1213 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1214 let mut validator = AstValidator {
1217 in_trait_impl: false,
1218 has_proc_macro_decls: false,
1219 outer_impl_trait: None,
1220 bound_context: None,
1221 is_impl_trait_banned: false,
1222 is_assoc_ty_bound_banned: false,
1225 visit::walk_crate(&mut validator, krate);
1227 validator.has_proc_macro_decls