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(def, ref sig, ref generics, ref body) => {
885 self.check_defaultness(item.span, def);
886 self.check_const_fn_const_generic(item.span, sig, generics);
889 let msg = "free function without a body";
890 self.error_item_without_body(item.span, "function", msg, " { <body> }");
893 ItemKind::ForeignMod(_) => {
894 let old_item = mem::replace(&mut self.extern_mod, Some(item));
895 self.invalid_visibility(
897 Some("place qualifiers on individual foreign items instead"),
899 visit::walk_item(self, item);
900 self.extern_mod = old_item;
901 return; // Avoid visiting again.
903 ItemKind::Enum(ref def, _) => {
904 for variant in &def.variants {
905 self.invalid_visibility(&variant.vis, None);
906 for field in variant.data.fields() {
907 self.invalid_visibility(&field.vis, None);
911 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
912 if is_auto == IsAuto::Yes {
913 // Auto traits cannot have generics, super traits nor contain items.
914 if !generics.params.is_empty() {
919 "auto traits cannot have generic parameters"
923 if !bounds.is_empty() {
928 "auto traits cannot have super traits"
932 if !trait_items.is_empty() {
937 "auto traits cannot have methods or associated items"
942 self.no_questions_in_bounds(bounds, "supertraits", true);
944 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
945 // context for the supertraits.
946 self.visit_vis(&item.vis);
947 self.visit_ident(item.ident);
948 self.visit_generics(generics);
949 self.with_bound_context(BoundContext::TraitBounds, |this| {
950 walk_list!(this, visit_param_bound, bounds);
952 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
953 walk_list!(self, visit_attribute, &item.attrs);
956 ItemKind::Mod(_) => {
957 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
958 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
960 ItemKind::Union(ref vdata, _) => {
961 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
963 .span_err(item.span, "tuple and unit unions are not permitted");
965 if vdata.fields().is_empty() {
966 self.err_handler().span_err(item.span, "unions cannot have zero fields");
969 ItemKind::Const(def, .., None) => {
970 self.check_defaultness(item.span, def);
971 let msg = "free constant item without body";
972 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
974 ItemKind::Static(.., None) => {
975 let msg = "free static item without body";
976 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
978 ItemKind::TyAlias(def, _, ref bounds, ref body) => {
979 self.check_defaultness(item.span, def);
981 let msg = "free type alias without body";
982 self.error_item_without_body(item.span, "type", msg, " = <type>;");
984 self.check_type_no_bounds(bounds, "this context");
989 visit::walk_item(self, item)
992 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
994 ForeignItemKind::Fn(def, sig, _, body) => {
995 self.check_defaultness(fi.span, *def);
996 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
997 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
999 ForeignItemKind::TyAlias(def, generics, bounds, body) => {
1000 self.check_defaultness(fi.span, *def);
1001 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1002 self.check_type_no_bounds(bounds, "`extern` blocks");
1003 self.check_foreign_ty_genericless(generics);
1005 ForeignItemKind::Static(_, _, body) => {
1006 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1008 ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
1011 visit::walk_foreign_item(self, fi)
1014 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1015 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1016 match *generic_args {
1017 GenericArgs::AngleBracketed(ref data) => {
1018 walk_list!(self, visit_generic_arg, &data.args);
1019 validate_generics_order(
1022 data.args.iter().map(|arg| {
1025 GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
1026 GenericArg::Type(..) => ParamKindOrd::Type,
1027 GenericArg::Const(..) => ParamKindOrd::Const,
1034 GenericPosition::Arg,
1035 generic_args.span(),
1038 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1039 // are allowed to contain nested `impl Trait`.
1040 self.with_impl_trait(None, |this| {
1043 visit_assoc_ty_constraint_from_generic_args,
1048 GenericArgs::Parenthesized(ref data) => {
1049 walk_list!(self, visit_ty, &data.inputs);
1050 if let FnRetTy::Ty(ty) = &data.output {
1051 // `-> Foo` syntax is essentially an associated type binding,
1052 // so it is also allowed to contain nested `impl Trait`.
1053 self.with_impl_trait(None, |this| this.visit_ty(ty));
1059 fn visit_generics(&mut self, generics: &'a Generics) {
1060 let mut prev_ty_default = None;
1061 for param in &generics.params {
1062 if let GenericParamKind::Type { ref default, .. } = param.kind {
1063 if default.is_some() {
1064 prev_ty_default = Some(param.ident.span);
1065 } else if let Some(span) = prev_ty_default {
1067 .span_err(span, "type parameters with a default must be trailing");
1073 validate_generics_order(
1076 generics.params.iter().map(|param| {
1077 let ident = Some(param.ident.to_string());
1078 let (kind, ident) = match ¶m.kind {
1079 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1080 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1081 GenericParamKind::Const { ref ty } => {
1082 let ty = pprust::ty_to_string(ty);
1083 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1086 (kind, Some(&*param.bounds), param.ident.span, ident)
1088 GenericPosition::Param,
1092 for predicate in &generics.where_clause.predicates {
1093 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1097 "equality constraints are not yet supported in `where` clauses",
1099 .span_label(predicate.span, "not supported")
1101 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1102 for more information",
1108 visit::walk_generics(self, generics)
1111 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1112 if let GenericParamKind::Lifetime { .. } = param.kind {
1113 self.check_lifetime(param.ident);
1115 visit::walk_generic_param(self, param);
1118 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1120 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1121 if let Some(ctx) = self.bound_context {
1122 let msg = format!("`?const` is not permitted in {}", ctx.description());
1123 self.err_handler().span_err(bound.span(), &msg);
1127 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1129 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1135 visit::walk_param_bound(self, bound)
1138 fn visit_pat(&mut self, pat: &'a Pat) {
1140 PatKind::Lit(ref expr) => {
1141 self.check_expr_within_pat(expr, false);
1143 PatKind::Range(ref start, ref end, _) => {
1144 if let Some(expr) = start {
1145 self.check_expr_within_pat(expr, true);
1147 if let Some(expr) = end {
1148 self.check_expr_within_pat(expr, true);
1154 visit::walk_pat(self, pat)
1157 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1158 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1159 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1160 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1162 visit::walk_where_predicate(self, p);
1165 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1166 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1167 visit::walk_poly_trait_ref(self, t, m);
1170 fn visit_variant_data(&mut self, s: &'a VariantData) {
1171 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1176 enum_definition: &'a EnumDef,
1177 generics: &'a Generics,
1181 self.with_banned_assoc_ty_bound(|this| {
1182 visit::walk_enum_def(this, enum_definition, generics, item_id)
1186 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1187 // Only associated `fn`s can have `self` parameters.
1188 let self_semantic = match fk.ctxt() {
1189 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1190 _ => SelfSemantic::No,
1192 self.check_fn_decl(fk.decl(), self_semantic);
1194 self.check_c_varadic_type(fk);
1196 // Functions cannot both be `const async`
1197 if let Some(FnHeader {
1198 constness: Const::Yes(cspan),
1199 asyncness: Async::Yes { span: aspan, .. },
1204 .struct_span_err(span, "functions cannot be both `const` and `async`")
1205 .span_label(*cspan, "`const` because of this")
1206 .span_label(*aspan, "`async` because of this")
1210 // Functions without bodies cannot have patterns.
1211 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1212 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1213 let (code, msg, label) = match ctxt {
1214 FnCtxt::Foreign => (
1216 "patterns aren't allowed in foreign function declarations",
1217 "pattern not allowed in foreign function",
1221 "patterns aren't allowed in functions without bodies",
1222 "pattern not allowed in function without body",
1225 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1226 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1229 .struct_span_err(span, msg)
1230 .span_label(span, label)
1237 visit::walk_fn(self, fk, span);
1240 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1241 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1242 self.check_defaultness(item.span, item.kind.defaultness());
1245 if ctxt == AssocCtxt::Impl {
1247 AssocItemKind::Const(_, _, body) => {
1248 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1250 AssocItemKind::Fn(_, _, _, body) => {
1251 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1253 AssocItemKind::TyAlias(_, _, bounds, body) => {
1254 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1255 self.check_type_no_bounds(bounds, "`impl`s");
1261 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1262 self.invalid_visibility(&item.vis, None);
1263 if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
1264 self.check_trait_fn_not_const(sig.header.constness);
1265 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1269 if let AssocItemKind::Const(..) = item.kind {
1270 self.check_item_named(item.ident, "const");
1273 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1277 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1278 let mut validator = AstValidator {
1281 in_trait_impl: false,
1282 has_proc_macro_decls: false,
1283 outer_impl_trait: None,
1284 bound_context: None,
1285 is_impl_trait_banned: false,
1286 is_assoc_ty_bound_banned: false,
1289 visit::walk_crate(&mut validator, krate);
1291 validator.has_proc_macro_decls