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 = 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 enum GenericPosition {
602 fn validate_generics_order<'a>(
604 handler: &rustc_errors::Handler,
605 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
606 pos: GenericPosition,
609 let mut max_param: Option<ParamKindOrd> = None;
610 let mut out_of_order = FxHashMap::default();
611 let mut param_idents = vec![];
612 let mut found_type = false;
613 let mut found_const = false;
615 for (kind, bounds, span, ident) in generics {
616 if let Some(ident) = ident {
617 param_idents.push((kind, bounds, param_idents.len(), ident));
619 let max_param = &mut max_param;
621 Some(max_param) if *max_param > kind => {
622 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
625 Some(_) | None => *max_param = Some(kind),
628 ParamKindOrd::Type => found_type = true,
629 ParamKindOrd::Const => found_const = true,
634 let mut ordered_params = "<".to_string();
635 if !out_of_order.is_empty() {
636 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
637 let mut first = true;
638 for (_, bounds, _, ident) in param_idents {
640 ordered_params += ", ";
642 ordered_params += &ident;
643 if let Some(bounds) = bounds {
644 if !bounds.is_empty() {
645 ordered_params += ": ";
646 ordered_params += &pprust::bounds_to_string(&bounds);
652 ordered_params += ">";
654 let pos_str = match pos {
655 GenericPosition::Param => "parameter",
656 GenericPosition::Arg => "argument",
659 for (param_ord, (max_param, spans)) in &out_of_order {
660 let mut err = handler.struct_span_err(
663 "{} {pos}s must be declared prior to {} {pos}s",
669 if let GenericPosition::Param = pos {
673 "reorder the {}s: lifetimes, then types{}",
675 if sess.features_untracked().const_generics { ", then consts" } else { "" },
677 ordered_params.clone(),
678 Applicability::MachineApplicable,
684 // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
685 // if we don't. Const parameters and type parameters can currently conflict if they
687 if !out_of_order.is_empty() && found_type && found_const {
692 impl<'a> Visitor<'a> for AstValidator<'a> {
693 fn visit_attribute(&mut self, attr: &Attribute) {
694 validate_attr::check_meta(&self.session.parse_sess, attr);
697 fn visit_expr(&mut self, expr: &'a Expr) {
699 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
704 "asm! is unsupported on this target"
711 visit::walk_expr(self, expr);
714 fn visit_ty(&mut self, ty: &'a Ty) {
716 TyKind::BareFn(ref bfty) => {
717 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
718 Self::check_decl_no_pat(&bfty.decl, |span, _| {
723 "patterns aren't allowed in function pointer types"
727 self.check_late_bound_lifetime_defs(&bfty.generic_params);
729 TyKind::TraitObject(ref bounds, ..) => {
730 let mut any_lifetime_bounds = false;
731 for bound in bounds {
732 if let GenericBound::Outlives(ref lifetime) = *bound {
733 if any_lifetime_bounds {
738 "only a single explicit lifetime bound is permitted"
743 any_lifetime_bounds = true;
746 self.no_questions_in_bounds(bounds, "trait object types", false);
748 TyKind::ImplTrait(_, ref bounds) => {
749 if self.is_impl_trait_banned {
754 "`impl Trait` is not allowed in path parameters"
759 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
764 "nested `impl Trait` is not allowed"
766 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
767 .span_label(ty.span, "nested `impl Trait` here")
773 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
775 self.err_handler().span_err(ty.span, "at least one trait must be specified");
787 fn visit_label(&mut self, label: &'a Label) {
788 self.check_label(label.ident);
789 visit::walk_label(self, label);
792 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
793 self.check_lifetime(lifetime.ident);
794 visit::walk_lifetime(self, lifetime);
797 fn visit_item(&mut self, item: &'a Item) {
798 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
799 self.has_proc_macro_decls = true;
813 self.with_in_trait_impl(true, |this| {
814 this.invalid_visibility(&item.vis, None);
815 if let TyKind::Err = self_ty.kind {
819 "`impl Trait for .. {}` is an obsolete syntax",
821 .help("use `auto trait Trait {}` instead")
824 if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
829 "negative impls cannot be unsafe"
831 .span_label(span, "unsafe because of this")
835 visit::walk_item(this, item);
837 return; // Avoid visiting again.
849 self.invalid_visibility(
851 Some("place qualifiers on individual impl items instead"),
853 if let Unsafe::Yes(span) = unsafety {
858 "inherent impls cannot be unsafe"
860 .span_label(span, "unsafe because of this")
863 if polarity == ImplPolarity::Negative {
864 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
866 if defaultness == Defaultness::Default {
868 .struct_span_err(item.span, "inherent impls cannot be default")
869 .note("only trait implementations may be annotated with default")
872 if let Const::Yes(span) = constness {
874 .struct_span_err(item.span, "inherent impls cannot be `const`")
875 .span_label(span, "`const` because of this")
876 .note("only trait implementations may be annotated with `const`")
880 ItemKind::Fn(ref sig, ref generics, ref body) => {
881 self.check_const_fn_const_generic(item.span, sig, generics);
884 let msg = "free function without a body";
885 self.error_item_without_body(item.span, "function", msg, " { <body> }");
888 ItemKind::ForeignMod(_) => {
889 let old_item = mem::replace(&mut self.extern_mod, Some(item));
890 self.invalid_visibility(
892 Some("place qualifiers on individual foreign items instead"),
894 visit::walk_item(self, item);
895 self.extern_mod = old_item;
896 return; // Avoid visiting again.
898 ItemKind::Enum(ref def, _) => {
899 for variant in &def.variants {
900 self.invalid_visibility(&variant.vis, None);
901 for field in variant.data.fields() {
902 self.invalid_visibility(&field.vis, None);
906 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
907 if is_auto == IsAuto::Yes {
908 // Auto traits cannot have generics, super traits nor contain items.
909 if !generics.params.is_empty() {
914 "auto traits cannot have generic parameters"
918 if !bounds.is_empty() {
923 "auto traits cannot have super traits"
927 if !trait_items.is_empty() {
932 "auto traits cannot have methods or associated items"
937 self.no_questions_in_bounds(bounds, "supertraits", true);
939 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
940 // context for the supertraits.
941 self.visit_vis(&item.vis);
942 self.visit_ident(item.ident);
943 self.visit_generics(generics);
944 self.with_bound_context(BoundContext::TraitBounds, |this| {
945 walk_list!(this, visit_param_bound, bounds);
947 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
948 walk_list!(self, visit_attribute, &item.attrs);
951 ItemKind::Mod(_) => {
952 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
953 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
955 ItemKind::Union(ref vdata, _) => {
956 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
958 .span_err(item.span, "tuple and unit unions are not permitted");
960 if vdata.fields().is_empty() {
961 self.err_handler().span_err(item.span, "unions cannot have zero fields");
964 ItemKind::Const(.., None) => {
965 let msg = "free constant item without body";
966 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
968 ItemKind::Static(.., None) => {
969 let msg = "free static item without body";
970 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
972 ItemKind::TyAlias(_, ref bounds, ref body) => {
974 let msg = "free type alias without body";
975 self.error_item_without_body(item.span, "type", msg, " = <type>;");
977 self.check_type_no_bounds(bounds, "this context");
982 visit::walk_item(self, item)
985 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
987 ForeignItemKind::Fn(sig, _, body) => {
988 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
989 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
991 ForeignItemKind::TyAlias(generics, bounds, body) => {
992 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
993 self.check_type_no_bounds(bounds, "`extern` blocks");
994 self.check_foreign_ty_genericless(generics);
996 ForeignItemKind::Static(_, _, body) => {
997 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
999 ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
1002 visit::walk_foreign_item(self, fi)
1005 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1006 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1007 match *generic_args {
1008 GenericArgs::AngleBracketed(ref data) => {
1009 walk_list!(self, visit_generic_arg, &data.args);
1010 validate_generics_order(
1013 data.args.iter().map(|arg| {
1016 GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
1017 GenericArg::Type(..) => ParamKindOrd::Type,
1018 GenericArg::Const(..) => ParamKindOrd::Const,
1025 GenericPosition::Arg,
1026 generic_args.span(),
1029 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1030 // are allowed to contain nested `impl Trait`.
1031 self.with_impl_trait(None, |this| {
1034 visit_assoc_ty_constraint_from_generic_args,
1039 GenericArgs::Parenthesized(ref data) => {
1040 walk_list!(self, visit_ty, &data.inputs);
1041 if let FnRetTy::Ty(ty) = &data.output {
1042 // `-> Foo` syntax is essentially an associated type binding,
1043 // so it is also allowed to contain nested `impl Trait`.
1044 self.with_impl_trait(None, |this| this.visit_ty(ty));
1050 fn visit_generics(&mut self, generics: &'a Generics) {
1051 let mut prev_ty_default = None;
1052 for param in &generics.params {
1053 if let GenericParamKind::Type { ref default, .. } = param.kind {
1054 if default.is_some() {
1055 prev_ty_default = Some(param.ident.span);
1056 } else if let Some(span) = prev_ty_default {
1058 .span_err(span, "type parameters with a default must be trailing");
1064 validate_generics_order(
1067 generics.params.iter().map(|param| {
1068 let ident = Some(param.ident.to_string());
1069 let (kind, ident) = match ¶m.kind {
1070 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1071 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1072 GenericParamKind::Const { ref ty } => {
1073 let ty = pprust::ty_to_string(ty);
1074 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1077 (kind, Some(&*param.bounds), param.ident.span, ident)
1079 GenericPosition::Param,
1083 for predicate in &generics.where_clause.predicates {
1084 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1088 "equality constraints are not yet supported in `where` clauses",
1090 .span_label(predicate.span, "not supported")
1092 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1093 for more information",
1099 visit::walk_generics(self, generics)
1102 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1103 if let GenericParamKind::Lifetime { .. } = param.kind {
1104 self.check_lifetime(param.ident);
1106 visit::walk_generic_param(self, param);
1109 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1111 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1112 if let Some(ctx) = self.bound_context {
1113 let msg = format!("`?const` is not permitted in {}", ctx.description());
1114 self.err_handler().span_err(bound.span(), &msg);
1118 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1120 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1126 visit::walk_param_bound(self, bound)
1129 fn visit_pat(&mut self, pat: &'a Pat) {
1131 PatKind::Lit(ref expr) => {
1132 self.check_expr_within_pat(expr, false);
1134 PatKind::Range(ref start, ref end, _) => {
1135 if let Some(expr) = start {
1136 self.check_expr_within_pat(expr, true);
1138 if let Some(expr) = end {
1139 self.check_expr_within_pat(expr, true);
1145 visit::walk_pat(self, pat)
1148 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1149 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1150 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1151 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1153 visit::walk_where_predicate(self, p);
1156 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1157 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1158 visit::walk_poly_trait_ref(self, t, m);
1161 fn visit_variant_data(&mut self, s: &'a VariantData) {
1162 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1167 enum_definition: &'a EnumDef,
1168 generics: &'a Generics,
1172 self.with_banned_assoc_ty_bound(|this| {
1173 visit::walk_enum_def(this, enum_definition, generics, item_id)
1177 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1178 // Only associated `fn`s can have `self` parameters.
1179 let self_semantic = match fk.ctxt() {
1180 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1181 _ => SelfSemantic::No,
1183 self.check_fn_decl(fk.decl(), self_semantic);
1185 self.check_c_varadic_type(fk);
1187 // Functions cannot both be `const async`
1188 if let Some(FnHeader {
1189 constness: Const::Yes(cspan),
1190 asyncness: Async::Yes { span: aspan, .. },
1195 .struct_span_err(span, "functions cannot be both `const` and `async`")
1196 .span_label(*cspan, "`const` because of this")
1197 .span_label(*aspan, "`async` because of this")
1201 // Functions without bodies cannot have patterns.
1202 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1203 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1204 let (code, msg, label) = match ctxt {
1205 FnCtxt::Foreign => (
1207 "patterns aren't allowed in foreign function declarations",
1208 "pattern not allowed in foreign function",
1212 "patterns aren't allowed in functions without bodies",
1213 "pattern not allowed in function without body",
1216 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1217 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1220 .struct_span_err(span, msg)
1221 .span_label(span, label)
1228 visit::walk_fn(self, fk, span);
1231 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1232 if ctxt == AssocCtxt::Trait {
1233 self.check_defaultness(item.span, item.defaultness);
1236 if ctxt == AssocCtxt::Impl {
1238 AssocItemKind::Const(_, body) => {
1239 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1241 AssocItemKind::Fn(_, _, body) => {
1242 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1244 AssocItemKind::TyAlias(_, bounds, body) => {
1245 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1246 self.check_type_no_bounds(bounds, "`impl`s");
1252 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1253 self.invalid_visibility(&item.vis, None);
1254 if let AssocItemKind::Fn(sig, _, _) = &item.kind {
1255 self.check_trait_fn_not_const(sig.header.constness);
1256 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1260 if let AssocItemKind::Const(..) = item.kind {
1261 self.check_item_named(item.ident, "const");
1264 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1268 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1269 let mut validator = AstValidator {
1272 in_trait_impl: false,
1273 has_proc_macro_decls: false,
1274 outer_impl_trait: None,
1275 bound_context: None,
1276 is_impl_trait_banned: false,
1277 is_assoc_ty_bound_banned: false,
1280 visit::walk_crate(&mut validator, krate);
1282 validator.has_proc_macro_decls