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, BoundKind, FnCtxt, FnKind, Visitor}
;
12 use rustc_ast
::walk_list
;
14 use rustc_ast_pretty
::pprust
::{self, State}
;
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
::{
19 DEPRECATED_WHERE_CLAUSE_LOCATION
, MISSING_ABI
, PATTERNS_IN_FNS_WITHOUT_BODY
,
21 use rustc_session
::lint
::{BuiltinLintDiagnostics, LintBuffer}
;
22 use rustc_session
::Session
;
23 use rustc_span
::source_map
::Spanned
;
24 use rustc_span
::symbol
::{kw, sym, Ident}
;
26 use rustc_target
::spec
::abi
;
28 use std
::ops
::{Deref, DerefMut}
;
30 const MORE_EXTERN
: &str =
31 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
33 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
39 struct AstValidator
<'a
> {
42 /// The span of the `extern` in an `extern { ... }` block, if any.
43 extern_mod
: Option
<&'a Item
>,
45 /// Are we inside a trait impl?
48 in_const_trait_impl
: bool
,
50 has_proc_macro_decls
: bool
,
52 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
53 /// Nested `impl Trait` _is_ allowed in associated type position,
54 /// e.g., `impl Iterator<Item = impl Debug>`.
55 outer_impl_trait
: Option
<Span
>,
57 is_tilde_const_allowed
: bool
,
59 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
60 /// or `Foo::Bar<impl Trait>`
61 is_impl_trait_banned
: bool
,
63 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
64 /// certain positions.
65 is_assoc_ty_bound_banned
: bool
,
67 /// See [ForbiddenLetReason]
68 forbidden_let_reason
: Option
<ForbiddenLetReason
>,
70 lint_buffer
: &'a
mut LintBuffer
,
73 impl<'a
> AstValidator
<'a
> {
74 fn with_in_trait_impl(
77 constness
: Option
<Const
>,
78 f
: impl FnOnce(&mut Self),
80 let old
= mem
::replace(&mut self.in_trait_impl
, is_in
);
82 mem
::replace(&mut self.in_const_trait_impl
, matches
!(constness
, Some(Const
::Yes(_
))));
84 self.in_trait_impl
= old
;
85 self.in_const_trait_impl
= old_const
;
88 fn with_banned_impl_trait(&mut self, f
: impl FnOnce(&mut Self)) {
89 let old
= mem
::replace(&mut self.is_impl_trait_banned
, true);
91 self.is_impl_trait_banned
= old
;
94 fn with_tilde_const(&mut self, allowed
: bool
, f
: impl FnOnce(&mut Self)) {
95 let old
= mem
::replace(&mut self.is_tilde_const_allowed
, allowed
);
97 self.is_tilde_const_allowed
= old
;
100 fn with_tilde_const_allowed(&mut self, f
: impl FnOnce(&mut Self)) {
101 self.with_tilde_const(true, f
)
104 fn with_banned_tilde_const(&mut self, f
: impl FnOnce(&mut Self)) {
105 self.with_tilde_const(false, f
)
108 fn with_let_management(
110 forbidden_let_reason
: Option
<ForbiddenLetReason
>,
111 f
: impl FnOnce(&mut Self, Option
<ForbiddenLetReason
>),
113 let old
= mem
::replace(&mut self.forbidden_let_reason
, forbidden_let_reason
);
115 self.forbidden_let_reason
= old
;
118 /// Emits an error banning the `let` expression provided in the given location.
119 fn ban_let_expr(&self, expr
: &'a Expr
, forbidden_let_reason
: ForbiddenLetReason
) {
120 let sess
= &self.session
;
121 if sess
.opts
.unstable_features
.is_nightly_build() {
122 let err
= "`let` expressions are not supported here";
123 let mut diag
= sess
.struct_span_err(expr
.span
, err
);
124 diag
.note("only supported directly in conditions of `if` and `while` expressions");
125 match forbidden_let_reason
{
126 ForbiddenLetReason
::GenericForbidden
=> {}
127 ForbiddenLetReason
::NotSupportedOr(span
) => {
130 "`||` operators are not supported in let chain expressions",
133 ForbiddenLetReason
::NotSupportedParentheses(span
) => {
136 "`let`s wrapped in parentheses are not supported in a context with let \
143 sess
.struct_span_err(expr
.span
, "expected expression, found statement (`let`)")
144 .note("variable declaration using `let` is a statement")
152 before_predicates
: &[WherePredicate
],
153 where_clauses
: (ast
::TyAliasWhereClause
, ast
::TyAliasWhereClause
),
155 if !before_predicates
.is_empty() {
156 let mut state
= State
::new();
157 if !where_clauses
.1.0 {
159 state
.word_space("where");
161 state
.word_space(",");
163 let mut first
= true;
164 for p
in before_predicates
.iter() {
166 state
.word_space(",");
169 state
.print_where_predicate(p
);
171 let suggestion
= state
.s
.eof();
172 self.lint_buffer
.buffer_lint_with_diagnostic(
173 DEPRECATED_WHERE_CLAUSE_LOCATION
,
176 "where clause not allowed here",
177 BuiltinLintDiagnostics
::DeprecatedWhereclauseLocation(
178 where_clauses
.1.1.shrink_to_hi(),
185 fn with_banned_assoc_ty_bound(&mut self, f
: impl FnOnce(&mut Self)) {
186 let old
= mem
::replace(&mut self.is_assoc_ty_bound_banned
, true);
188 self.is_assoc_ty_bound_banned
= old
;
191 fn with_impl_trait(&mut self, outer
: Option
<Span
>, f
: impl FnOnce(&mut Self)) {
192 let old
= mem
::replace(&mut self.outer_impl_trait
, outer
);
194 self.with_banned_tilde_const(f
);
198 self.outer_impl_trait
= old
;
201 fn visit_assoc_constraint_from_generic_args(&mut self, constraint
: &'a AssocConstraint
) {
202 match constraint
.kind
{
203 AssocConstraintKind
::Equality { .. }
=> {}
204 AssocConstraintKind
::Bound { .. }
=> {
205 if self.is_assoc_ty_bound_banned
{
206 self.err_handler().span_err(
208 "associated type bounds are not allowed within structs, enums, or unions",
213 self.visit_assoc_constraint(constraint
);
216 // Mirrors `visit::walk_ty`, but tracks relevant state.
217 fn walk_ty(&mut self, t
: &'a Ty
) {
219 TyKind
::ImplTrait(..) => {
220 self.with_impl_trait(Some(t
.span
), |this
| visit
::walk_ty(this
, t
))
222 TyKind
::TraitObject(..) => self.with_banned_tilde_const(|this
| visit
::walk_ty(this
, t
)),
223 TyKind
::Path(ref qself
, ref path
) => {
225 // - `Option<impl Trait>`
226 // - `option::Option<impl Trait>`
227 // - `option::Option<T>::Foo<impl Trait>
230 // - `<impl Trait>::Foo`
231 // - `option::Option<impl Trait>::Foo`.
233 // To implement this, we disallow `impl Trait` from `qself`
234 // (for cases like `<impl Trait>::Foo>`)
235 // but we allow `impl Trait` in `GenericArgs`
236 // iff there are no more PathSegments.
237 if let Some(ref qself
) = *qself
{
238 // `impl Trait` in `qself` is always illegal
239 self.with_banned_impl_trait(|this
| this
.visit_ty(&qself
.ty
));
242 // Note that there should be a call to visit_path here,
243 // so if any logic is added to process `Path`s a call to it should be
244 // added both in visit_path and here. This code mirrors visit::walk_path.
245 for (i
, segment
) in path
.segments
.iter().enumerate() {
246 // Allow `impl Trait` iff we're on the final path segment
247 if i
== path
.segments
.len() - 1 {
248 self.visit_path_segment(path
.span
, segment
);
250 self.with_banned_impl_trait(|this
| {
251 this
.visit_path_segment(path
.span
, segment
)
256 _
=> visit
::walk_ty(self, t
),
260 fn visit_struct_field_def(&mut self, field
: &'a FieldDef
) {
261 if let Some(ident
) = field
.ident
{
262 if ident
.name
== kw
::Underscore
{
263 self.visit_vis(&field
.vis
);
264 self.visit_ident(ident
);
265 self.visit_ty_common(&field
.ty
);
266 self.walk_ty(&field
.ty
);
267 walk_list
!(self, visit_attribute
, &field
.attrs
);
271 self.visit_field_def(field
);
274 fn err_handler(&self) -> &rustc_errors
::Handler
{
275 &self.session
.diagnostic()
278 fn check_lifetime(&self, ident
: Ident
) {
279 let valid_names
= [kw
::UnderscoreLifetime
, kw
::StaticLifetime
, kw
::Empty
];
280 if !valid_names
.contains(&ident
.name
) && ident
.without_first_quote().is_reserved() {
281 self.err_handler().span_err(ident
.span
, "lifetimes cannot use keyword names");
285 fn check_label(&self, ident
: Ident
) {
286 if ident
.without_first_quote().is_reserved() {
288 .span_err(ident
.span
, &format
!("invalid label name `{}`", ident
.name
));
292 fn invalid_visibility(&self, vis
: &Visibility
, note
: Option
<&str>) {
293 if let VisibilityKind
::Inherited
= vis
.kind
{
298 struct_span_err
!(self.session
, vis
.span
, E0449
, "unnecessary visibility qualifier");
299 if vis
.kind
.is_pub() {
300 err
.span_label(vis
.span
, "`pub` not permitted here because it's implied");
302 if let Some(note
) = note
{
308 fn check_decl_no_pat(decl
: &FnDecl
, mut report_err
: impl FnMut(Span
, Option
<Ident
>, bool
)) {
309 for Param { pat, .. }
in &decl
.inputs
{
311 PatKind
::Ident(BindingMode
::ByValue(Mutability
::Not
), _
, None
) | PatKind
::Wild
=> {}
312 PatKind
::Ident(BindingMode
::ByValue(Mutability
::Mut
), ident
, None
) => {
313 report_err(pat
.span
, Some(ident
), true)
315 _
=> report_err(pat
.span
, None
, false),
320 fn check_trait_fn_not_async(&self, fn_span
: Span
, asyncness
: Async
) {
321 if let Async
::Yes { span, .. }
= asyncness
{
326 "functions in traits cannot be declared `async`"
328 .span_label(span
, "`async` because of this")
329 .note("`async` trait functions are not currently supported")
330 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
335 fn check_trait_fn_not_const(&self, constness
: Const
) {
336 if let Const
::Yes(span
) = constness
{
341 "functions in traits cannot be declared const"
343 .span_label(span
, "functions in traits cannot be const")
348 fn check_late_bound_lifetime_defs(&self, params
: &[GenericParam
]) {
349 // Check only lifetime parameters are present and that the lifetime
350 // parameters that are present have no bounds.
351 let non_lt_param_spans
: Vec
<_
> = params
353 .filter_map(|param
| match param
.kind
{
354 GenericParamKind
::Lifetime { .. }
=> {
355 if !param
.bounds
.is_empty() {
356 let spans
: Vec
<_
> = param
.bounds
.iter().map(|b
| b
.span()).collect();
358 .span_err(spans
, "lifetime bounds cannot be used in this context");
362 _
=> Some(param
.ident
.span
),
365 if !non_lt_param_spans
.is_empty() {
366 self.err_handler().span_err(
368 "only lifetime parameters can be used in this context",
373 fn check_fn_decl(&self, fn_decl
: &FnDecl
, self_semantic
: SelfSemantic
) {
374 self.check_decl_num_args(fn_decl
);
375 self.check_decl_cvaradic_pos(fn_decl
);
376 self.check_decl_attrs(fn_decl
);
377 self.check_decl_self_param(fn_decl
, self_semantic
);
380 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
381 /// Error is fatal to prevent errors during typechecking
382 fn check_decl_num_args(&self, fn_decl
: &FnDecl
) {
383 let max_num_args
: usize = u16::MAX
.into();
384 if fn_decl
.inputs
.len() > max_num_args
{
385 let Param { span, .. }
= fn_decl
.inputs
[0];
386 self.err_handler().span_fatal(
388 &format
!("function can not have more than {} arguments", max_num_args
),
393 fn check_decl_cvaradic_pos(&self, fn_decl
: &FnDecl
) {
394 match &*fn_decl
.inputs
{
395 [Param { ty, span, .. }
] => {
396 if let TyKind
::CVarArgs
= ty
.kind
{
397 self.err_handler().span_err(
399 "C-variadic function must be declared with at least one named argument",
404 for Param { ty, span, .. }
in ps
{
405 if let TyKind
::CVarArgs
= ty
.kind
{
406 self.err_handler().span_err(
408 "`...` must be the last argument of a C-variadic function",
417 fn check_decl_attrs(&self, fn_decl
: &FnDecl
) {
421 .flat_map(|i
| i
.attrs
.as_ref())
432 !arr
.contains(&attr
.name_or_empty()) && rustc_attr
::is_builtin_attr(attr
)
435 if attr
.is_doc_comment() {
439 "documentation comments cannot be applied to function parameters",
441 .span_label(attr
.span
, "doc comments are not allowed here")
444 self.err_handler().span_err(
446 "allow, cfg, cfg_attr, deny, expect, \
447 forbid, and warn are the only allowed built-in attributes in function parameters",
453 fn check_decl_self_param(&self, fn_decl
: &FnDecl
, self_semantic
: SelfSemantic
) {
454 if let (SelfSemantic
::No
, [param
, ..]) = (self_semantic
, &*fn_decl
.inputs
) {
459 "`self` parameter is only allowed in associated functions",
461 .span_label(param
.span
, "not semantically valid as function parameter")
462 .note("associated functions are those in `impl` or `trait` definitions")
468 fn check_defaultness(&self, span
: Span
, defaultness
: Defaultness
) {
469 if let Defaultness
::Default(def_span
) = defaultness
{
470 let span
= self.session
.source_map().guess_head_span(span
);
472 .struct_span_err(span
, "`default` is only allowed on items in trait impls")
473 .span_label(def_span
, "`default` because of this")
478 fn error_item_without_body(&self, sp
: Span
, ctx
: &str, msg
: &str, sugg
: &str) {
479 let source_map
= self.session
.source_map();
480 let end
= source_map
.end_point(sp
);
481 let replace_span
= if source_map
.span_to_snippet(end
).map(|s
| s
== ";").unwrap_or(false) {
487 .struct_span_err(sp
, msg
)
490 &format
!("provide a definition for the {}", ctx
),
492 Applicability
::HasPlaceholders
,
497 fn check_impl_item_provided
<T
>(&self, sp
: Span
, body
: &Option
<T
>, ctx
: &str, sugg
: &str) {
499 let msg
= format
!("associated {} in `impl` without body", ctx
);
500 self.error_item_without_body(sp
, ctx
, &msg
, sugg
);
504 fn check_type_no_bounds(&self, bounds
: &[GenericBound
], ctx
: &str) {
505 let span
= match bounds
{
508 [b0
, .., bl
] => b0
.span().to(bl
.span()),
511 .struct_span_err(span
, &format
!("bounds on `type`s in {} have no effect", ctx
))
515 fn check_foreign_ty_genericless(&self, generics
: &Generics
, where_span
: Span
) {
516 let cannot_have
= |span
, descr
, remove_descr
| {
520 &format
!("`type`s inside `extern` blocks cannot have {}", descr
),
524 &format
!("remove the {}", remove_descr
),
526 Applicability
::MaybeIncorrect
,
528 .span_label(self.current_extern_span(), "`extern` block begins here")
533 if !generics
.params
.is_empty() {
534 cannot_have(generics
.span
, "generic parameters", "generic parameters");
537 if !generics
.where_clause
.predicates
.is_empty() {
538 cannot_have(where_span
, "`where` clauses", "`where` clause");
542 fn check_foreign_kind_bodyless(&self, ident
: Ident
, kind
: &str, body
: Option
<Span
>) {
543 let Some(body
) = body
else {
547 .struct_span_err(ident
.span
, &format
!("incorrect `{}` inside `extern` block", kind
))
548 .span_label(ident
.span
, "cannot have a body")
549 .span_label(body
, "the invalid body")
551 self.current_extern_span(),
553 "`extern` blocks define existing foreign {0}s and {0}s \
554 inside of them cannot have a body",
562 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
563 fn check_foreign_fn_bodyless(&self, ident
: Ident
, body
: Option
<&Block
>) {
564 let Some(body
) = body
else {
568 .struct_span_err(ident
.span
, "incorrect function inside `extern` block")
569 .span_label(ident
.span
, "cannot have a body")
572 "remove the invalid body",
574 Applicability
::MaybeIncorrect
,
577 "you might have meant to write a function accessible through FFI, \
578 which can be done by writing `extern fn` outside of the `extern` block",
581 self.current_extern_span(),
582 "`extern` blocks define existing foreign functions and functions \
583 inside of them cannot have a body",
589 fn current_extern_span(&self) -> Span
{
590 self.session
.source_map().guess_head_span(self.extern_mod
.unwrap().span
)
593 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
594 fn check_foreign_fn_headerless(&self, ident
: Ident
, span
: Span
, header
: FnHeader
) {
595 if header
.has_qualifiers() {
597 .struct_span_err(ident
.span
, "functions in `extern` blocks cannot have qualifiers")
598 .span_label(self.current_extern_span(), "in this `extern` block")
599 .span_suggestion_verbose(
600 span
.until(ident
.span
.shrink_to_lo()),
601 "remove the qualifiers",
603 Applicability
::MaybeIncorrect
,
609 /// An item in `extern { ... }` cannot use non-ascii identifier.
610 fn check_foreign_item_ascii_only(&self, ident
: Ident
) {
611 if !ident
.as_str().is_ascii() {
616 "items in `extern` blocks cannot use non-ascii identifiers",
618 .span_label(self.current_extern_span(), "in this `extern` block")
620 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
627 /// Reject C-variadic type unless the function is foreign,
628 /// or free and `unsafe extern "C"` semantically.
629 fn check_c_variadic_type(&self, fk
: FnKind
<'a
>) {
630 match (fk
.ctxt(), fk
.header()) {
631 (Some(FnCtxt
::Foreign
), _
) => return,
632 (Some(FnCtxt
::Free
), Some(header
)) => match header
.ext
{
633 Extern
::Explicit(StrLit { symbol_unescaped: sym::C, .. }
) | Extern
::Implicit
634 if matches
!(header
.unsafety
, Unsafe
::Yes(_
)) =>
643 for Param { ty, span, .. }
in &fk
.decl().inputs
{
644 if let TyKind
::CVarArgs
= ty
.kind
{
648 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
655 fn check_item_named(&self, ident
: Ident
, kind
: &str) {
656 if ident
.name
!= kw
::Underscore
{
660 .struct_span_err(ident
.span
, &format
!("`{}` items in this context need a name", kind
))
661 .span_label(ident
.span
, format
!("`_` is not a valid name for this `{}` item", kind
))
665 fn check_nomangle_item_asciionly(&self, ident
: Ident
, item_span
: Span
) {
666 if ident
.name
.as_str().is_ascii() {
669 let head_span
= self.session
.source_map().guess_head_span(item_span
);
674 "`#[no_mangle]` requires ASCII identifier"
679 fn check_mod_file_item_asciionly(&self, ident
: Ident
) {
680 if ident
.name
.as_str().is_ascii() {
687 "trying to load file for module `{}` with non-ascii identifier name",
690 .help("consider using `#[path]` attribute to specify filesystem path")
694 fn deny_generic_params(&self, generics
: &Generics
, ident_span
: Span
) {
695 if !generics
.params
.is_empty() {
700 "auto traits cannot have generic parameters"
702 .span_label(ident_span
, "auto trait cannot have generic parameters")
705 "remove the parameters",
707 Applicability
::MachineApplicable
,
713 fn emit_e0568(&self, span
: Span
, ident_span
: Span
) {
718 "auto traits cannot have super traits or lifetime bounds"
720 .span_label(ident_span
, "auto trait cannot have super traits or lifetime bounds")
723 "remove the super traits or lifetime bounds",
725 Applicability
::MachineApplicable
,
730 fn deny_super_traits(&self, bounds
: &GenericBounds
, ident_span
: Span
) {
731 if let [.., last
] = &bounds
[..] {
732 let span
= ident_span
.shrink_to_hi().to(last
.span());
733 self.emit_e0568(span
, ident_span
);
737 fn deny_where_clause(&self, where_clause
: &WhereClause
, ident_span
: Span
) {
738 if !where_clause
.predicates
.is_empty() {
739 self.emit_e0568(where_clause
.span
, ident_span
);
743 fn deny_items(&self, trait_items
: &[P
<AssocItem
>], ident_span
: Span
) {
744 if !trait_items
.is_empty() {
745 let spans
: Vec
<_
> = trait_items
.iter().map(|i
| i
.ident
.span
).collect();
746 let total_span
= trait_items
.first().unwrap().span
.to(trait_items
.last().unwrap().span
);
751 "auto traits cannot have associated items"
755 "remove these associated items",
757 Applicability
::MachineApplicable
,
759 .span_label(ident_span
, "auto trait cannot have associated items")
764 fn correct_generic_order_suggestion(&self, data
: &AngleBracketedArgs
) -> String
{
765 // Lifetimes always come first.
766 let lt_sugg
= data
.args
.iter().filter_map(|arg
| match arg
{
767 AngleBracketedArg
::Arg(lt @ GenericArg
::Lifetime(_
)) => {
768 Some(pprust
::to_string(|s
| s
.print_generic_arg(lt
)))
772 let args_sugg
= data
.args
.iter().filter_map(|a
| match a
{
773 AngleBracketedArg
::Arg(GenericArg
::Lifetime(_
)) | AngleBracketedArg
::Constraint(_
) => {
776 AngleBracketedArg
::Arg(arg
) => Some(pprust
::to_string(|s
| s
.print_generic_arg(arg
))),
778 // Constraints always come last.
779 let constraint_sugg
= data
.args
.iter().filter_map(|a
| match a
{
780 AngleBracketedArg
::Arg(_
) => None
,
781 AngleBracketedArg
::Constraint(c
) => {
782 Some(pprust
::to_string(|s
| s
.print_assoc_constraint(c
)))
787 lt_sugg
.chain(args_sugg
).chain(constraint_sugg
).collect
::<Vec
<String
>>().join(", ")
791 /// Enforce generic args coming before constraints in `<...>` of a path segment.
792 fn check_generic_args_before_constraints(&self, data
: &AngleBracketedArgs
) {
793 // Early exit in case it's partitioned as it should be.
794 if data
.args
.iter().is_partitioned(|arg
| matches
!(arg
, AngleBracketedArg
::Arg(_
))) {
797 // Find all generic argument coming after the first constraint...
798 let (constraint_spans
, arg_spans
): (Vec
<Span
>, Vec
<Span
>) =
799 data
.args
.iter().partition_map(|arg
| match arg
{
800 AngleBracketedArg
::Constraint(c
) => Either
::Left(c
.span
),
801 AngleBracketedArg
::Arg(a
) => Either
::Right(a
.span()),
803 let args_len
= arg_spans
.len();
804 let constraint_len
= constraint_spans
.len();
805 // ...and then error:
809 "generic arguments must come before the first constraint",
811 .span_label(constraint_spans
[0], &format
!("constraint{}", pluralize
!(constraint_len
)))
813 *arg_spans
.iter().last().unwrap(),
814 &format
!("generic argument{}", pluralize
!(args_len
)),
816 .span_labels(constraint_spans
, "")
817 .span_labels(arg_spans
, "")
818 .span_suggestion_verbose(
821 "move the constraint{} after the generic argument{}",
822 pluralize
!(constraint_len
),
825 self.correct_generic_order_suggestion(&data
),
826 Applicability
::MachineApplicable
,
831 fn visit_ty_common(&mut self, ty
: &'a Ty
) {
833 TyKind
::BareFn(ref bfty
) => {
834 self.check_fn_decl(&bfty
.decl
, SelfSemantic
::No
);
835 Self::check_decl_no_pat(&bfty
.decl
, |span
, _
, _
| {
840 "patterns aren't allowed in function pointer types"
844 self.check_late_bound_lifetime_defs(&bfty
.generic_params
);
845 if let Extern
::Implicit
= bfty
.ext
{
846 let sig_span
= self.session
.source_map().next_point(ty
.span
.shrink_to_lo());
847 self.maybe_lint_missing_abi(sig_span
, ty
.id
);
850 TyKind
::TraitObject(ref bounds
, ..) => {
851 let mut any_lifetime_bounds
= false;
852 for bound
in bounds
{
853 if let GenericBound
::Outlives(ref lifetime
) = *bound
{
854 if any_lifetime_bounds
{
859 "only a single explicit lifetime bound is permitted"
864 any_lifetime_bounds
= true;
868 TyKind
::ImplTrait(_
, ref bounds
) => {
869 if self.is_impl_trait_banned
{
874 "`impl Trait` is not allowed in path parameters"
879 if let Some(outer_impl_trait_sp
) = self.outer_impl_trait
{
884 "nested `impl Trait` is not allowed"
886 .span_label(outer_impl_trait_sp
, "outer `impl Trait`")
887 .span_label(ty
.span
, "nested `impl Trait` here")
891 if !bounds
.iter().any(|b
| matches
!(b
, GenericBound
::Trait(..))) {
892 self.err_handler().span_err(ty
.span
, "at least one trait must be specified");
899 fn maybe_lint_missing_abi(&mut self, span
: Span
, id
: NodeId
) {
900 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
901 // call site which do not have a macro backtrace. See #61963.
902 let is_macro_callsite
= self
905 .span_to_snippet(span
)
906 .map(|snippet
| snippet
.starts_with("#["))
908 if !is_macro_callsite
{
909 self.lint_buffer
.buffer_lint_with_diagnostic(
913 "extern declarations without an explicit ABI are deprecated",
914 BuiltinLintDiagnostics
::MissingAbi(span
, abi
::Abi
::FALLBACK
),
920 /// Checks that generic parameters are in the correct order,
921 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
922 fn validate_generic_param_order(
923 handler
: &rustc_errors
::Handler
,
924 generics
: &[GenericParam
],
927 let mut max_param
: Option
<ParamKindOrd
> = None
;
928 let mut out_of_order
= FxHashMap
::default();
929 let mut param_idents
= Vec
::with_capacity(generics
.len());
931 for (idx
, param
) in generics
.iter().enumerate() {
932 let ident
= param
.ident
;
933 let (kind
, bounds
, span
) = (¶m
.kind
, ¶m
.bounds
, ident
.span
);
934 let (ord_kind
, ident
) = match ¶m
.kind
{
935 GenericParamKind
::Lifetime
=> (ParamKindOrd
::Lifetime
, ident
.to_string()),
936 GenericParamKind
::Type { default: _ }
=> (ParamKindOrd
::Type
, ident
.to_string()),
937 GenericParamKind
::Const { ref ty, kw_span: _, default: _ }
=> {
938 let ty
= pprust
::ty_to_string(ty
);
939 (ParamKindOrd
::Const
, format
!("const {}: {}", ident
, ty
))
942 param_idents
.push((kind
, ord_kind
, bounds
, idx
, ident
));
944 Some(max_param
) if max_param
> ord_kind
=> {
945 let entry
= out_of_order
.entry(ord_kind
).or_insert((max_param
, vec
![]));
948 Some(_
) | None
=> max_param
= Some(ord_kind
),
952 if !out_of_order
.is_empty() {
953 let mut ordered_params
= "<".to_string();
954 param_idents
.sort_by_key(|&(_
, po
, _
, i
, _
)| (po
, i
));
955 let mut first
= true;
956 for (kind
, _
, bounds
, _
, ident
) in param_idents
{
958 ordered_params
+= ", ";
960 ordered_params
+= &ident
;
962 if !bounds
.is_empty() {
963 ordered_params
+= ": ";
964 ordered_params
+= &pprust
::bounds_to_string(&bounds
);
968 GenericParamKind
::Type { default: Some(default) }
=> {
969 ordered_params
+= " = ";
970 ordered_params
+= &pprust
::ty_to_string(default);
972 GenericParamKind
::Type { default: None }
=> (),
973 GenericParamKind
::Lifetime
=> (),
974 GenericParamKind
::Const { ty: _, kw_span: _, default: Some(default) }
=> {
975 ordered_params
+= " = ";
976 ordered_params
+= &pprust
::expr_to_string(&*default.value
);
978 GenericParamKind
::Const { ty: _, kw_span: _, default: None }
=> (),
983 ordered_params
+= ">";
985 for (param_ord
, (max_param
, spans
)) in &out_of_order
{
986 let mut err
= handler
.struct_span_err(
989 "{} parameters must be declared prior to {} parameters",
990 param_ord
, max_param
,
995 "reorder the parameters: lifetimes, then consts and types",
997 Applicability
::MachineApplicable
,
1004 impl<'a
> Visitor
<'a
> for AstValidator
<'a
> {
1005 fn visit_attribute(&mut self, attr
: &Attribute
) {
1006 validate_attr
::check_meta(&self.session
.parse_sess
, attr
);
1009 fn visit_expr(&mut self, expr
: &'a Expr
) {
1010 self.with_let_management(Some(ForbiddenLetReason
::GenericForbidden
), |this
, forbidden_let_reason
| {
1012 ExprKind
::Binary(Spanned { node: BinOpKind::Or, span }
, lhs
, rhs
) => {
1013 let local_reason
= Some(ForbiddenLetReason
::NotSupportedOr(*span
));
1014 this
.with_let_management(local_reason
, |this
, _
| this
.visit_expr(lhs
));
1015 this
.with_let_management(local_reason
, |this
, _
| this
.visit_expr(rhs
));
1017 ExprKind
::If(cond
, then
, opt_else
) => {
1018 this
.visit_block(then
);
1019 walk_list
!(this
, visit_expr
, opt_else
);
1020 this
.with_let_management(None
, |this
, _
| this
.visit_expr(cond
));
1023 ExprKind
::Let(..) if let Some(elem
) = forbidden_let_reason
=> {
1024 this
.ban_let_expr(expr
, elem
);
1026 ExprKind
::Match(scrutinee
, arms
) => {
1027 this
.visit_expr(scrutinee
);
1029 this
.visit_expr(&arm
.body
);
1030 this
.visit_pat(&arm
.pat
);
1031 walk_list
!(this
, visit_attribute
, &arm
.attrs
);
1032 if let Some(guard
) = &arm
.guard
&& let ExprKind
::Let(_
, guard_expr
, _
) = &guard
.kind
{
1033 this
.with_let_management(None
, |this
, _
| {
1034 this
.visit_expr(guard_expr
)
1040 ExprKind
::Paren(local_expr
) => {
1041 fn has_let_expr(expr
: &Expr
) -> bool
{
1043 ExprKind
::Binary(_
, ref lhs
, ref rhs
) => has_let_expr(lhs
) || has_let_expr(rhs
),
1044 ExprKind
::Let(..) => true,
1048 let local_reason
= if has_let_expr(local_expr
) {
1049 Some(ForbiddenLetReason
::NotSupportedParentheses(local_expr
.span
))
1052 forbidden_let_reason
1054 this
.with_let_management(local_reason
, |this
, _
| this
.visit_expr(local_expr
));
1056 ExprKind
::Binary(Spanned { node: BinOpKind::And, .. }
, ..) => {
1057 this
.with_let_management(forbidden_let_reason
, |this
, _
| visit
::walk_expr(this
, expr
));
1060 ExprKind
::While(cond
, then
, opt_label
) => {
1061 walk_list
!(this
, visit_label
, opt_label
);
1062 this
.visit_block(then
);
1063 this
.with_let_management(None
, |this
, _
| this
.visit_expr(cond
));
1066 _
=> visit
::walk_expr(this
, expr
),
1071 fn visit_ty(&mut self, ty
: &'a Ty
) {
1072 self.visit_ty_common(ty
);
1076 fn visit_label(&mut self, label
: &'a Label
) {
1077 self.check_label(label
.ident
);
1078 visit
::walk_label(self, label
);
1081 fn visit_lifetime(&mut self, lifetime
: &'a Lifetime
, _
: visit
::LifetimeCtxt
) {
1082 self.check_lifetime(lifetime
.ident
);
1083 visit
::walk_lifetime(self, lifetime
);
1086 fn visit_field_def(&mut self, s
: &'a FieldDef
) {
1087 visit
::walk_field_def(self, s
)
1090 fn visit_item(&mut self, item
: &'a Item
) {
1091 if item
.attrs
.iter().any(|attr
| self.session
.is_proc_macro_attr(attr
)) {
1092 self.has_proc_macro_decls
= true;
1095 if self.session
.contains_name(&item
.attrs
, sym
::no_mangle
) {
1096 self.check_nomangle_item_asciionly(item
.ident
, item
.span
);
1100 ItemKind
::Impl(box Impl
{
1106 of_trait
: Some(ref t
),
1110 self.with_in_trait_impl(true, Some(constness
), |this
| {
1111 this
.invalid_visibility(&item
.vis
, None
);
1112 if let TyKind
::Err
= self_ty
.kind
{
1116 "`impl Trait for .. {}` is an obsolete syntax",
1118 .help("use `auto trait Trait {}` instead")
1121 if let (Unsafe
::Yes(span
), ImplPolarity
::Negative(sp
)) = (unsafety
, polarity
) {
1126 "negative impls cannot be unsafe"
1128 .span_label(sp
, "negative because of this")
1129 .span_label(span
, "unsafe because of this")
1133 this
.visit_vis(&item
.vis
);
1134 this
.visit_ident(item
.ident
);
1135 if let Const
::Yes(_
) = constness
{
1136 this
.with_tilde_const_allowed(|this
| this
.visit_generics(generics
));
1138 this
.visit_generics(generics
);
1140 this
.visit_trait_ref(t
);
1141 this
.visit_ty(self_ty
);
1143 walk_list
!(this
, visit_assoc_item
, items
, AssocCtxt
::Impl
);
1145 return; // Avoid visiting again.
1147 ItemKind
::Impl(box Impl
{
1157 let error
= |annotation_span
, annotation
| {
1158 let mut err
= self.err_handler().struct_span_err(
1160 &format
!("inherent impls cannot be {}", annotation
),
1162 err
.span_label(annotation_span
, &format
!("{} because of this", annotation
));
1163 err
.span_label(self_ty
.span
, "inherent impl for this type");
1167 self.invalid_visibility(
1169 Some("place qualifiers on individual impl items instead"),
1171 if let Unsafe
::Yes(span
) = unsafety
{
1172 error(span
, "unsafe").code(error_code
!(E0197
)).emit();
1174 if let ImplPolarity
::Negative(span
) = polarity
{
1175 error(span
, "negative").emit();
1177 if let Defaultness
::Default(def_span
) = defaultness
{
1178 error(def_span
, "`default`")
1179 .note("only trait implementations may be annotated with `default`")
1182 if let Const
::Yes(span
) = constness
{
1183 error(span
, "`const`")
1184 .note("only trait implementations may be annotated with `const`")
1188 ItemKind
::Fn(box Fn { defaultness, ref sig, ref generics, ref body }
) => {
1189 self.check_defaultness(item
.span
, defaultness
);
1192 let msg
= "free function without a body";
1193 self.error_item_without_body(item
.span
, "function", msg
, " { <body> }");
1195 self.visit_vis(&item
.vis
);
1196 self.visit_ident(item
.ident
);
1198 FnKind
::Fn(FnCtxt
::Free
, item
.ident
, sig
, &item
.vis
, generics
, body
.as_deref());
1199 self.visit_fn(kind
, item
.span
, item
.id
);
1200 walk_list
!(self, visit_attribute
, &item
.attrs
);
1201 return; // Avoid visiting again.
1203 ItemKind
::ForeignMod(ForeignMod { abi, unsafety, .. }
) => {
1204 let old_item
= mem
::replace(&mut self.extern_mod
, Some(item
));
1205 self.invalid_visibility(
1207 Some("place qualifiers on individual foreign items instead"),
1209 if let Unsafe
::Yes(span
) = unsafety
{
1210 self.err_handler().span_err(span
, "extern block cannot be declared unsafe");
1213 self.maybe_lint_missing_abi(item
.span
, item
.id
);
1215 visit
::walk_item(self, item
);
1216 self.extern_mod
= old_item
;
1217 return; // Avoid visiting again.
1219 ItemKind
::Enum(ref def
, _
) => {
1220 for variant
in &def
.variants
{
1221 self.invalid_visibility(&variant
.vis
, None
);
1222 for field
in variant
.data
.fields() {
1223 self.invalid_visibility(&field
.vis
, None
);
1227 ItemKind
::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }
) => {
1228 if is_auto
== IsAuto
::Yes
{
1229 // Auto traits cannot have generics, super traits nor contain items.
1230 self.deny_generic_params(generics
, item
.ident
.span
);
1231 self.deny_super_traits(bounds
, item
.ident
.span
);
1232 self.deny_where_clause(&generics
.where_clause
, item
.ident
.span
);
1233 self.deny_items(items
, item
.ident
.span
);
1236 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1237 // context for the supertraits.
1238 self.visit_vis(&item
.vis
);
1239 self.visit_ident(item
.ident
);
1240 self.visit_generics(generics
);
1241 self.with_banned_tilde_const(|this
| {
1242 walk_list
!(this
, visit_param_bound
, bounds
, BoundKind
::SuperTraits
)
1244 walk_list
!(self, visit_assoc_item
, items
, AssocCtxt
::Trait
);
1245 walk_list
!(self, visit_attribute
, &item
.attrs
);
1248 ItemKind
::Mod(unsafety
, ref mod_kind
) => {
1249 if let Unsafe
::Yes(span
) = unsafety
{
1250 self.err_handler().span_err(span
, "module cannot be declared unsafe");
1252 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1253 if !matches
!(mod_kind
, ModKind
::Loaded(_
, Inline
::Yes
, _
))
1254 && !self.session
.contains_name(&item
.attrs
, sym
::path
)
1256 self.check_mod_file_item_asciionly(item
.ident
);
1259 ItemKind
::Struct(ref vdata
, ref generics
) => match vdata
{
1260 // Duplicating the `Visitor` logic allows catching all cases
1261 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1263 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1264 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1265 // it uses `visit_ty_common`, which doesn't contain that specific check.
1266 VariantData
::Struct(ref fields
, ..) => {
1267 self.visit_vis(&item
.vis
);
1268 self.visit_ident(item
.ident
);
1269 self.visit_generics(generics
);
1270 self.with_banned_assoc_ty_bound(|this
| {
1271 walk_list
!(this
, visit_struct_field_def
, fields
);
1273 walk_list
!(self, visit_attribute
, &item
.attrs
);
1278 ItemKind
::Union(ref vdata
, ref generics
) => {
1279 if vdata
.fields().is_empty() {
1280 self.err_handler().span_err(item
.span
, "unions cannot have zero fields");
1283 VariantData
::Struct(ref fields
, ..) => {
1284 self.visit_vis(&item
.vis
);
1285 self.visit_ident(item
.ident
);
1286 self.visit_generics(generics
);
1287 self.with_banned_assoc_ty_bound(|this
| {
1288 walk_list
!(this
, visit_struct_field_def
, fields
);
1290 walk_list
!(self, visit_attribute
, &item
.attrs
);
1296 ItemKind
::Const(def
, .., None
) => {
1297 self.check_defaultness(item
.span
, def
);
1298 let msg
= "free constant item without body";
1299 self.error_item_without_body(item
.span
, "constant", msg
, " = <expr>;");
1301 ItemKind
::Static(.., None
) => {
1302 let msg
= "free static item without body";
1303 self.error_item_without_body(item
.span
, "static", msg
, " = <expr>;");
1305 ItemKind
::TyAlias(box TyAlias
{
1312 self.check_defaultness(item
.span
, defaultness
);
1314 let msg
= "free type alias without body";
1315 self.error_item_without_body(item
.span
, "type", msg
, " = <type>;");
1317 self.check_type_no_bounds(bounds
, "this context");
1318 if where_clauses
.1.0 {
1319 let mut err
= self.err_handler().struct_span_err(
1321 "where clauses are not allowed after the type for type aliases",
1324 "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
1332 visit
::walk_item(self, item
);
1335 fn visit_foreign_item(&mut self, fi
: &'a ForeignItem
) {
1337 ForeignItemKind
::Fn(box Fn { defaultness, sig, body, .. }
) => {
1338 self.check_defaultness(fi
.span
, *defaultness
);
1339 self.check_foreign_fn_bodyless(fi
.ident
, body
.as_deref());
1340 self.check_foreign_fn_headerless(fi
.ident
, fi
.span
, sig
.header
);
1341 self.check_foreign_item_ascii_only(fi
.ident
);
1343 ForeignItemKind
::TyAlias(box TyAlias
{
1351 self.check_defaultness(fi
.span
, *defaultness
);
1352 self.check_foreign_kind_bodyless(fi
.ident
, "type", ty
.as_ref().map(|b
| b
.span
));
1353 self.check_type_no_bounds(bounds
, "`extern` blocks");
1354 self.check_foreign_ty_genericless(generics
, where_clauses
.0.1);
1355 self.check_foreign_item_ascii_only(fi
.ident
);
1357 ForeignItemKind
::Static(_
, _
, body
) => {
1358 self.check_foreign_kind_bodyless(fi
.ident
, "static", body
.as_ref().map(|b
| b
.span
));
1359 self.check_foreign_item_ascii_only(fi
.ident
);
1361 ForeignItemKind
::MacCall(..) => {}
1364 visit
::walk_foreign_item(self, fi
)
1367 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1368 fn visit_generic_args(&mut self, _
: Span
, generic_args
: &'a GenericArgs
) {
1369 match *generic_args
{
1370 GenericArgs
::AngleBracketed(ref data
) => {
1371 self.check_generic_args_before_constraints(data
);
1373 for arg
in &data
.args
{
1375 AngleBracketedArg
::Arg(arg
) => self.visit_generic_arg(arg
),
1376 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1377 // are allowed to contain nested `impl Trait`.
1378 AngleBracketedArg
::Constraint(constraint
) => {
1379 self.with_impl_trait(None
, |this
| {
1380 this
.visit_assoc_constraint_from_generic_args(constraint
);
1386 GenericArgs
::Parenthesized(ref data
) => {
1387 walk_list
!(self, visit_ty
, &data
.inputs
);
1388 if let FnRetTy
::Ty(ty
) = &data
.output
{
1389 // `-> Foo` syntax is essentially an associated type binding,
1390 // so it is also allowed to contain nested `impl Trait`.
1391 self.with_impl_trait(None
, |this
| this
.visit_ty(ty
));
1397 fn visit_generics(&mut self, generics
: &'a Generics
) {
1398 let mut prev_param_default
= None
;
1399 for param
in &generics
.params
{
1401 GenericParamKind
::Lifetime
=> (),
1402 GenericParamKind
::Type { default: Some(_), .. }
1403 | GenericParamKind
::Const { default: Some(_), .. }
=> {
1404 prev_param_default
= Some(param
.ident
.span
);
1406 GenericParamKind
::Type { .. }
| GenericParamKind
::Const { .. }
=> {
1407 if let Some(span
) = prev_param_default
{
1408 let mut err
= self.err_handler().struct_span_err(
1410 "generic parameters with a default must be trailing",
1419 validate_generic_param_order(self.err_handler(), &generics
.params
, generics
.span
);
1421 for predicate
in &generics
.where_clause
.predicates
{
1422 if let WherePredicate
::EqPredicate(ref predicate
) = *predicate
{
1423 deny_equality_constraints(self, predicate
, generics
);
1426 walk_list
!(self, visit_generic_param
, &generics
.params
);
1427 for predicate
in &generics
.where_clause
.predicates
{
1429 WherePredicate
::BoundPredicate(bound_pred
) => {
1430 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1431 self.check_late_bound_lifetime_defs(&bound_pred
.bound_generic_params
);
1433 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1434 // binder and thus we only allow a single level of quantification. However,
1435 // the syntax of Rust permits quantification in two places in where clauses,
1436 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1437 // defined, then error.
1438 if !bound_pred
.bound_generic_params
.is_empty() {
1439 for bound
in &bound_pred
.bounds
{
1441 GenericBound
::Trait(t
, _
) => {
1442 if !t
.bound_generic_params
.is_empty() {
1447 "nested quantification of lifetimes"
1452 GenericBound
::Outlives(_
) => {}
1459 self.visit_where_predicate(predicate
);
1463 fn visit_generic_param(&mut self, param
: &'a GenericParam
) {
1464 if let GenericParamKind
::Lifetime { .. }
= param
.kind
{
1465 self.check_lifetime(param
.ident
);
1467 visit
::walk_generic_param(self, param
);
1470 fn visit_param_bound(&mut self, bound
: &'a GenericBound
, ctxt
: BoundKind
) {
1471 if let GenericBound
::Trait(ref poly
, modify
) = *bound
{
1472 match (ctxt
, modify
) {
1473 (BoundKind
::SuperTraits
, TraitBoundModifier
::Maybe
) => {
1476 .struct_span_err(poly
.span
, "`?Trait` is not permitted in supertraits");
1477 let path_str
= pprust
::path_to_string(&poly
.trait_ref
.path
);
1478 err
.note(&format
!("traits are `?{}` by default", path_str
));
1481 (BoundKind
::TraitObject
, TraitBoundModifier
::Maybe
) => {
1482 let mut err
= self.err_handler().struct_span_err(
1484 "`?Trait` is not permitted in trait object types",
1488 (_
, TraitBoundModifier
::MaybeConst
) => {
1489 if !self.is_tilde_const_allowed
{
1491 .struct_span_err(bound
.span(), "`~const` is not allowed here")
1492 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1496 (_
, TraitBoundModifier
::MaybeConstMaybe
) => {
1498 .span_err(bound
.span(), "`~const` and `?` are mutually exclusive");
1504 visit
::walk_param_bound(self, bound
)
1507 fn visit_poly_trait_ref(&mut self, t
: &'a PolyTraitRef
, m
: &'a TraitBoundModifier
) {
1508 self.check_late_bound_lifetime_defs(&t
.bound_generic_params
);
1509 visit
::walk_poly_trait_ref(self, t
, m
);
1512 fn visit_variant_data(&mut self, s
: &'a VariantData
) {
1513 self.with_banned_assoc_ty_bound(|this
| visit
::walk_struct_def(this
, s
))
1518 enum_definition
: &'a EnumDef
,
1519 generics
: &'a Generics
,
1523 self.with_banned_assoc_ty_bound(|this
| {
1524 visit
::walk_enum_def(this
, enum_definition
, generics
, item_id
)
1528 fn visit_fn(&mut self, fk
: FnKind
<'a
>, span
: Span
, id
: NodeId
) {
1529 // Only associated `fn`s can have `self` parameters.
1530 let self_semantic
= match fk
.ctxt() {
1531 Some(FnCtxt
::Assoc(_
)) => SelfSemantic
::Yes
,
1532 _
=> SelfSemantic
::No
,
1534 self.check_fn_decl(fk
.decl(), self_semantic
);
1536 self.check_c_variadic_type(fk
);
1538 // Functions cannot both be `const async`
1539 if let Some(FnHeader
{
1540 constness
: Const
::Yes(cspan
),
1541 asyncness
: Async
::Yes { span: aspan, .. }
,
1547 vec
![*cspan
, *aspan
],
1548 "functions cannot be both `const` and `async`",
1550 .span_label(*cspan
, "`const` because of this")
1551 .span_label(*aspan
, "`async` because of this")
1552 .span_label(span
, "") // Point at the fn header.
1559 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }
, .. },
1565 self.maybe_lint_missing_abi(*sig_span
, id
);
1568 // Functions without bodies cannot have patterns.
1569 if let FnKind
::Fn(ctxt
, _
, sig
, _
, _
, None
) = fk
{
1570 Self::check_decl_no_pat(&sig
.decl
, |span
, ident
, mut_ident
| {
1571 let (code
, msg
, label
) = match ctxt
{
1572 FnCtxt
::Foreign
=> (
1574 "patterns aren't allowed in foreign function declarations",
1575 "pattern not allowed in foreign function",
1579 "patterns aren't allowed in functions without bodies",
1580 "pattern not allowed in function without body",
1583 if mut_ident
&& matches
!(ctxt
, FnCtxt
::Assoc(_
)) {
1584 if let Some(ident
) = ident
{
1585 let diag
= BuiltinLintDiagnostics
::PatternsInFnsWithoutBody(span
, ident
);
1586 self.lint_buffer
.buffer_lint_with_diagnostic(
1587 PATTERNS_IN_FNS_WITHOUT_BODY
,
1596 .struct_span_err(span
, msg
)
1597 .span_label(span
, label
)
1604 let tilde_const_allowed
=
1605 matches
!(fk
.header(), Some(FnHeader { constness: Const::Yes(_), .. }
))
1606 || matches
!(fk
.ctxt(), Some(FnCtxt
::Assoc(_
)));
1608 self.with_tilde_const(tilde_const_allowed
, |this
| visit
::walk_fn(this
, fk
, span
));
1611 fn visit_assoc_item(&mut self, item
: &'a AssocItem
, ctxt
: AssocCtxt
) {
1612 if self.session
.contains_name(&item
.attrs
, sym
::no_mangle
) {
1613 self.check_nomangle_item_asciionly(item
.ident
, item
.span
);
1616 if ctxt
== AssocCtxt
::Trait
|| !self.in_trait_impl
{
1617 self.check_defaultness(item
.span
, item
.kind
.defaultness());
1620 if ctxt
== AssocCtxt
::Impl
{
1622 AssocItemKind
::Const(_
, _
, body
) => {
1623 self.check_impl_item_provided(item
.span
, body
, "constant", " = <expr>;");
1625 AssocItemKind
::Fn(box Fn { body, .. }
) => {
1626 self.check_impl_item_provided(item
.span
, body
, "function", " { <body> }");
1628 AssocItemKind
::TyAlias(box TyAlias
{
1631 where_predicates_split
,
1636 self.check_impl_item_provided(item
.span
, ty
, "type", " = <type>;");
1637 self.check_type_no_bounds(bounds
, "`impl`s");
1639 self.check_gat_where(
1641 generics
.where_clause
.predicates
.split_at(*where_predicates_split
).0,
1650 if ctxt
== AssocCtxt
::Trait
|| self.in_trait_impl
{
1651 self.invalid_visibility(&item
.vis
, None
);
1652 if let AssocItemKind
::Fn(box Fn { sig, .. }
) = &item
.kind
{
1653 self.check_trait_fn_not_const(sig
.header
.constness
);
1654 self.check_trait_fn_not_async(item
.span
, sig
.header
.asyncness
);
1658 if let AssocItemKind
::Const(..) = item
.kind
{
1659 self.check_item_named(item
.ident
, "const");
1663 AssocItemKind
::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }
)
1664 if ctxt
== AssocCtxt
::Trait
=>
1666 self.visit_vis(&item
.vis
);
1667 self.visit_ident(item
.ident
);
1668 walk_list
!(self, visit_attribute
, &item
.attrs
);
1669 self.with_tilde_const_allowed(|this
| {
1670 this
.visit_generics(generics
);
1671 walk_list
!(this
, visit_param_bound
, bounds
, BoundKind
::Bound
);
1673 walk_list
!(self, visit_ty
, ty
);
1675 AssocItemKind
::Fn(box Fn { ref sig, ref generics, ref body, .. }
)
1676 if self.in_const_trait_impl
1677 || ctxt
== AssocCtxt
::Trait
1678 || matches
!(sig
.header
.constness
, Const
::Yes(_
)) =>
1680 self.visit_vis(&item
.vis
);
1681 self.visit_ident(item
.ident
);
1682 let kind
= FnKind
::Fn(
1683 FnCtxt
::Assoc(ctxt
),
1690 self.visit_fn(kind
, item
.span
, item
.id
);
1693 .with_in_trait_impl(false, None
, |this
| visit
::walk_assoc_item(this
, item
, ctxt
)),
1698 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1699 /// like it's setting an associated type, provide an appropriate suggestion.
1700 fn deny_equality_constraints(
1701 this
: &mut AstValidator
<'_
>,
1702 predicate
: &WhereEqPredicate
,
1703 generics
: &Generics
,
1705 let mut err
= this
.err_handler().struct_span_err(
1707 "equality constraints are not yet supported in `where` clauses",
1709 err
.span_label(predicate
.span
, "not supported");
1711 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1712 if let TyKind
::Path(Some(qself
), full_path
) = &predicate
.lhs_ty
.kind
{
1713 if let TyKind
::Path(None
, path
) = &qself
.ty
.kind
{
1714 match &path
.segments
[..] {
1715 [PathSegment { ident, args: None, .. }
] => {
1716 for param
in &generics
.params
{
1717 if param
.ident
== *ident
{
1719 match &full_path
.segments
[qself
.position
..] {
1720 [PathSegment { ident, args, .. }
] => {
1721 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1722 let mut assoc_path
= full_path
.clone();
1723 // Remove `Bar` from `Foo::Bar`.
1724 assoc_path
.segments
.pop();
1725 let len
= assoc_path
.segments
.len() - 1;
1726 let gen_args
= args
.as_ref().map(|p
| (**p
).clone());
1727 // Build `<Bar = RhsTy>`.
1728 let arg
= AngleBracketedArg
::Constraint(AssocConstraint
{
1729 id
: rustc_ast
::node_id
::DUMMY_NODE_ID
,
1732 kind
: AssocConstraintKind
::Equality
{
1733 term
: predicate
.rhs_ty
.clone().into(),
1737 // Add `<Bar = RhsTy>` to `Foo`.
1738 match &mut assoc_path
.segments
[len
].args
{
1739 Some(args
) => match args
.deref_mut() {
1740 GenericArgs
::Parenthesized(_
) => continue,
1741 GenericArgs
::AngleBracketed(args
) => {
1742 args
.args
.push(arg
);
1746 *empty_args
= AngleBracketedArgs
{
1753 err
.span_suggestion_verbose(
1756 "if `{}` is an associated type you're trying to set, \
1757 use the associated type binding syntax",
1763 pprust
::path_to_string(&assoc_path
)
1765 Applicability
::MaybeIncorrect
,
1777 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1778 if let TyKind
::Path(None
, full_path
) = &predicate
.lhs_ty
.kind
{
1779 if let [potential_param
, potential_assoc
] = &full_path
.segments
[..] {
1780 for param
in &generics
.params
{
1781 if param
.ident
== potential_param
.ident
{
1782 for bound
in ¶m
.bounds
{
1783 if let ast
::GenericBound
::Trait(trait_ref
, TraitBoundModifier
::None
) = bound
1785 if let [trait_segment
] = &trait_ref
.trait_ref
.path
.segments
[..] {
1786 let assoc
= pprust
::path_to_string(&ast
::Path
::from_ident(
1787 potential_assoc
.ident
,
1789 let ty
= pprust
::ty_to_string(&predicate
.rhs_ty
);
1790 let (args
, span
) = match &trait_segment
.args
{
1791 Some(args
) => match args
.deref() {
1792 ast
::GenericArgs
::AngleBracketed(args
) => {
1793 let Some(arg
) = args
.args
.last() else {
1797 format
!(", {} = {}", assoc
, ty
),
1798 arg
.span().shrink_to_hi(),
1804 format
!("<{} = {}>", assoc
, ty
),
1805 trait_segment
.span().shrink_to_hi(),
1808 err
.multipart_suggestion(
1810 "if `{}::{}` is an associated type you're trying to set, \
1811 use the associated type binding syntax",
1812 trait_segment
.ident
, potential_assoc
.ident
,
1814 vec
![(span
, args
), (predicate
.span
, String
::new())],
1815 Applicability
::MaybeIncorrect
,
1825 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1830 pub fn check_crate(session
: &Session
, krate
: &Crate
, lints
: &mut LintBuffer
) -> bool
{
1831 let mut validator
= AstValidator
{
1834 in_trait_impl
: false,
1835 in_const_trait_impl
: false,
1836 has_proc_macro_decls
: false,
1837 outer_impl_trait
: None
,
1838 is_tilde_const_allowed
: false,
1839 is_impl_trait_banned
: false,
1840 is_assoc_ty_bound_banned
: false,
1841 forbidden_let_reason
: Some(ForbiddenLetReason
::GenericForbidden
),
1844 visit
::walk_crate(&mut validator
, krate
);
1846 validator
.has_proc_macro_decls
1849 /// Used to forbid `let` expressions in certain syntactic locations.
1850 #[derive(Clone, Copy)]
1851 enum ForbiddenLetReason
{
1852 /// `let` is not valid and the source environment is not important
1854 /// A let chain with the `||` operator
1855 NotSupportedOr(Span
),
1856 /// A let chain with invalid parentheses
1858 /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
1859 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1860 NotSupportedParentheses(Span
),