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 fn error_foreign_const(&self, ident: Ident, span: Span) {
538 .struct_span_err(ident.span, "extern items cannot be `const`")
540 span.with_hi(ident.span.lo()),
541 "try using a static value",
542 "static ".to_string(),
543 Applicability::MachineApplicable,
545 .span_label(self.current_extern_span(), "in this `extern` block")
550 /// Reject C-varadic type unless the function is foreign,
551 /// or free and `unsafe extern "C"` semantically.
552 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
553 match (fk.ctxt(), fk.header()) {
554 (Some(FnCtxt::Foreign), _) => return,
555 (Some(FnCtxt::Free), Some(header)) => match header.ext {
556 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
557 if matches!(header.unsafety, Unsafe::Yes(_)) =>
566 for Param { ty, span, .. } in &fk.decl().inputs {
567 if let TyKind::CVarArgs = ty.kind {
571 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
578 /// We currently do not permit const generics in `const fn`,
579 /// as this is tantamount to allowing compile-time dependent typing.
581 /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
582 /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
583 fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
584 if let Const::Yes(const_span) = sig.header.constness {
585 // Look for const generics and error if we find any.
586 for param in &generics.params {
587 if let GenericParamKind::Const { .. } = param.kind {
591 "const parameters are not permitted in const functions",
593 .span_label(const_span, "`const` because of this")
600 fn check_item_named(&self, ident: Ident, kind: &str) {
601 if ident.name != kw::Underscore {
605 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
606 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
611 enum GenericPosition {
616 fn validate_generics_order<'a>(
618 handler: &rustc_errors::Handler,
619 generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
620 pos: GenericPosition,
623 let mut max_param: Option<ParamKindOrd> = None;
624 let mut out_of_order = FxHashMap::default();
625 let mut param_idents = vec![];
626 let mut found_type = false;
627 let mut found_const = false;
629 for (kind, bounds, span, ident) in generics {
630 if let Some(ident) = ident {
631 param_idents.push((kind, bounds, param_idents.len(), ident));
633 let max_param = &mut max_param;
635 Some(max_param) if *max_param > kind => {
636 let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
639 Some(_) | None => *max_param = Some(kind),
642 ParamKindOrd::Type => found_type = true,
643 ParamKindOrd::Const => found_const = true,
648 let mut ordered_params = "<".to_string();
649 if !out_of_order.is_empty() {
650 param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
651 let mut first = true;
652 for (_, bounds, _, ident) in param_idents {
654 ordered_params += ", ";
656 ordered_params += &ident;
657 if let Some(bounds) = bounds {
658 if !bounds.is_empty() {
659 ordered_params += ": ";
660 ordered_params += &pprust::bounds_to_string(&bounds);
666 ordered_params += ">";
668 let pos_str = match pos {
669 GenericPosition::Param => "parameter",
670 GenericPosition::Arg => "argument",
673 for (param_ord, (max_param, spans)) in &out_of_order {
674 let mut err = handler.struct_span_err(
677 "{} {pos}s must be declared prior to {} {pos}s",
683 if let GenericPosition::Param = pos {
687 "reorder the {}s: lifetimes, then types{}",
689 if sess.features_untracked().const_generics { ", then consts" } else { "" },
691 ordered_params.clone(),
692 Applicability::MachineApplicable,
698 // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
699 // if we don't. Const parameters and type parameters can currently conflict if they
701 if !out_of_order.is_empty() && found_type && found_const {
706 impl<'a> Visitor<'a> for AstValidator<'a> {
707 fn visit_attribute(&mut self, attr: &Attribute) {
708 validate_attr::check_meta(&self.session.parse_sess, attr);
711 fn visit_expr(&mut self, expr: &'a Expr) {
713 ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
718 "asm! is unsupported on this target"
725 visit::walk_expr(self, expr);
728 fn visit_ty(&mut self, ty: &'a Ty) {
730 TyKind::BareFn(ref bfty) => {
731 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
732 Self::check_decl_no_pat(&bfty.decl, |span, _| {
737 "patterns aren't allowed in function pointer types"
741 self.check_late_bound_lifetime_defs(&bfty.generic_params);
743 TyKind::TraitObject(ref bounds, ..) => {
744 let mut any_lifetime_bounds = false;
745 for bound in bounds {
746 if let GenericBound::Outlives(ref lifetime) = *bound {
747 if any_lifetime_bounds {
752 "only a single explicit lifetime bound is permitted"
757 any_lifetime_bounds = true;
760 self.no_questions_in_bounds(bounds, "trait object types", false);
762 TyKind::ImplTrait(_, ref bounds) => {
763 if self.is_impl_trait_banned {
768 "`impl Trait` is not allowed in path parameters"
773 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
778 "nested `impl Trait` is not allowed"
780 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
781 .span_label(ty.span, "nested `impl Trait` here")
787 .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
789 self.err_handler().span_err(ty.span, "at least one trait must be specified");
801 fn visit_label(&mut self, label: &'a Label) {
802 self.check_label(label.ident);
803 visit::walk_label(self, label);
806 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
807 self.check_lifetime(lifetime.ident);
808 visit::walk_lifetime(self, lifetime);
811 fn visit_item(&mut self, item: &'a Item) {
812 if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
813 self.has_proc_macro_decls = true;
827 self.with_in_trait_impl(true, |this| {
828 this.invalid_visibility(&item.vis, None);
829 if let TyKind::Err = self_ty.kind {
833 "`impl Trait for .. {}` is an obsolete syntax",
835 .help("use `auto trait Trait {}` instead")
838 if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
843 "negative impls cannot be unsafe"
845 .span_label(span, "unsafe because of this")
849 visit::walk_item(this, item);
851 return; // Avoid visiting again.
863 self.invalid_visibility(
865 Some("place qualifiers on individual impl items instead"),
867 if let Unsafe::Yes(span) = unsafety {
872 "inherent impls cannot be unsafe"
874 .span_label(span, "unsafe because of this")
877 if polarity == ImplPolarity::Negative {
878 self.err_handler().span_err(item.span, "inherent impls cannot be negative");
880 if defaultness == Defaultness::Default {
882 .struct_span_err(item.span, "inherent impls cannot be default")
883 .note("only trait implementations may be annotated with default")
886 if let Const::Yes(span) = constness {
888 .struct_span_err(item.span, "inherent impls cannot be `const`")
889 .span_label(span, "`const` because of this")
890 .note("only trait implementations may be annotated with `const`")
894 ItemKind::Fn(ref sig, ref generics, ref body) => {
895 self.check_const_fn_const_generic(item.span, sig, generics);
898 let msg = "free function without a body";
899 self.error_item_without_body(item.span, "function", msg, " { <body> }");
902 ItemKind::ForeignMod(_) => {
903 let old_item = mem::replace(&mut self.extern_mod, Some(item));
904 self.invalid_visibility(
906 Some("place qualifiers on individual foreign items instead"),
908 visit::walk_item(self, item);
909 self.extern_mod = old_item;
910 return; // Avoid visiting again.
912 ItemKind::Enum(ref def, _) => {
913 for variant in &def.variants {
914 self.invalid_visibility(&variant.vis, None);
915 for field in variant.data.fields() {
916 self.invalid_visibility(&field.vis, None);
920 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
921 if is_auto == IsAuto::Yes {
922 // Auto traits cannot have generics, super traits nor contain items.
923 if !generics.params.is_empty() {
928 "auto traits cannot have generic parameters"
932 if !bounds.is_empty() {
937 "auto traits cannot have super traits"
941 if !trait_items.is_empty() {
946 "auto traits cannot have methods or associated items"
951 self.no_questions_in_bounds(bounds, "supertraits", true);
953 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
954 // context for the supertraits.
955 self.visit_vis(&item.vis);
956 self.visit_ident(item.ident);
957 self.visit_generics(generics);
958 self.with_bound_context(BoundContext::TraitBounds, |this| {
959 walk_list!(this, visit_param_bound, bounds);
961 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
962 walk_list!(self, visit_attribute, &item.attrs);
965 ItemKind::Mod(_) => {
966 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
967 attr::first_attr_value_str_by_name(&item.attrs, sym::path);
969 ItemKind::Union(ref vdata, _) => {
970 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
972 .span_err(item.span, "tuple and unit unions are not permitted");
974 if vdata.fields().is_empty() {
975 self.err_handler().span_err(item.span, "unions cannot have zero fields");
978 ItemKind::Const(.., None) => {
979 let msg = "free constant item without body";
980 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
982 ItemKind::Static(.., None) => {
983 let msg = "free static item without body";
984 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
989 visit::walk_item(self, item)
992 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
994 ForeignItemKind::Fn(sig, _, body) => {
995 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
996 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
998 ForeignItemKind::TyAlias(generics, bounds, body) => {
999 self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
1000 self.check_type_no_bounds(bounds, "`extern` blocks");
1001 self.check_foreign_ty_genericless(generics);
1003 ForeignItemKind::Static(_, _, body) => {
1004 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1006 ForeignItemKind::Const(..) => {
1007 self.error_foreign_const(fi.ident, fi.span);
1009 ForeignItemKind::Macro(..) => {}
1012 visit::walk_foreign_item(self, fi)
1015 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1016 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1017 match *generic_args {
1018 GenericArgs::AngleBracketed(ref data) => {
1019 walk_list!(self, visit_generic_arg, &data.args);
1020 validate_generics_order(
1023 data.args.iter().map(|arg| {
1026 GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
1027 GenericArg::Type(..) => ParamKindOrd::Type,
1028 GenericArg::Const(..) => ParamKindOrd::Const,
1035 GenericPosition::Arg,
1036 generic_args.span(),
1039 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1040 // are allowed to contain nested `impl Trait`.
1041 self.with_impl_trait(None, |this| {
1044 visit_assoc_ty_constraint_from_generic_args,
1049 GenericArgs::Parenthesized(ref data) => {
1050 walk_list!(self, visit_ty, &data.inputs);
1051 if let FunctionRetTy::Ty(ty) = &data.output {
1052 // `-> Foo` syntax is essentially an associated type binding,
1053 // so it is also allowed to contain nested `impl Trait`.
1054 self.with_impl_trait(None, |this| this.visit_ty(ty));
1060 fn visit_generics(&mut self, generics: &'a Generics) {
1061 let mut prev_ty_default = None;
1062 for param in &generics.params {
1063 if let GenericParamKind::Type { ref default, .. } = param.kind {
1064 if default.is_some() {
1065 prev_ty_default = Some(param.ident.span);
1066 } else if let Some(span) = prev_ty_default {
1068 .span_err(span, "type parameters with a default must be trailing");
1074 validate_generics_order(
1077 generics.params.iter().map(|param| {
1078 let ident = Some(param.ident.to_string());
1079 let (kind, ident) = match ¶m.kind {
1080 GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
1081 GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
1082 GenericParamKind::Const { ref ty } => {
1083 let ty = pprust::ty_to_string(ty);
1084 (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
1087 (kind, Some(&*param.bounds), param.ident.span, ident)
1089 GenericPosition::Param,
1093 for predicate in &generics.where_clause.predicates {
1094 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1098 "equality constraints are not yet supported in `where` clauses",
1100 .span_label(predicate.span, "not supported")
1102 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1103 for more information",
1109 visit::walk_generics(self, generics)
1112 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1113 if let GenericParamKind::Lifetime { .. } = param.kind {
1114 self.check_lifetime(param.ident);
1116 visit::walk_generic_param(self, param);
1119 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1121 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1122 if let Some(ctx) = self.bound_context {
1123 let msg = format!("`?const` is not permitted in {}", ctx.description());
1124 self.err_handler().span_err(bound.span(), &msg);
1128 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1130 .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1136 visit::walk_param_bound(self, bound)
1139 fn visit_pat(&mut self, pat: &'a Pat) {
1141 PatKind::Lit(ref expr) => {
1142 self.check_expr_within_pat(expr, false);
1144 PatKind::Range(ref start, ref end, _) => {
1145 if let Some(expr) = start {
1146 self.check_expr_within_pat(expr, true);
1148 if let Some(expr) = end {
1149 self.check_expr_within_pat(expr, true);
1155 visit::walk_pat(self, pat)
1158 fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
1159 if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
1160 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1161 self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
1163 visit::walk_where_predicate(self, p);
1166 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1167 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1168 visit::walk_poly_trait_ref(self, t, m);
1171 fn visit_variant_data(&mut self, s: &'a VariantData) {
1172 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1177 enum_definition: &'a EnumDef,
1178 generics: &'a Generics,
1182 self.with_banned_assoc_ty_bound(|this| {
1183 visit::walk_enum_def(this, enum_definition, generics, item_id)
1187 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1188 // Only associated `fn`s can have `self` parameters.
1189 let self_semantic = match fk.ctxt() {
1190 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1191 _ => SelfSemantic::No,
1193 self.check_fn_decl(fk.decl(), self_semantic);
1195 self.check_c_varadic_type(fk);
1197 // Functions cannot both be `const async`
1198 if let Some(FnHeader {
1199 constness: Const::Yes(cspan),
1200 asyncness: Async::Yes { span: aspan, .. },
1205 .struct_span_err(span, "functions cannot be both `const` and `async`")
1206 .span_label(*cspan, "`const` because of this")
1207 .span_label(*aspan, "`async` because of this")
1211 // Functions without bodies cannot have patterns.
1212 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1213 Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
1214 let (code, msg, label) = match ctxt {
1215 FnCtxt::Foreign => (
1217 "patterns aren't allowed in foreign function declarations",
1218 "pattern not allowed in foreign function",
1222 "patterns aren't allowed in functions without bodies",
1223 "pattern not allowed in function without body",
1226 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1227 self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
1230 .struct_span_err(span, msg)
1231 .span_label(span, label)
1238 visit::walk_fn(self, fk, span);
1241 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1242 if ctxt == AssocCtxt::Trait {
1243 self.check_defaultness(item.span, item.defaultness);
1246 if ctxt == AssocCtxt::Impl {
1248 AssocItemKind::Const(_, body) => {
1249 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1251 AssocItemKind::Fn(_, _, body) => {
1252 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1254 AssocItemKind::TyAlias(_, bounds, body) => {
1255 self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1256 self.check_type_no_bounds(bounds, "`impl`s");
1262 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1263 self.invalid_visibility(&item.vis, None);
1264 if let AssocItemKind::Fn(sig, _, _) = &item.kind {
1265 self.check_trait_fn_not_const(sig.header.constness);
1266 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1271 AssocItemKind::Const(..) => self.check_item_named(item.ident, "const"),
1272 AssocItemKind::Static(..) => self
1274 .struct_span_err(item.span, "associated `static` items are not allowed")
1279 self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1283 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1284 let mut validator = AstValidator {
1287 in_trait_impl: false,
1288 has_proc_macro_decls: false,
1289 outer_impl_trait: None,
1290 bound_context: None,
1291 is_impl_trait_banned: false,
1292 is_assoc_ty_bound_banned: false,
1295 visit::walk_crate(&mut validator, krate);
1297 validator.has_proc_macro_decls