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 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 enum GenericPosition {
604 fn validate_generics_order<'a>(
606 handler: &rustc_errors::Handler,
607 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
608 pos: GenericPosition,
611 let mut max_param: Option<ParamKindOrd> = None;
612 let mut out_of_order = FxHashMap::default();
613 let mut param_idents = vec![];
614 let mut found_type = false;
615 let mut found_const = false;
617 for (kind, bounds, span, ident) in generics {
618 if let Some(ident) = ident {
619 param_idents.push((kind, bounds, param_idents.len(), ident));
621 let max_param = &mut max_param;
623 Some(max_param) if *max_param > kind => {
624 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
627 Some(_) | None => *max_param = Some(kind),
630 ParamKindOrd::Type => found_type = true,
631 ParamKindOrd::Const => found_const = true,
636 let mut ordered_params = "<".to_string();
637 if !out_of_order.is_empty() {
638 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
639 let mut first = true;
640 for (_, bounds, _, ident) in param_idents {
642 ordered_params += ", ";
644 ordered_params += &ident;
645 if let Some(bounds) = bounds {
646 if !bounds.is_empty() {
647 ordered_params += ": ";
648 ordered_params += &pprust::bounds_to_string(&bounds);
654 ordered_params += ">";
656 let pos_str = match pos {
657 GenericPosition::Param => "parameter",
658 GenericPosition::Arg => "argument",
661 for (param_ord, (max_param, spans)) in &out_of_order {
662 let mut err = handler.struct_span_err(
665 "{} {pos}s must be declared prior to {} {pos}s",
671 if let GenericPosition::Param = pos {
675 "reorder the {}s: lifetimes, then types{}",
677 if sess.features_untracked().const_generics { ", then consts" } else { "" },
679 ordered_params.clone(),
680 Applicability::MachineApplicable,
686 // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
687 // if we don't. Const parameters and type parameters can currently conflict if they
689 if !out_of_order.is_empty() && found_type && found_const {
694 impl<'a> Visitor<'a> for AstValidator<'a> {
695 fn visit_attribute(&mut self, attr: &Attribute) {
696 validate_attr::check_meta(&self.session.parse_sess, attr);
699 fn visit_expr(&mut self, expr: &'a Expr) {
701 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
706 "asm! is unsupported on this target"
713 visit::walk_expr(self, expr);
716 fn visit_ty(&mut self, ty: &'a Ty) {
718 TyKind::BareFn(ref bfty) => {
719 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
720 Self::check_decl_no_pat(&bfty.decl, |span, _| {
725 "patterns aren't allowed in function pointer types"
729 self.check_late_bound_lifetime_defs(&bfty.generic_params);
731 TyKind::TraitObject(ref bounds, ..) => {
732 let mut any_lifetime_bounds = false;
733 for bound in bounds {
734 if let GenericBound::Outlives(ref lifetime) = *bound {
735 if any_lifetime_bounds {
740 "only a single explicit lifetime bound is permitted"
745 any_lifetime_bounds = true;
748 self.no_questions_in_bounds(bounds, "trait object types", false);
750 TyKind::ImplTrait(_, ref bounds) => {
751 if self.is_impl_trait_banned {
756 "`impl Trait` is not allowed in path parameters"
761 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
766 "nested `impl Trait` is not allowed"
768 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
769 .span_label(ty.span, "nested `impl Trait` here")
775 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
777 self.err_handler().span_err(ty.span, "at least one trait must be specified");
789 fn visit_label(&mut self, label: &'a Label) {
790 self.check_label(label.ident);
791 visit::walk_label(self, label);
794 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
795 self.check_lifetime(lifetime.ident);
796 visit::walk_lifetime(self, lifetime);
799 fn visit_item(&mut self, item: &'a Item) {
800 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
801 self.has_proc_macro_decls = true;
815 self.with_in_trait_impl(true, |this| {
816 this.invalid_visibility(&item.vis, None);
817 if let TyKind::Err = self_ty.kind {
821 "`impl Trait for .. {}` is an obsolete syntax",
823 .help("use `auto trait Trait {}` instead")
826 if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
831 "negative impls cannot be unsafe"
833 .span_label(span, "unsafe because of this")
837 visit::walk_item(this, item);
839 return; // Avoid visiting again.
851 self.invalid_visibility(
853 Some("place qualifiers on individual impl items instead"),
855 if let Unsafe::Yes(span) = unsafety {
860 "inherent impls cannot be unsafe"
862 .span_label(span, "unsafe because of this")
865 if polarity == ImplPolarity::Negative {
866 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
868 if let Defaultness::Default(def_span) = defaultness {
869 let span = self.session.source_map().def_span(item.span);
871 .struct_span_err(span, "inherent impls cannot be `default`")
872 .span_label(def_span, "`default` because of this")
873 .note("only trait implementations may be annotated with `default`")
876 if let Const::Yes(span) = constness {
878 .struct_span_err(item.span, "inherent impls cannot be `const`")
879 .span_label(span, "`const` because of this")
880 .note("only trait implementations may be annotated with `const`")
884 ItemKind::Fn(ref sig, ref generics, ref body) => {
885 self.check_const_fn_const_generic(item.span, sig, generics);
888 let msg = "free function without a body";
889 self.error_item_without_body(item.span, "function", msg, " { <body> }");
892 ItemKind::ForeignMod(_) => {
893 let old_item = mem::replace(&mut self.extern_mod, Some(item));
894 self.invalid_visibility(
896 Some("place qualifiers on individual foreign items instead"),
898 visit::walk_item(self, item);
899 self.extern_mod = old_item;
900 return; // Avoid visiting again.
902 ItemKind::Enum(ref def, _) => {
903 for variant in &def.variants {
904 self.invalid_visibility(&variant.vis, None);
905 for field in variant.data.fields() {
906 self.invalid_visibility(&field.vis, None);
910 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
911 if is_auto == IsAuto::Yes {
912 // Auto traits cannot have generics, super traits nor contain items.
913 if !generics.params.is_empty() {
918 "auto traits cannot have generic parameters"
922 if !bounds.is_empty() {
927 "auto traits cannot have super traits"
931 if !trait_items.is_empty() {
936 "auto traits cannot have methods or associated items"
941 self.no_questions_in_bounds(bounds, "supertraits", true);
943 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
944 // context for the supertraits.
945 self.visit_vis(&item.vis);
946 self.visit_ident(item.ident);
947 self.visit_generics(generics);
948 self.with_bound_context(BoundContext::TraitBounds, |this| {
949 walk_list!(this, visit_param_bound, bounds);
951 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
952 walk_list!(self, visit_attribute, &item.attrs);
955 ItemKind::Mod(_) => {
956 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
957 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
959 ItemKind::Union(ref vdata, _) => {
960 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
962 .span_err(item.span, "tuple and unit unions are not permitted");
964 if vdata.fields().is_empty() {
965 self.err_handler().span_err(item.span, "unions cannot have zero fields");
968 ItemKind::Const(.., None) => {
969 let msg = "free constant item without body";
970 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
972 ItemKind::Static(.., None) => {
973 let msg = "free static item without body";
974 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
976 ItemKind::TyAlias(_, ref bounds, ref body) => {
978 let msg = "free type alias without body";
979 self.error_item_without_body(item.span, "type", msg, " = <type>;");
981 self.check_type_no_bounds(bounds, "this context");
986 visit::walk_item(self, item)
989 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
991 ForeignItemKind::Fn(sig, _, body) => {
992 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
993 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
995 ForeignItemKind::TyAlias(generics, bounds, body) => {
996 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
997 self.check_type_no_bounds(bounds, "`extern` blocks");
998 self.check_foreign_ty_genericless(generics);
1000 ForeignItemKind::Static(_, _, body) => {
1001 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1003 ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
1006 visit::walk_foreign_item(self, fi)
1009 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1010 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1011 match *generic_args {
1012 GenericArgs::AngleBracketed(ref data) => {
1013 walk_list!(self, visit_generic_arg, &data.args);
1014 validate_generics_order(
1017 data.args.iter().map(|arg| {
1020 GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
1021 GenericArg::Type(..) => ParamKindOrd::Type,
1022 GenericArg::Const(..) => ParamKindOrd::Const,
1029 GenericPosition::Arg,
1030 generic_args.span(),
1033 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1034 // are allowed to contain nested `impl Trait`.
1035 self.with_impl_trait(None, |this| {
1038 visit_assoc_ty_constraint_from_generic_args,
1043 GenericArgs::Parenthesized(ref data) => {
1044 walk_list!(self, visit_ty, &data.inputs);
1045 if let FnRetTy::Ty(ty) = &data.output {
1046 // `-> Foo` syntax is essentially an associated type binding,
1047 // so it is also allowed to contain nested `impl Trait`.
1048 self.with_impl_trait(None, |this| this.visit_ty(ty));
1054 fn visit_generics(&mut self, generics: &'a Generics) {
1055 let mut prev_ty_default = None;
1056 for param in &generics.params {
1057 if let GenericParamKind::Type { ref default, .. } = param.kind {
1058 if default.is_some() {
1059 prev_ty_default = Some(param.ident.span);
1060 } else if let Some(span) = prev_ty_default {
1062 .span_err(span, "type parameters with a default must be trailing");
1068 validate_generics_order(
1071 generics.params.iter().map(|param| {
1072 let ident = Some(param.ident.to_string());
1073 let (kind, ident) = match ¶m.kind {
1074 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1075 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1076 GenericParamKind::Const { ref ty } => {
1077 let ty = pprust::ty_to_string(ty);
1078 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1081 (kind, Some(&*param.bounds), param.ident.span, ident)
1083 GenericPosition::Param,
1087 for predicate in &generics.where_clause.predicates {
1088 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1092 "equality constraints are not yet supported in `where` clauses",
1094 .span_label(predicate.span, "not supported")
1096 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1097 for more information",
1103 visit::walk_generics(self, generics)
1106 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1107 if let GenericParamKind::Lifetime { .. } = param.kind {
1108 self.check_lifetime(param.ident);
1110 visit::walk_generic_param(self, param);
1113 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1115 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1116 if let Some(ctx) = self.bound_context {
1117 let msg = format!("`?const` is not permitted in {}", ctx.description());
1118 self.err_handler().span_err(bound.span(), &msg);
1122 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1124 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1130 visit::walk_param_bound(self, bound)
1133 fn visit_pat(&mut self, pat: &'a Pat) {
1135 PatKind::Lit(ref expr) => {
1136 self.check_expr_within_pat(expr, false);
1138 PatKind::Range(ref start, ref end, _) => {
1139 if let Some(expr) = start {
1140 self.check_expr_within_pat(expr, true);
1142 if let Some(expr) = end {
1143 self.check_expr_within_pat(expr, true);
1149 visit::walk_pat(self, pat)
1152 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1153 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1154 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1155 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1157 visit::walk_where_predicate(self, p);
1160 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1161 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1162 visit::walk_poly_trait_ref(self, t, m);
1165 fn visit_variant_data(&mut self, s: &'a VariantData) {
1166 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1171 enum_definition: &'a EnumDef,
1172 generics: &'a Generics,
1176 self.with_banned_assoc_ty_bound(|this| {
1177 visit::walk_enum_def(this, enum_definition, generics, item_id)
1181 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1182 // Only associated `fn`s can have `self` parameters.
1183 let self_semantic = match fk.ctxt() {
1184 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1185 _ => SelfSemantic::No,
1187 self.check_fn_decl(fk.decl(), self_semantic);
1189 self.check_c_varadic_type(fk);
1191 // Functions cannot both be `const async`
1192 if let Some(FnHeader {
1193 constness: Const::Yes(cspan),
1194 asyncness: Async::Yes { span: aspan, .. },
1199 .struct_span_err(span, "functions cannot be both `const` and `async`")
1200 .span_label(*cspan, "`const` because of this")
1201 .span_label(*aspan, "`async` because of this")
1205 // Functions without bodies cannot have patterns.
1206 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1207 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1208 let (code, msg, label) = match ctxt {
1209 FnCtxt::Foreign => (
1211 "patterns aren't allowed in foreign function declarations",
1212 "pattern not allowed in foreign function",
1216 "patterns aren't allowed in functions without bodies",
1217 "pattern not allowed in function without body",
1220 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1221 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1224 .struct_span_err(span, msg)
1225 .span_label(span, label)
1232 visit::walk_fn(self, fk, span);
1235 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1236 if ctxt == AssocCtxt::Trait {
1237 self.check_defaultness(item.span, item.defaultness);
1240 if ctxt == AssocCtxt::Impl {
1242 AssocItemKind::Const(_, body) => {
1243 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1245 AssocItemKind::Fn(_, _, body) => {
1246 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1248 AssocItemKind::TyAlias(_, bounds, body) => {
1249 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1250 self.check_type_no_bounds(bounds, "`impl`s");
1256 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1257 self.invalid_visibility(&item.vis, None);
1258 if let AssocItemKind::Fn(sig, _, _) = &item.kind {
1259 self.check_trait_fn_not_const(sig.header.constness);
1260 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1264 if let AssocItemKind::Const(..) = item.kind {
1265 self.check_item_named(item.ident, "const");
1268 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1272 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1273 let mut validator = AstValidator {
1276 in_trait_impl: false,
1277 has_proc_macro_decls: false,
1278 outer_impl_trait: None,
1279 bound_context: None,
1280 is_impl_trait_banned: false,
1281 is_assoc_ty_bound_banned: false,
1284 visit::walk_crate(&mut validator, krate);
1286 validator.has_proc_macro_decls