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.
11 use rustc_ast::expand::is_proc_macro_attr;
12 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
13 use rustc_ast::walk_list;
14 use rustc_ast_pretty::pprust;
15 use rustc_data_structures::fx::FxHashMap;
16 use rustc_errors::{error_code, struct_span_err, Applicability};
17 use rustc_parse::validate_attr;
18 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
19 use rustc_session::lint::LintBuffer;
20 use rustc_session::Session;
21 use rustc_span::symbol::{kw, sym};
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(def_span) = defaultness {
404 let span = self.session.source_map().def_span(span);
406 .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
407 .span_label(def_span, "`default` because of this")
412 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
414 .struct_span_err(sp, msg)
416 self.session.source_map().end_point(sp),
417 &format!("provide a definition for the {}", ctx),
419 Applicability::HasPlaceholders,
424 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
426 let msg = format!("associated {} in `impl` without body", ctx);
427 self.error_item_without_body(sp, ctx, &msg, sugg);
431 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
432 let span = match bounds {
435 [b0, .., bl] => b0.span().to(bl.span()),
438 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
442 fn check_foreign_ty_genericless(&self, generics: &Generics) {
443 let cannot_have = |span, descr, remove_descr| {
447 &format!("`type`s inside `extern` blocks cannot have {}", descr),
451 &format!("remove the {}", remove_descr),
453 Applicability::MaybeIncorrect,
455 .span_label(self.current_extern_span(), "`extern` block begins here")
460 if !generics.params.is_empty() {
461 cannot_have(generics.span, "generic parameters", "generic parameters");
464 if !generics.where_clause.predicates.is_empty() {
465 cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
469 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
470 let body = match body {
475 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
476 .span_label(ident.span, "cannot have a body")
477 .span_label(body, "the invalid body")
479 self.current_extern_span(),
481 "`extern` blocks define existing foreign {0}s and {0}s \
482 inside of them cannot have a body",
490 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
491 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
492 let body = match body {
497 .struct_span_err(ident.span, "incorrect function inside `extern` block")
498 .span_label(ident.span, "cannot have a body")
501 "remove the invalid body",
503 Applicability::MaybeIncorrect,
506 "you might have meant to write a function accessible through FFI, \
507 which can be done by writing `extern fn` outside of the `extern` block",
510 self.current_extern_span(),
511 "`extern` blocks define existing foreign functions and functions \
512 inside of them cannot have a body",
518 fn current_extern_span(&self) -> Span {
519 self.session.source_map().def_span(self.extern_mod.unwrap().span)
522 /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
523 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
524 if header.has_qualifiers() {
526 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
527 .span_label(self.current_extern_span(), "in this `extern` block")
529 span.until(ident.span.shrink_to_lo()),
530 "remove the qualifiers",
532 Applicability::MaybeIncorrect,
538 /// Reject C-varadic type unless the function is foreign,
539 /// or free and `unsafe extern "C"` semantically.
540 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
541 match (fk.ctxt(), fk.header()) {
542 (Some(FnCtxt::Foreign), _) => return,
543 (Some(FnCtxt::Free), Some(header)) => match header.ext {
544 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
545 if matches!(header.unsafety, Unsafe::Yes(_)) =>
554 for Param { ty, span, .. } in &fk.decl().inputs {
555 if let TyKind::CVarArgs = ty.kind {
559 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
566 /// We currently do not permit const generics in `const fn`,
567 /// as this is tantamount to allowing compile-time dependent typing.
569 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
570 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
571 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
572 if let Const::Yes(const_span) = sig.header.constness {
573 // Look for const generics and error if we find any.
574 for param in &generics.params {
575 if let GenericParamKind::Const { .. } = param.kind {
579 "const parameters are not permitted in const functions",
581 .span_label(const_span, "`const` because of this")
588 fn check_item_named(&self, ident: Ident, kind: &str) {
589 if ident.name != kw::Underscore {
593 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
594 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
599 fn validate_generic_param_order<'a>(
601 handler: &rustc_errors::Handler,
602 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
605 let mut max_param: Option<ParamKindOrd> = None;
606 let mut out_of_order = FxHashMap::default();
607 let mut param_idents = vec![];
609 for (kind, bounds, span, ident) in generics {
610 if let Some(ident) = ident {
611 param_idents.push((kind, bounds, param_idents.len(), ident));
613 let max_param = &mut max_param;
615 Some(max_param) if *max_param > kind => {
616 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
619 Some(_) | None => *max_param = Some(kind),
623 let mut ordered_params = "<".to_string();
624 if !out_of_order.is_empty() {
625 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
626 let mut first = true;
627 for (_, bounds, _, ident) in param_idents {
629 ordered_params += ", ";
631 ordered_params += &ident;
632 if let Some(bounds) = bounds {
633 if !bounds.is_empty() {
634 ordered_params += ": ";
635 ordered_params += &pprust::bounds_to_string(&bounds);
641 ordered_params += ">";
643 for (param_ord, (max_param, spans)) in &out_of_order {
645 handler.struct_span_err(
648 "{} parameters must be declared prior to {} parameters",
649 param_ord, max_param,
655 "reorder the parameters: lifetimes, then types{}",
656 if sess.features_untracked().const_generics { ", then consts" } else { "" },
658 ordered_params.clone(),
659 Applicability::MachineApplicable,
665 impl<'a> Visitor<'a> for AstValidator<'a> {
666 fn visit_attribute(&mut self, attr: &Attribute) {
667 validate_attr::check_meta(&self.session.parse_sess, attr);
670 fn visit_expr(&mut self, expr: &'a Expr) {
672 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
677 "asm! is unsupported on this target"
684 visit::walk_expr(self, expr);
687 fn visit_ty(&mut self, ty: &'a Ty) {
689 TyKind::BareFn(ref bfty) => {
690 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
691 Self::check_decl_no_pat(&bfty.decl, |span, _| {
696 "patterns aren't allowed in function pointer types"
700 self.check_late_bound_lifetime_defs(&bfty.generic_params);
702 TyKind::TraitObject(ref bounds, ..) => {
703 let mut any_lifetime_bounds = false;
704 for bound in bounds {
705 if let GenericBound::Outlives(ref lifetime) = *bound {
706 if any_lifetime_bounds {
711 "only a single explicit lifetime bound is permitted"
716 any_lifetime_bounds = true;
719 self.no_questions_in_bounds(bounds, "trait object types", false);
721 TyKind::ImplTrait(_, ref bounds) => {
722 if self.is_impl_trait_banned {
727 "`impl Trait` is not allowed in path parameters"
732 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
737 "nested `impl Trait` is not allowed"
739 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
740 .span_label(ty.span, "nested `impl Trait` here")
746 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
748 self.err_handler().span_err(ty.span, "at least one trait must be specified");
760 fn visit_label(&mut self, label: &'a Label) {
761 self.check_label(label.ident);
762 visit::walk_label(self, label);
765 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
766 self.check_lifetime(lifetime.ident);
767 visit::walk_lifetime(self, lifetime);
770 fn visit_item(&mut self, item: &'a Item) {
771 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
772 self.has_proc_macro_decls = true;
786 self.with_in_trait_impl(true, |this| {
787 this.invalid_visibility(&item.vis, None);
788 if let TyKind::Err = self_ty.kind {
792 "`impl Trait for .. {}` is an obsolete syntax",
794 .help("use `auto trait Trait {}` instead")
797 if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
802 "negative impls cannot be unsafe"
804 .span_label(span, "unsafe because of this")
808 visit::walk_item(this, item);
810 return; // Avoid visiting again.
822 self.invalid_visibility(
824 Some("place qualifiers on individual impl items instead"),
826 if let Unsafe::Yes(span) = unsafety {
831 "inherent impls cannot be unsafe"
833 .span_label(span, "unsafe because of this")
836 if polarity == ImplPolarity::Negative {
837 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
839 if let Defaultness::Default(def_span) = defaultness {
840 let span = self.session.source_map().def_span(item.span);
842 .struct_span_err(span, "inherent impls cannot be `default`")
843 .span_label(def_span, "`default` because of this")
844 .note("only trait implementations may be annotated with `default`")
847 if let Const::Yes(span) = constness {
849 .struct_span_err(item.span, "inherent impls cannot be `const`")
850 .span_label(span, "`const` because of this")
851 .note("only trait implementations may be annotated with `const`")
855 ItemKind::Fn(def, ref sig, ref generics, ref body) => {
856 self.check_defaultness(item.span, def);
857 self.check_const_fn_const_generic(item.span, sig, generics);
860 let msg = "free function without a body";
861 self.error_item_without_body(item.span, "function", msg, " { <body> }");
864 ItemKind::ForeignMod(_) => {
865 let old_item = mem::replace(&mut self.extern_mod, Some(item));
866 self.invalid_visibility(
868 Some("place qualifiers on individual foreign items instead"),
870 visit::walk_item(self, item);
871 self.extern_mod = old_item;
872 return; // Avoid visiting again.
874 ItemKind::Enum(ref def, _) => {
875 for variant in &def.variants {
876 self.invalid_visibility(&variant.vis, None);
877 for field in variant.data.fields() {
878 self.invalid_visibility(&field.vis, None);
882 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
883 if is_auto == IsAuto::Yes {
884 // Auto traits cannot have generics, super traits nor contain items.
885 if !generics.params.is_empty() {
890 "auto traits cannot have generic parameters"
894 if !bounds.is_empty() {
899 "auto traits cannot have super traits"
903 if !trait_items.is_empty() {
908 "auto traits cannot have methods or associated items"
913 self.no_questions_in_bounds(bounds, "supertraits", true);
915 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
916 // context for the supertraits.
917 self.visit_vis(&item.vis);
918 self.visit_ident(item.ident);
919 self.visit_generics(generics);
920 self.with_bound_context(BoundContext::TraitBounds, |this| {
921 walk_list!(this, visit_param_bound, bounds);
923 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
924 walk_list!(self, visit_attribute, &item.attrs);
927 ItemKind::Mod(_) => {
928 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
929 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
931 ItemKind::Union(ref vdata, _) => {
932 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
934 .span_err(item.span, "tuple and unit unions are not permitted");
936 if vdata.fields().is_empty() {
937 self.err_handler().span_err(item.span, "unions cannot have zero fields");
940 ItemKind::Const(def, .., None) => {
941 self.check_defaultness(item.span, def);
942 let msg = "free constant item without body";
943 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
945 ItemKind::Static(.., None) => {
946 let msg = "free static item without body";
947 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
949 ItemKind::TyAlias(def, _, ref bounds, ref body) => {
950 self.check_defaultness(item.span, def);
952 let msg = "free type alias without body";
953 self.error_item_without_body(item.span, "type", msg, " = <type>;");
955 self.check_type_no_bounds(bounds, "this context");
960 visit::walk_item(self, item)
963 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
965 ForeignItemKind::Fn(def, sig, _, body) => {
966 self.check_defaultness(fi.span, *def);
967 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
968 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
970 ForeignItemKind::TyAlias(def, generics, bounds, body) => {
971 self.check_defaultness(fi.span, *def);
972 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
973 self.check_type_no_bounds(bounds, "`extern` blocks");
974 self.check_foreign_ty_genericless(generics);
976 ForeignItemKind::Static(_, _, body) => {
977 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
979 ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
982 visit::walk_foreign_item(self, fi)
985 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
986 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
987 match *generic_args {
988 GenericArgs::AngleBracketed(ref data) => {
989 walk_list!(self, visit_generic_arg, &data.args);
991 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
992 // are allowed to contain nested `impl Trait`.
993 self.with_impl_trait(None, |this| {
996 visit_assoc_ty_constraint_from_generic_args,
1001 GenericArgs::Parenthesized(ref data) => {
1002 walk_list!(self, visit_ty, &data.inputs);
1003 if let FnRetTy::Ty(ty) = &data.output {
1004 // `-> Foo` syntax is essentially an associated type binding,
1005 // so it is also allowed to contain nested `impl Trait`.
1006 self.with_impl_trait(None, |this| this.visit_ty(ty));
1012 fn visit_generics(&mut self, generics: &'a Generics) {
1013 let mut prev_ty_default = None;
1014 for param in &generics.params {
1015 if let GenericParamKind::Type { ref default, .. } = param.kind {
1016 if default.is_some() {
1017 prev_ty_default = Some(param.ident.span);
1018 } else if let Some(span) = prev_ty_default {
1020 .span_err(span, "type parameters with a default must be trailing");
1026 validate_generic_param_order(
1029 generics.params.iter().map(|param| {
1030 let ident = Some(param.ident.to_string());
1031 let (kind, ident) = match ¶m.kind {
1032 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1033 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1034 GenericParamKind::Const { ref ty } => {
1035 let ty = pprust::ty_to_string(ty);
1036 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1039 (kind, Some(&*param.bounds), param.ident.span, ident)
1044 for predicate in &generics.where_clause.predicates {
1045 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1049 "equality constraints are not yet supported in `where` clauses",
1051 .span_label(predicate.span, "not supported")
1053 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1054 for more information",
1060 visit::walk_generics(self, generics)
1063 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1064 if let GenericParamKind::Lifetime { .. } = param.kind {
1065 self.check_lifetime(param.ident);
1067 visit::walk_generic_param(self, param);
1070 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1072 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1073 if let Some(ctx) = self.bound_context {
1074 let msg = format!("`?const` is not permitted in {}", ctx.description());
1075 self.err_handler().span_err(bound.span(), &msg);
1079 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1081 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1087 visit::walk_param_bound(self, bound)
1090 fn visit_pat(&mut self, pat: &'a Pat) {
1092 PatKind::Lit(ref expr) => {
1093 self.check_expr_within_pat(expr, false);
1095 PatKind::Range(ref start, ref end, _) => {
1096 if let Some(expr) = start {
1097 self.check_expr_within_pat(expr, true);
1099 if let Some(expr) = end {
1100 self.check_expr_within_pat(expr, true);
1106 visit::walk_pat(self, pat)
1109 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1110 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1111 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1112 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1114 visit::walk_where_predicate(self, p);
1117 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1118 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1119 visit::walk_poly_trait_ref(self, t, m);
1122 fn visit_variant_data(&mut self, s: &'a VariantData) {
1123 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1128 enum_definition: &'a EnumDef,
1129 generics: &'a Generics,
1133 self.with_banned_assoc_ty_bound(|this| {
1134 visit::walk_enum_def(this, enum_definition, generics, item_id)
1138 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1139 // Only associated `fn`s can have `self` parameters.
1140 let self_semantic = match fk.ctxt() {
1141 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1142 _ => SelfSemantic::No,
1144 self.check_fn_decl(fk.decl(), self_semantic);
1146 self.check_c_varadic_type(fk);
1148 // Functions cannot both be `const async`
1149 if let Some(FnHeader {
1150 constness: Const::Yes(cspan),
1151 asyncness: Async::Yes { span: aspan, .. },
1156 .struct_span_err(span, "functions cannot be both `const` and `async`")
1157 .span_label(*cspan, "`const` because of this")
1158 .span_label(*aspan, "`async` because of this")
1162 // Functions without bodies cannot have patterns.
1163 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1164 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1165 let (code, msg, label) = match ctxt {
1166 FnCtxt::Foreign => (
1168 "patterns aren't allowed in foreign function declarations",
1169 "pattern not allowed in foreign function",
1173 "patterns aren't allowed in functions without bodies",
1174 "pattern not allowed in function without body",
1177 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1178 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1181 .struct_span_err(span, msg)
1182 .span_label(span, label)
1189 visit::walk_fn(self, fk, span);
1192 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1193 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1194 self.check_defaultness(item.span, item.kind.defaultness());
1197 if ctxt == AssocCtxt::Impl {
1199 AssocItemKind::Const(_, _, body) => {
1200 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1202 AssocItemKind::Fn(_, _, _, body) => {
1203 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1205 AssocItemKind::TyAlias(_, _, bounds, body) => {
1206 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1207 self.check_type_no_bounds(bounds, "`impl`s");
1213 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1214 self.invalid_visibility(&item.vis, None);
1215 if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
1216 self.check_trait_fn_not_const(sig.header.constness);
1217 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1221 if let AssocItemKind::Const(..) = item.kind {
1222 self.check_item_named(item.ident, "const");
1225 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1229 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1230 let mut validator = AstValidator {
1233 in_trait_impl: false,
1234 has_proc_macro_decls: false,
1235 outer_impl_trait: None,
1236 bound_context: None,
1237 is_impl_trait_banned: false,
1238 is_assoc_ty_bound_banned: false,
1241 visit::walk_crate(&mut validator, krate);
1243 validator.has_proc_macro_decls