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 itertools
::{Either, Itertools}
;
10 use rustc_ast
::ptr
::P
;
11 use rustc_ast
::visit
::{self, AssocCtxt, FnCtxt, FnKind, Visitor}
;
12 use rustc_ast
::walk_list
;
14 use rustc_ast_pretty
::pprust
;
15 use rustc_data_structures
::fx
::FxHashMap
;
16 use rustc_errors
::{error_code, pluralize, struct_span_err, Applicability}
;
17 use rustc_parse
::validate_attr
;
18 use rustc_session
::lint
::builtin
::PATTERNS_IN_FNS_WITHOUT_BODY
;
19 use rustc_session
::lint
::LintBuffer
;
20 use rustc_session
::Session
;
21 use rustc_span
::symbol
::{kw, sym, Ident}
;
24 use std
::ops
::DerefMut
;
26 const MORE_EXTERN
: &str =
27 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
29 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
35 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
36 #[derive(Clone, Copy)]
44 fn description(&self) -> &'
static str {
46 Self::ImplTrait
=> "`impl Trait`",
47 Self::TraitBounds
=> "supertraits",
48 Self::TraitObject
=> "trait objects",
53 struct AstValidator
<'a
> {
56 /// The span of the `extern` in an `extern { ... }` block, if any.
57 extern_mod
: Option
<&'a Item
>,
59 /// Are we inside a trait impl?
62 has_proc_macro_decls
: bool
,
64 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
65 /// Nested `impl Trait` _is_ allowed in associated type position,
66 /// e.g., `impl Iterator<Item = impl Debug>`.
67 outer_impl_trait
: Option
<Span
>,
69 /// Keeps track of the `BoundContext` as we recurse.
71 /// This is used to forbid `?const Trait` bounds in, e.g.,
72 /// `impl Iterator<Item = Box<dyn ?const Trait>`.
73 bound_context
: Option
<BoundContext
>,
75 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
76 /// or `Foo::Bar<impl Trait>`
77 is_impl_trait_banned
: bool
,
79 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
80 /// certain positions.
81 is_assoc_ty_bound_banned
: bool
,
83 lint_buffer
: &'a
mut LintBuffer
,
86 impl<'a
> AstValidator
<'a
> {
87 fn with_in_trait_impl(&mut self, is_in
: bool
, f
: impl FnOnce(&mut Self)) {
88 let old
= mem
::replace(&mut self.in_trait_impl
, is_in
);
90 self.in_trait_impl
= old
;
93 fn with_banned_impl_trait(&mut self, f
: impl FnOnce(&mut Self)) {
94 let old
= mem
::replace(&mut self.is_impl_trait_banned
, true);
96 self.is_impl_trait_banned
= old
;
99 fn with_banned_assoc_ty_bound(&mut self, f
: impl FnOnce(&mut Self)) {
100 let old
= mem
::replace(&mut self.is_assoc_ty_bound_banned
, true);
102 self.is_assoc_ty_bound_banned
= old
;
105 fn with_impl_trait(&mut self, outer
: Option
<Span
>, f
: impl FnOnce(&mut Self)) {
106 let old
= mem
::replace(&mut self.outer_impl_trait
, outer
);
108 self.with_bound_context(BoundContext
::ImplTrait
, |this
| f(this
));
112 self.outer_impl_trait
= old
;
115 fn with_bound_context(&mut self, ctx
: BoundContext
, f
: impl FnOnce(&mut Self)) {
116 let old
= self.bound_context
.replace(ctx
);
118 self.bound_context
= old
;
121 fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint
: &'a AssocTyConstraint
) {
122 match constraint
.kind
{
123 AssocTyConstraintKind
::Equality { .. }
=> {}
124 AssocTyConstraintKind
::Bound { .. }
=> {
125 if self.is_assoc_ty_bound_banned
{
126 self.err_handler().span_err(
128 "associated type bounds are not allowed within structs, enums, or unions",
133 self.visit_assoc_ty_constraint(constraint
);
136 // Mirrors `visit::walk_ty`, but tracks relevant state.
137 fn walk_ty(&mut self, t
: &'a Ty
) {
139 TyKind
::ImplTrait(..) => {
140 self.with_impl_trait(Some(t
.span
), |this
| visit
::walk_ty(this
, t
))
142 TyKind
::TraitObject(..) => {
143 self.with_bound_context(BoundContext
::TraitObject
, |this
| visit
::walk_ty(this
, t
));
145 TyKind
::Path(ref qself
, ref path
) => {
147 // - `Option<impl Trait>`
148 // - `option::Option<impl Trait>`
149 // - `option::Option<T>::Foo<impl Trait>
152 // - `<impl Trait>::Foo`
153 // - `option::Option<impl Trait>::Foo`.
155 // To implement this, we disallow `impl Trait` from `qself`
156 // (for cases like `<impl Trait>::Foo>`)
157 // but we allow `impl Trait` in `GenericArgs`
158 // iff there are no more PathSegments.
159 if let Some(ref qself
) = *qself
{
160 // `impl Trait` in `qself` is always illegal
161 self.with_banned_impl_trait(|this
| this
.visit_ty(&qself
.ty
));
164 // Note that there should be a call to visit_path here,
165 // so if any logic is added to process `Path`s a call to it should be
166 // added both in visit_path and here. This code mirrors visit::walk_path.
167 for (i
, segment
) in path
.segments
.iter().enumerate() {
168 // Allow `impl Trait` iff we're on the final path segment
169 if i
== path
.segments
.len() - 1 {
170 self.visit_path_segment(path
.span
, segment
);
172 self.with_banned_impl_trait(|this
| {
173 this
.visit_path_segment(path
.span
, segment
)
178 _
=> visit
::walk_ty(self, t
),
182 fn err_handler(&self) -> &rustc_errors
::Handler
{
183 &self.session
.diagnostic()
186 fn check_lifetime(&self, ident
: Ident
) {
187 let valid_names
= [kw
::UnderscoreLifetime
, kw
::StaticLifetime
, kw
::Invalid
];
188 if !valid_names
.contains(&ident
.name
) && ident
.without_first_quote().is_reserved() {
189 self.err_handler().span_err(ident
.span
, "lifetimes cannot use keyword names");
193 fn check_label(&self, ident
: Ident
) {
194 if ident
.without_first_quote().is_reserved() {
196 .span_err(ident
.span
, &format
!("invalid label name `{}`", ident
.name
));
200 fn invalid_visibility(&self, vis
: &Visibility
, note
: Option
<&str>) {
201 if let VisibilityKind
::Inherited
= vis
.kind
{
206 struct_span_err
!(self.session
, vis
.span
, E0449
, "unnecessary visibility qualifier");
207 if vis
.kind
.is_pub() {
208 err
.span_label(vis
.span
, "`pub` not permitted here because it's implied");
210 if let Some(note
) = note
{
216 fn check_decl_no_pat(decl
: &FnDecl
, mut report_err
: impl FnMut(Span
, bool
)) {
217 for Param { pat, .. }
in &decl
.inputs
{
219 PatKind
::Ident(BindingMode
::ByValue(Mutability
::Not
), _
, None
) | PatKind
::Wild
=> {}
220 PatKind
::Ident(BindingMode
::ByValue(Mutability
::Mut
), _
, None
) => {
221 report_err(pat
.span
, true)
223 _
=> report_err(pat
.span
, false),
228 fn check_trait_fn_not_async(&self, fn_span
: Span
, asyncness
: Async
) {
229 if let Async
::Yes { span, .. }
= asyncness
{
234 "functions in traits cannot be declared `async`"
236 .span_label(span
, "`async` because of this")
237 .note("`async` trait functions are not currently supported")
238 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
243 fn check_trait_fn_not_const(&self, constness
: Const
) {
244 if let Const
::Yes(span
) = constness
{
249 "functions in traits cannot be declared const"
251 .span_label(span
, "functions in traits cannot be const")
256 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
257 fn no_questions_in_bounds(&self, bounds
: &GenericBounds
, where_
: &str, is_trait
: bool
) {
258 for bound
in bounds
{
259 if let GenericBound
::Trait(ref poly
, TraitBoundModifier
::Maybe
) = *bound
{
260 let mut err
= self.err_handler().struct_span_err(
262 &format
!("`?Trait` is not permitted in {}", where_
),
265 let path_str
= pprust
::path_to_string(&poly
.trait_ref
.path
);
266 err
.note(&format
!("traits are `?{}` by default", path_str
));
273 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
274 /// or paths for ranges.
276 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
277 // That means making this work:
279 // ```rust,ignore (FIXME)
288 fn check_expr_within_pat(&self, expr
: &Expr
, allow_paths
: bool
) {
290 ExprKind
::Lit(..) | ExprKind
::ConstBlock(..) | ExprKind
::Err
=> {}
291 ExprKind
::Path(..) if allow_paths
=> {}
292 ExprKind
::Unary(UnOp
::Neg
, ref inner
) if matches
!(inner
.kind
, ExprKind
::Lit(_
)) => {}
293 _
=> self.err_handler().span_err(
295 "arbitrary expressions aren't allowed \
301 fn check_late_bound_lifetime_defs(&self, params
: &[GenericParam
]) {
302 // Check only lifetime parameters are present and that the lifetime
303 // parameters that are present have no bounds.
304 let non_lt_param_spans
: Vec
<_
> = params
306 .filter_map(|param
| match param
.kind
{
307 GenericParamKind
::Lifetime { .. }
=> {
308 if !param
.bounds
.is_empty() {
309 let spans
: Vec
<_
> = param
.bounds
.iter().map(|b
| b
.span()).collect();
311 .span_err(spans
, "lifetime bounds cannot be used in this context");
315 _
=> Some(param
.ident
.span
),
318 if !non_lt_param_spans
.is_empty() {
319 self.err_handler().span_err(
321 "only lifetime parameters can be used in this context",
326 fn check_fn_decl(&self, fn_decl
: &FnDecl
, self_semantic
: SelfSemantic
) {
327 self.check_decl_cvaradic_pos(fn_decl
);
328 self.check_decl_attrs(fn_decl
);
329 self.check_decl_self_param(fn_decl
, self_semantic
);
332 fn check_decl_cvaradic_pos(&self, fn_decl
: &FnDecl
) {
333 match &*fn_decl
.inputs
{
334 [Param { ty, span, .. }
] => {
335 if let TyKind
::CVarArgs
= ty
.kind
{
336 self.err_handler().span_err(
338 "C-variadic function must be declared with at least one named argument",
343 for Param { ty, span, .. }
in ps
{
344 if let TyKind
::CVarArgs
= ty
.kind
{
345 self.err_handler().span_err(
347 "`...` must be the last argument of a C-variadic function",
356 fn check_decl_attrs(&self, fn_decl
: &FnDecl
) {
360 .flat_map(|i
| i
.attrs
.as_ref())
362 let arr
= [sym
::allow
, sym
::cfg
, sym
::cfg_attr
, sym
::deny
, sym
::forbid
, sym
::warn
];
363 !arr
.contains(&attr
.name_or_empty()) && rustc_attr
::is_builtin_attr(attr
)
366 if attr
.is_doc_comment() {
370 "documentation comments cannot be applied to function parameters",
372 .span_label(attr
.span
, "doc comments are not allowed here")
375 self.err_handler().span_err(
377 "allow, cfg, cfg_attr, deny, \
378 forbid, and warn are the only allowed built-in attributes in function parameters",
384 fn check_decl_self_param(&self, fn_decl
: &FnDecl
, self_semantic
: SelfSemantic
) {
385 if let (SelfSemantic
::No
, [param
, ..]) = (self_semantic
, &*fn_decl
.inputs
) {
390 "`self` parameter is only allowed in associated functions",
392 .span_label(param
.span
, "not semantically valid as function parameter")
393 .note("associated functions are those in `impl` or `trait` definitions")
399 fn check_defaultness(&self, span
: Span
, defaultness
: Defaultness
) {
400 if let Defaultness
::Default(def_span
) = defaultness
{
401 let span
= self.session
.source_map().guess_head_span(span
);
403 .struct_span_err(span
, "`default` is only allowed on items in trait impls")
404 .span_label(def_span
, "`default` because of this")
409 fn error_item_without_body(&self, sp
: Span
, ctx
: &str, msg
: &str, sugg
: &str) {
411 .struct_span_err(sp
, msg
)
413 self.session
.source_map().end_point(sp
),
414 &format
!("provide a definition for the {}", ctx
),
416 Applicability
::HasPlaceholders
,
421 fn check_impl_item_provided
<T
>(&self, sp
: Span
, body
: &Option
<T
>, ctx
: &str, sugg
: &str) {
423 let msg
= format
!("associated {} in `impl` without body", ctx
);
424 self.error_item_without_body(sp
, ctx
, &msg
, sugg
);
428 fn check_type_no_bounds(&self, bounds
: &[GenericBound
], ctx
: &str) {
429 let span
= match bounds
{
432 [b0
, .., bl
] => b0
.span().to(bl
.span()),
435 .struct_span_err(span
, &format
!("bounds on `type`s in {} have no effect", ctx
))
439 fn check_foreign_ty_genericless(&self, generics
: &Generics
) {
440 let cannot_have
= |span
, descr
, remove_descr
| {
444 &format
!("`type`s inside `extern` blocks cannot have {}", descr
),
448 &format
!("remove the {}", remove_descr
),
450 Applicability
::MaybeIncorrect
,
452 .span_label(self.current_extern_span(), "`extern` block begins here")
457 if !generics
.params
.is_empty() {
458 cannot_have(generics
.span
, "generic parameters", "generic parameters");
461 if !generics
.where_clause
.predicates
.is_empty() {
462 cannot_have(generics
.where_clause
.span
, "`where` clauses", "`where` clause");
466 fn check_foreign_kind_bodyless(&self, ident
: Ident
, kind
: &str, body
: Option
<Span
>) {
467 let body
= match body
{
472 .struct_span_err(ident
.span
, &format
!("incorrect `{}` inside `extern` block", kind
))
473 .span_label(ident
.span
, "cannot have a body")
474 .span_label(body
, "the invalid body")
476 self.current_extern_span(),
478 "`extern` blocks define existing foreign {0}s and {0}s \
479 inside of them cannot have a body",
487 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
488 fn check_foreign_fn_bodyless(&self, ident
: Ident
, body
: Option
<&Block
>) {
489 let body
= match body
{
494 .struct_span_err(ident
.span
, "incorrect function inside `extern` block")
495 .span_label(ident
.span
, "cannot have a body")
498 "remove the invalid body",
500 Applicability
::MaybeIncorrect
,
503 "you might have meant to write a function accessible through FFI, \
504 which can be done by writing `extern fn` outside of the `extern` block",
507 self.current_extern_span(),
508 "`extern` blocks define existing foreign functions and functions \
509 inside of them cannot have a body",
515 fn current_extern_span(&self) -> Span
{
516 self.session
.source_map().guess_head_span(self.extern_mod
.unwrap().span
)
519 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
520 fn check_foreign_fn_headerless(&self, ident
: Ident
, span
: Span
, header
: FnHeader
) {
521 if header
.has_qualifiers() {
523 .struct_span_err(ident
.span
, "functions in `extern` blocks cannot have qualifiers")
524 .span_label(self.current_extern_span(), "in this `extern` block")
525 .span_suggestion_verbose(
526 span
.until(ident
.span
.shrink_to_lo()),
527 "remove the qualifiers",
529 Applicability
::MaybeIncorrect
,
535 /// Reject C-varadic type unless the function is foreign,
536 /// or free and `unsafe extern "C"` semantically.
537 fn check_c_varadic_type(&self, fk
: FnKind
<'a
>) {
538 match (fk
.ctxt(), fk
.header()) {
539 (Some(FnCtxt
::Foreign
), _
) => return,
540 (Some(FnCtxt
::Free
), Some(header
)) => match header
.ext
{
541 Extern
::Explicit(StrLit { symbol_unescaped: sym::C, .. }
) | Extern
::Implicit
542 if matches
!(header
.unsafety
, Unsafe
::Yes(_
)) =>
551 for Param { ty, span, .. }
in &fk
.decl().inputs
{
552 if let TyKind
::CVarArgs
= ty
.kind
{
556 "only foreign or `unsafe extern \"C\" functions may be C-variadic",
563 fn check_item_named(&self, ident
: Ident
, kind
: &str) {
564 if ident
.name
!= kw
::Underscore
{
568 .struct_span_err(ident
.span
, &format
!("`{}` items in this context need a name", kind
))
569 .span_label(ident
.span
, format
!("`_` is not a valid name for this `{}` item", kind
))
573 fn check_nomangle_item_asciionly(&self, ident
: Ident
, item_span
: Span
) {
574 if ident
.name
.as_str().is_ascii() {
577 let head_span
= self.session
.source_map().guess_head_span(item_span
);
582 "`#[no_mangle]` requires ASCII identifier"
587 fn check_mod_file_item_asciionly(&self, ident
: Ident
) {
588 if ident
.name
.as_str().is_ascii() {
595 "trying to load file for module `{}` with non ascii identifer name",
598 .help("consider using `#[path]` attribute to specify filesystem path")
602 fn deny_generic_params(&self, generics
: &Generics
, ident_span
: Span
) {
603 if !generics
.params
.is_empty() {
608 "auto traits cannot have generic parameters"
610 .span_label(ident_span
, "auto trait cannot have generic parameters")
613 "remove the parameters",
615 Applicability
::MachineApplicable
,
621 fn deny_super_traits(&self, bounds
: &GenericBounds
, ident_span
: Span
) {
622 if let [first @ last
] | [first
, .., last
] = &bounds
[..] {
623 let span
= first
.span().to(last
.span());
624 struct_span_err
!(self.session
, span
, E0568
, "auto traits cannot have super traits")
625 .span_label(ident_span
, "auto trait cannot have super traits")
628 "remove the super traits",
630 Applicability
::MachineApplicable
,
636 fn deny_items(&self, trait_items
: &[P
<AssocItem
>], ident_span
: Span
) {
637 if !trait_items
.is_empty() {
638 let spans
: Vec
<_
> = trait_items
.iter().map(|i
| i
.ident
.span
).collect();
643 "auto traits cannot have methods or associated items"
645 .span_label(ident_span
, "auto trait cannot have items")
650 fn correct_generic_order_suggestion(&self, data
: &AngleBracketedArgs
) -> String
{
651 // Lifetimes always come first.
652 let lt_sugg
= data
.args
.iter().filter_map(|arg
| match arg
{
653 AngleBracketedArg
::Arg(lt @ GenericArg
::Lifetime(_
)) => {
654 Some(pprust
::to_string(|s
| s
.print_generic_arg(lt
)))
658 let args_sugg
= data
.args
.iter().filter_map(|a
| match a
{
659 AngleBracketedArg
::Arg(GenericArg
::Lifetime(_
)) | AngleBracketedArg
::Constraint(_
) => {
662 AngleBracketedArg
::Arg(arg
) => Some(pprust
::to_string(|s
| s
.print_generic_arg(arg
))),
664 // Constraints always come last.
665 let constraint_sugg
= data
.args
.iter().filter_map(|a
| match a
{
666 AngleBracketedArg
::Arg(_
) => None
,
667 AngleBracketedArg
::Constraint(c
) => {
668 Some(pprust
::to_string(|s
| s
.print_assoc_constraint(c
)))
673 lt_sugg
.chain(args_sugg
).chain(constraint_sugg
).collect
::<Vec
<String
>>().join(", ")
677 /// Enforce generic args coming before constraints in `<...>` of a path segment.
678 fn check_generic_args_before_constraints(&self, data
: &AngleBracketedArgs
) {
679 // Early exit in case it's partitioned as it should be.
680 if data
.args
.iter().is_partitioned(|arg
| matches
!(arg
, AngleBracketedArg
::Arg(_
))) {
683 // Find all generic argument coming after the first constraint...
684 let (constraint_spans
, arg_spans
): (Vec
<Span
>, Vec
<Span
>) =
685 data
.args
.iter().partition_map(|arg
| match arg
{
686 AngleBracketedArg
::Constraint(c
) => Either
::Left(c
.span
),
687 AngleBracketedArg
::Arg(a
) => Either
::Right(a
.span()),
689 let args_len
= arg_spans
.len();
690 let constraint_len
= constraint_spans
.len();
691 // ...and then error:
695 "generic arguments must come before the first constraint",
697 .span_label(constraint_spans
[0], &format
!("constraint{}", pluralize
!(constraint_len
)))
699 *arg_spans
.iter().last().unwrap(),
700 &format
!("generic argument{}", pluralize
!(args_len
)),
702 .span_labels(constraint_spans
, "")
703 .span_labels(arg_spans
, "")
704 .span_suggestion_verbose(
707 "move the constraint{} after the generic argument{}",
708 pluralize
!(constraint_len
),
711 self.correct_generic_order_suggestion(&data
),
712 Applicability
::MachineApplicable
,
718 /// Checks that generic parameters are in the correct order,
719 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
720 fn validate_generic_param_order
<'a
>(
722 handler
: &rustc_errors
::Handler
,
723 generics
: impl Iterator
<Item
= (ParamKindOrd
, Option
<&'a
[GenericBound
]>, Span
, Option
<String
>)>,
726 let mut max_param
: Option
<ParamKindOrd
> = None
;
727 let mut out_of_order
= FxHashMap
::default();
728 let mut param_idents
= vec
![];
730 for (kind
, bounds
, span
, ident
) in generics
{
731 if let Some(ident
) = ident
{
732 param_idents
.push((kind
, bounds
, param_idents
.len(), ident
));
734 let max_param
= &mut max_param
;
736 Some(max_param
) if *max_param
> kind
=> {
737 let entry
= out_of_order
.entry(kind
).or_insert((*max_param
, vec
![]));
740 Some(_
) | None
=> *max_param
= Some(kind
),
744 let mut ordered_params
= "<".to_string();
745 if !out_of_order
.is_empty() {
746 param_idents
.sort_by_key(|&(po
, _
, i
, _
)| (po
, i
));
747 let mut first
= true;
748 for (_
, bounds
, _
, ident
) in param_idents
{
750 ordered_params
+= ", ";
752 ordered_params
+= &ident
;
753 if let Some(bounds
) = bounds
{
754 if !bounds
.is_empty() {
755 ordered_params
+= ": ";
756 ordered_params
+= &pprust
::bounds_to_string(&bounds
);
762 ordered_params
+= ">";
764 for (param_ord
, (max_param
, spans
)) in &out_of_order
{
766 handler
.struct_span_err(
769 "{} parameters must be declared prior to {} parameters",
770 param_ord
, max_param
,
776 "reorder the parameters: lifetimes{}",
777 if sess
.features_untracked().const_generics
{
778 ", then consts and types"
779 } else if sess
.features_untracked().min_const_generics
{
780 ", then types, then consts"
785 ordered_params
.clone(),
786 Applicability
::MachineApplicable
,
792 impl<'a
> Visitor
<'a
> for AstValidator
<'a
> {
793 fn visit_attribute(&mut self, attr
: &Attribute
) {
794 validate_attr
::check_meta(&self.session
.parse_sess
, attr
);
797 fn visit_expr(&mut self, expr
: &'a Expr
) {
799 ExprKind
::LlvmInlineAsm(..) if !self.session
.target
.allow_asm
=> {
804 "llvm_asm! is unsupported on this target"
811 visit
::walk_expr(self, expr
);
814 fn visit_ty(&mut self, ty
: &'a Ty
) {
816 TyKind
::BareFn(ref bfty
) => {
817 self.check_fn_decl(&bfty
.decl
, SelfSemantic
::No
);
818 Self::check_decl_no_pat(&bfty
.decl
, |span
, _
| {
823 "patterns aren't allowed in function pointer types"
827 self.check_late_bound_lifetime_defs(&bfty
.generic_params
);
829 TyKind
::TraitObject(ref bounds
, ..) => {
830 let mut any_lifetime_bounds
= false;
831 for bound
in bounds
{
832 if let GenericBound
::Outlives(ref lifetime
) = *bound
{
833 if any_lifetime_bounds
{
838 "only a single explicit lifetime bound is permitted"
843 any_lifetime_bounds
= true;
846 self.no_questions_in_bounds(bounds
, "trait object types", false);
848 TyKind
::ImplTrait(_
, ref bounds
) => {
849 if self.is_impl_trait_banned
{
854 "`impl Trait` is not allowed in path parameters"
859 if let Some(outer_impl_trait_sp
) = self.outer_impl_trait
{
864 "nested `impl Trait` is not allowed"
866 .span_label(outer_impl_trait_sp
, "outer `impl Trait`")
867 .span_label(ty
.span
, "nested `impl Trait` here")
871 if !bounds
.iter().any(|b
| matches
!(b
, GenericBound
::Trait(..))) {
872 self.err_handler().span_err(ty
.span
, "at least one trait must be specified");
884 fn visit_label(&mut self, label
: &'a Label
) {
885 self.check_label(label
.ident
);
886 visit
::walk_label(self, label
);
889 fn visit_lifetime(&mut self, lifetime
: &'a Lifetime
) {
890 self.check_lifetime(lifetime
.ident
);
891 visit
::walk_lifetime(self, lifetime
);
894 fn visit_item(&mut self, item
: &'a Item
) {
895 if item
.attrs
.iter().any(|attr
| self.session
.is_proc_macro_attr(attr
)) {
896 self.has_proc_macro_decls
= true;
899 if self.session
.contains_name(&item
.attrs
, sym
::no_mangle
) {
900 self.check_nomangle_item_asciionly(item
.ident
, item
.span
);
910 of_trait
: Some(ref t
),
914 self.with_in_trait_impl(true, |this
| {
915 this
.invalid_visibility(&item
.vis
, None
);
916 if let TyKind
::Err
= self_ty
.kind
{
920 "`impl Trait for .. {}` is an obsolete syntax",
922 .help("use `auto trait Trait {}` instead")
925 if let (Unsafe
::Yes(span
), ImplPolarity
::Negative(sp
)) = (unsafety
, polarity
) {
930 "negative impls cannot be unsafe"
932 .span_label(sp
, "negative because of this")
933 .span_label(span
, "unsafe because of this")
937 visit
::walk_item(this
, item
);
939 return; // Avoid visiting again.
951 let error
= |annotation_span
, annotation
| {
952 let mut err
= self.err_handler().struct_span_err(
954 &format
!("inherent impls cannot be {}", annotation
),
956 err
.span_label(annotation_span
, &format
!("{} because of this", annotation
));
957 err
.span_label(self_ty
.span
, "inherent impl for this type");
961 self.invalid_visibility(
963 Some("place qualifiers on individual impl items instead"),
965 if let Unsafe
::Yes(span
) = unsafety
{
966 error(span
, "unsafe").code(error_code
!(E0197
)).emit();
968 if let ImplPolarity
::Negative(span
) = polarity
{
969 error(span
, "negative").emit();
971 if let Defaultness
::Default(def_span
) = defaultness
{
972 error(def_span
, "`default`")
973 .note("only trait implementations may be annotated with `default`")
976 if let Const
::Yes(span
) = constness
{
977 error(span
, "`const`")
978 .note("only trait implementations may be annotated with `const`")
982 ItemKind
::Fn(def
, _
, _
, ref body
) => {
983 self.check_defaultness(item
.span
, def
);
986 let msg
= "free function without a body";
987 self.error_item_without_body(item
.span
, "function", msg
, " { <body> }");
990 ItemKind
::ForeignMod(ForeignMod { unsafety, .. }
) => {
991 let old_item
= mem
::replace(&mut self.extern_mod
, Some(item
));
992 self.invalid_visibility(
994 Some("place qualifiers on individual foreign items instead"),
996 if let Unsafe
::Yes(span
) = unsafety
{
997 self.err_handler().span_err(span
, "extern block cannot be declared unsafe");
999 visit
::walk_item(self, item
);
1000 self.extern_mod
= old_item
;
1001 return; // Avoid visiting again.
1003 ItemKind
::Enum(ref def
, _
) => {
1004 for variant
in &def
.variants
{
1005 self.invalid_visibility(&variant
.vis
, None
);
1006 for field
in variant
.data
.fields() {
1007 self.invalid_visibility(&field
.vis
, None
);
1011 ItemKind
::Trait(is_auto
, _
, ref generics
, ref bounds
, ref trait_items
) => {
1012 if is_auto
== IsAuto
::Yes
{
1013 // Auto traits cannot have generics, super traits nor contain items.
1014 self.deny_generic_params(generics
, item
.ident
.span
);
1015 self.deny_super_traits(bounds
, item
.ident
.span
);
1016 self.deny_items(trait_items
, item
.ident
.span
);
1018 self.no_questions_in_bounds(bounds
, "supertraits", true);
1020 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1021 // context for the supertraits.
1022 self.visit_vis(&item
.vis
);
1023 self.visit_ident(item
.ident
);
1024 self.visit_generics(generics
);
1025 self.with_bound_context(BoundContext
::TraitBounds
, |this
| {
1026 walk_list
!(this
, visit_param_bound
, bounds
);
1028 walk_list
!(self, visit_assoc_item
, trait_items
, AssocCtxt
::Trait
);
1029 walk_list
!(self, visit_attribute
, &item
.attrs
);
1032 ItemKind
::Mod(Mod { inline, unsafety, .. }
) => {
1033 if let Unsafe
::Yes(span
) = unsafety
{
1034 self.err_handler().span_err(span
, "module cannot be declared unsafe");
1036 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1037 if !inline
&& !self.session
.contains_name(&item
.attrs
, sym
::path
) {
1038 self.check_mod_file_item_asciionly(item
.ident
);
1041 ItemKind
::Union(ref vdata
, _
) => {
1042 if let VariantData
::Tuple(..) | VariantData
::Unit(..) = vdata
{
1044 .span_err(item
.span
, "tuple and unit unions are not permitted");
1046 if vdata
.fields().is_empty() {
1047 self.err_handler().span_err(item
.span
, "unions cannot have zero fields");
1050 ItemKind
::Const(def
, .., None
) => {
1051 self.check_defaultness(item
.span
, def
);
1052 let msg
= "free constant item without body";
1053 self.error_item_without_body(item
.span
, "constant", msg
, " = <expr>;");
1055 ItemKind
::Static(.., None
) => {
1056 let msg
= "free static item without body";
1057 self.error_item_without_body(item
.span
, "static", msg
, " = <expr>;");
1059 ItemKind
::TyAlias(def
, _
, ref bounds
, ref body
) => {
1060 self.check_defaultness(item
.span
, def
);
1062 let msg
= "free type alias without body";
1063 self.error_item_without_body(item
.span
, "type", msg
, " = <type>;");
1065 self.check_type_no_bounds(bounds
, "this context");
1070 visit
::walk_item(self, item
)
1073 fn visit_foreign_item(&mut self, fi
: &'a ForeignItem
) {
1075 ForeignItemKind
::Fn(def
, sig
, _
, body
) => {
1076 self.check_defaultness(fi
.span
, *def
);
1077 self.check_foreign_fn_bodyless(fi
.ident
, body
.as_deref());
1078 self.check_foreign_fn_headerless(fi
.ident
, fi
.span
, sig
.header
);
1080 ForeignItemKind
::TyAlias(def
, generics
, bounds
, body
) => {
1081 self.check_defaultness(fi
.span
, *def
);
1082 self.check_foreign_kind_bodyless(fi
.ident
, "type", body
.as_ref().map(|b
| b
.span
));
1083 self.check_type_no_bounds(bounds
, "`extern` blocks");
1084 self.check_foreign_ty_genericless(generics
);
1086 ForeignItemKind
::Static(_
, _
, body
) => {
1087 self.check_foreign_kind_bodyless(fi
.ident
, "static", body
.as_ref().map(|b
| b
.span
));
1089 ForeignItemKind
::MacCall(..) => {}
1092 visit
::walk_foreign_item(self, fi
)
1095 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1096 fn visit_generic_args(&mut self, _
: Span
, generic_args
: &'a GenericArgs
) {
1097 match *generic_args
{
1098 GenericArgs
::AngleBracketed(ref data
) => {
1099 self.check_generic_args_before_constraints(data
);
1101 for arg
in &data
.args
{
1103 AngleBracketedArg
::Arg(arg
) => self.visit_generic_arg(arg
),
1104 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1105 // are allowed to contain nested `impl Trait`.
1106 AngleBracketedArg
::Constraint(constraint
) => {
1107 self.with_impl_trait(None
, |this
| {
1108 this
.visit_assoc_ty_constraint_from_generic_args(constraint
);
1114 GenericArgs
::Parenthesized(ref data
) => {
1115 walk_list
!(self, visit_ty
, &data
.inputs
);
1116 if let FnRetTy
::Ty(ty
) = &data
.output
{
1117 // `-> Foo` syntax is essentially an associated type binding,
1118 // so it is also allowed to contain nested `impl Trait`.
1119 self.with_impl_trait(None
, |this
| this
.visit_ty(ty
));
1125 fn visit_generics(&mut self, generics
: &'a Generics
) {
1126 let mut prev_ty_default
= None
;
1127 for param
in &generics
.params
{
1129 GenericParamKind
::Lifetime
=> (),
1130 GenericParamKind
::Type { default: Some(_), .. }
=> {
1131 prev_ty_default
= Some(param
.ident
.span
);
1133 GenericParamKind
::Type { .. }
| GenericParamKind
::Const { .. }
=> {
1134 if let Some(span
) = prev_ty_default
{
1135 let mut err
= self.err_handler().struct_span_err(
1137 "type parameters with a default must be trailing",
1139 if matches
!(param
.kind
, GenericParamKind
::Const { .. }
) {
1141 "using type defaults and const parameters \
1142 in the same parameter list is currently not permitted",
1152 validate_generic_param_order(
1155 generics
.params
.iter().map(|param
| {
1156 let ident
= Some(param
.ident
.to_string());
1157 let (kind
, ident
) = match ¶m
.kind
{
1158 GenericParamKind
::Lifetime
=> (ParamKindOrd
::Lifetime
, ident
),
1159 GenericParamKind
::Type { default: _ }
=> (ParamKindOrd
::Type
, ident
),
1160 GenericParamKind
::Const { ref ty, kw_span: _ }
=> {
1161 let ty
= pprust
::ty_to_string(ty
);
1162 let unordered
= self.session
.features_untracked().const_generics
;
1164 ParamKindOrd
::Const { unordered }
,
1165 Some(format
!("const {}: {}", param
.ident
, ty
)),
1169 (kind
, Some(&*param
.bounds
), param
.ident
.span
, ident
)
1174 for predicate
in &generics
.where_clause
.predicates
{
1175 if let WherePredicate
::EqPredicate(ref predicate
) = *predicate
{
1176 deny_equality_constraints(self, predicate
, generics
);
1180 visit
::walk_generics(self, generics
)
1183 fn visit_generic_param(&mut self, param
: &'a GenericParam
) {
1184 if let GenericParamKind
::Lifetime { .. }
= param
.kind
{
1185 self.check_lifetime(param
.ident
);
1187 visit
::walk_generic_param(self, param
);
1190 fn visit_param_bound(&mut self, bound
: &'a GenericBound
) {
1192 GenericBound
::Trait(_
, TraitBoundModifier
::MaybeConst
) => {
1193 if let Some(ctx
) = self.bound_context
{
1194 let msg
= format
!("`?const` is not permitted in {}", ctx
.description());
1195 self.err_handler().span_err(bound
.span(), &msg
);
1199 GenericBound
::Trait(_
, TraitBoundModifier
::MaybeConstMaybe
) => {
1201 .span_err(bound
.span(), "`?const` and `?` are mutually exclusive");
1207 visit
::walk_param_bound(self, bound
)
1210 fn visit_pat(&mut self, pat
: &'a Pat
) {
1212 PatKind
::Lit(ref expr
) => {
1213 self.check_expr_within_pat(expr
, false);
1215 PatKind
::Range(ref start
, ref end
, _
) => {
1216 if let Some(expr
) = start
{
1217 self.check_expr_within_pat(expr
, true);
1219 if let Some(expr
) = end
{
1220 self.check_expr_within_pat(expr
, true);
1226 visit
::walk_pat(self, pat
)
1229 fn visit_where_predicate(&mut self, p
: &'a WherePredicate
) {
1230 if let &WherePredicate
::BoundPredicate(ref bound_predicate
) = p
{
1231 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1232 self.check_late_bound_lifetime_defs(&bound_predicate
.bound_generic_params
);
1234 visit
::walk_where_predicate(self, p
);
1237 fn visit_poly_trait_ref(&mut self, t
: &'a PolyTraitRef
, m
: &'a TraitBoundModifier
) {
1238 self.check_late_bound_lifetime_defs(&t
.bound_generic_params
);
1239 visit
::walk_poly_trait_ref(self, t
, m
);
1242 fn visit_variant_data(&mut self, s
: &'a VariantData
) {
1243 self.with_banned_assoc_ty_bound(|this
| visit
::walk_struct_def(this
, s
))
1248 enum_definition
: &'a EnumDef
,
1249 generics
: &'a Generics
,
1253 self.with_banned_assoc_ty_bound(|this
| {
1254 visit
::walk_enum_def(this
, enum_definition
, generics
, item_id
)
1258 fn visit_fn(&mut self, fk
: FnKind
<'a
>, span
: Span
, id
: NodeId
) {
1259 // Only associated `fn`s can have `self` parameters.
1260 let self_semantic
= match fk
.ctxt() {
1261 Some(FnCtxt
::Assoc(_
)) => SelfSemantic
::Yes
,
1262 _
=> SelfSemantic
::No
,
1264 self.check_fn_decl(fk
.decl(), self_semantic
);
1266 self.check_c_varadic_type(fk
);
1268 // Functions cannot both be `const async`
1269 if let Some(FnHeader
{
1270 constness
: Const
::Yes(cspan
),
1271 asyncness
: Async
::Yes { span: aspan, .. }
,
1277 vec
![*cspan
, *aspan
],
1278 "functions cannot be both `const` and `async`",
1280 .span_label(*cspan
, "`const` because of this")
1281 .span_label(*aspan
, "`async` because of this")
1282 .span_label(span
, "") // Point at the fn header.
1286 // Functions without bodies cannot have patterns.
1287 if let FnKind
::Fn(ctxt
, _
, sig
, _
, None
) = fk
{
1288 Self::check_decl_no_pat(&sig
.decl
, |span
, mut_ident
| {
1289 let (code
, msg
, label
) = match ctxt
{
1290 FnCtxt
::Foreign
=> (
1292 "patterns aren't allowed in foreign function declarations",
1293 "pattern not allowed in foreign function",
1297 "patterns aren't allowed in functions without bodies",
1298 "pattern not allowed in function without body",
1301 if mut_ident
&& matches
!(ctxt
, FnCtxt
::Assoc(_
)) {
1302 self.lint_buffer
.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY
, id
, span
, msg
);
1305 .struct_span_err(span
, msg
)
1306 .span_label(span
, label
)
1313 visit
::walk_fn(self, fk
, span
);
1316 fn visit_assoc_item(&mut self, item
: &'a AssocItem
, ctxt
: AssocCtxt
) {
1317 if ctxt
== AssocCtxt
::Trait
|| !self.in_trait_impl
{
1318 self.check_defaultness(item
.span
, item
.kind
.defaultness());
1321 if ctxt
== AssocCtxt
::Impl
{
1323 AssocItemKind
::Const(_
, _
, body
) => {
1324 self.check_impl_item_provided(item
.span
, body
, "constant", " = <expr>;");
1326 AssocItemKind
::Fn(_
, _
, _
, body
) => {
1327 self.check_impl_item_provided(item
.span
, body
, "function", " { <body> }");
1329 AssocItemKind
::TyAlias(_
, _
, bounds
, body
) => {
1330 self.check_impl_item_provided(item
.span
, body
, "type", " = <type>;");
1331 self.check_type_no_bounds(bounds
, "`impl`s");
1337 if ctxt
== AssocCtxt
::Trait
|| self.in_trait_impl
{
1338 self.invalid_visibility(&item
.vis
, None
);
1339 if let AssocItemKind
::Fn(_
, sig
, _
, _
) = &item
.kind
{
1340 self.check_trait_fn_not_const(sig
.header
.constness
);
1341 self.check_trait_fn_not_async(item
.span
, sig
.header
.asyncness
);
1345 if let AssocItemKind
::Const(..) = item
.kind
{
1346 self.check_item_named(item
.ident
, "const");
1349 self.with_in_trait_impl(false, |this
| visit
::walk_assoc_item(this
, item
, ctxt
));
1353 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1354 /// like it's setting an associated type, provide an appropriate suggestion.
1355 fn deny_equality_constraints(
1356 this
: &mut AstValidator
<'_
>,
1357 predicate
: &WhereEqPredicate
,
1358 generics
: &Generics
,
1360 let mut err
= this
.err_handler().struct_span_err(
1362 "equality constraints are not yet supported in `where` clauses",
1364 err
.span_label(predicate
.span
, "not supported");
1366 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1367 if let TyKind
::Path(Some(qself
), full_path
) = &predicate
.lhs_ty
.kind
{
1368 if let TyKind
::Path(None
, path
) = &qself
.ty
.kind
{
1369 match &path
.segments
[..] {
1370 [PathSegment { ident, args: None, .. }
] => {
1371 for param
in &generics
.params
{
1372 if param
.ident
== *ident
{
1374 match &full_path
.segments
[qself
.position
..] {
1375 [PathSegment { ident, args, .. }
] => {
1376 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1377 let mut assoc_path
= full_path
.clone();
1378 // Remove `Bar` from `Foo::Bar`.
1379 assoc_path
.segments
.pop();
1380 let len
= assoc_path
.segments
.len() - 1;
1381 let gen_args
= args
.as_ref().map(|p
| (**p
).clone());
1382 // Build `<Bar = RhsTy>`.
1383 let arg
= AngleBracketedArg
::Constraint(AssocTyConstraint
{
1384 id
: rustc_ast
::node_id
::DUMMY_NODE_ID
,
1387 kind
: AssocTyConstraintKind
::Equality
{
1388 ty
: predicate
.rhs_ty
.clone(),
1392 // Add `<Bar = RhsTy>` to `Foo`.
1393 match &mut assoc_path
.segments
[len
].args
{
1394 Some(args
) => match args
.deref_mut() {
1395 GenericArgs
::Parenthesized(_
) => continue,
1396 GenericArgs
::AngleBracketed(args
) => {
1397 args
.args
.push(arg
);
1401 *empty_args
= AngleBracketedArgs
{
1408 err
.span_suggestion_verbose(
1411 "if `{}` is an associated type you're trying to set, \
1412 use the associated type binding syntax",
1418 pprust
::path_to_string(&assoc_path
)
1420 Applicability
::MaybeIncorrect
,
1433 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1438 pub fn check_crate(session
: &Session
, krate
: &Crate
, lints
: &mut LintBuffer
) -> bool
{
1439 let mut validator
= AstValidator
{
1442 in_trait_impl
: false,
1443 has_proc_macro_decls
: false,
1444 outer_impl_trait
: None
,
1445 bound_context
: None
,
1446 is_impl_trait_banned
: false,
1447 is_assoc_ty_bound_banned
: false,
1450 visit
::walk_crate(&mut validator
, krate
);
1452 validator
.has_proc_macro_decls