rustc_ast_passes/
ast_validation.rs

1//! Validate AST before lowering it to HIR.
2//!
3//! This pass intends to check that the constructed AST is *syntactically valid* to allow the rest
4//! of the compiler to assume that the AST is valid. These checks cannot be performed during parsing
5//! because attribute macros are allowed to accept certain pieces of invalid syntax such as a
6//! function without body outside of a trait definition:
7//!
8//! ```ignore (illustrative)
9//! #[my_attribute]
10//! mod foo {
11//!     fn missing_body();
12//! }
13//! ```
14//!
15//! These checks are run post-expansion, after AST is frozen, to be able to check for erroneous
16//! constructions produced by proc macros. This pass is only intended for simple checks that do not
17//! require name resolution or type checking, or other kinds of complex analysis.
18
19use std::mem;
20use std::ops::{Deref, DerefMut};
21use std::str::FromStr;
22
23use itertools::{Either, Itertools};
24use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
25use rustc_ast::ptr::P;
26use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
27use rustc_ast::*;
28use rustc_ast_pretty::pprust::{self, State};
29use rustc_data_structures::fx::FxIndexMap;
30use rustc_errors::DiagCtxtHandle;
31use rustc_feature::Features;
32use rustc_parse::validate_attr;
33use rustc_session::Session;
34use rustc_session::lint::builtin::{
35    DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
36    PATTERNS_IN_FNS_WITHOUT_BODY,
37};
38use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
39use rustc_span::{Ident, Span, kw, sym};
40use rustc_target::spec::{AbiMap, AbiMapping};
41use thin_vec::thin_vec;
42
43use crate::errors::{self, TildeConstReason};
44
45/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
46enum SelfSemantic {
47    Yes,
48    No,
49}
50
51enum TraitOrTraitImpl {
52    Trait { span: Span, constness: Const },
53    TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
54}
55
56impl TraitOrTraitImpl {
57    fn constness(&self) -> Option<Span> {
58        match self {
59            Self::Trait { constness: Const::Yes(span), .. }
60            | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
61            _ => None,
62        }
63    }
64}
65
66struct AstValidator<'a> {
67    sess: &'a Session,
68    features: &'a Features,
69
70    /// The span of the `extern` in an `extern { ... }` block, if any.
71    extern_mod_span: Option<Span>,
72
73    outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
74
75    has_proc_macro_decls: bool,
76
77    /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
78    /// Nested `impl Trait` _is_ allowed in associated type position,
79    /// e.g., `impl Iterator<Item = impl Debug>`.
80    outer_impl_trait_span: Option<Span>,
81
82    disallow_tilde_const: Option<TildeConstReason>,
83
84    /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
85    extern_mod_safety: Option<Safety>,
86    extern_mod_abi: Option<ExternAbi>,
87
88    lint_node_id: NodeId,
89
90    is_sdylib_interface: bool,
91
92    lint_buffer: &'a mut LintBuffer,
93}
94
95impl<'a> AstValidator<'a> {
96    fn with_in_trait_impl(
97        &mut self,
98        trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
99        f: impl FnOnce(&mut Self),
100    ) {
101        let old = mem::replace(
102            &mut self.outer_trait_or_trait_impl,
103            trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
104                constness,
105                polarity,
106                trait_ref_span: trait_ref.path.span,
107            }),
108        );
109        f(self);
110        self.outer_trait_or_trait_impl = old;
111    }
112
113    fn with_in_trait(&mut self, span: Span, constness: Const, f: impl FnOnce(&mut Self)) {
114        let old = mem::replace(
115            &mut self.outer_trait_or_trait_impl,
116            Some(TraitOrTraitImpl::Trait { span, constness }),
117        );
118        f(self);
119        self.outer_trait_or_trait_impl = old;
120    }
121
122    fn with_in_extern_mod(
123        &mut self,
124        extern_mod_safety: Safety,
125        abi: Option<ExternAbi>,
126        f: impl FnOnce(&mut Self),
127    ) {
128        let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
129        let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
130        f(self);
131        self.extern_mod_safety = old_safety;
132        self.extern_mod_abi = old_abi;
133    }
134
135    fn with_tilde_const(
136        &mut self,
137        disallowed: Option<TildeConstReason>,
138        f: impl FnOnce(&mut Self),
139    ) {
140        let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
141        f(self);
142        self.disallow_tilde_const = old;
143    }
144
145    fn check_type_alias_where_clause_location(
146        &mut self,
147        ty_alias: &TyAlias,
148    ) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
149        if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token {
150            return Ok(());
151        }
152
153        let (before_predicates, after_predicates) =
154            ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split);
155        let span = ty_alias.where_clauses.before.span;
156
157        let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token
158        {
159            let mut state = State::new();
160
161            if !ty_alias.where_clauses.after.has_where_token {
162                state.space();
163                state.word_space("where");
164            }
165
166            let mut first = after_predicates.is_empty();
167            for p in before_predicates {
168                if !first {
169                    state.word_space(",");
170                }
171                first = false;
172                state.print_where_predicate(p);
173            }
174
175            errors::WhereClauseBeforeTypeAliasSugg::Move {
176                left: span,
177                snippet: state.s.eof(),
178                right: ty_alias.where_clauses.after.span.shrink_to_hi(),
179            }
180        } else {
181            errors::WhereClauseBeforeTypeAliasSugg::Remove { span }
182        };
183
184        Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
185    }
186
187    fn with_impl_trait(&mut self, outer_span: Option<Span>, f: impl FnOnce(&mut Self)) {
188        let old = mem::replace(&mut self.outer_impl_trait_span, outer_span);
189        f(self);
190        self.outer_impl_trait_span = old;
191    }
192
193    // Mirrors `visit::walk_ty`, but tracks relevant state.
194    fn walk_ty(&mut self, t: &'a Ty) {
195        match &t.kind {
196            TyKind::ImplTrait(_, bounds) => {
197                self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
198
199                // FIXME(precise_capturing): If we were to allow `use` in other positions
200                // (e.g. GATs), then we must validate those as well. However, we don't have
201                // a good way of doing this with the current `Visitor` structure.
202                let mut use_bounds = bounds
203                    .iter()
204                    .filter_map(|bound| match bound {
205                        GenericBound::Use(_, span) => Some(span),
206                        _ => None,
207                    })
208                    .copied();
209                if let Some(bound1) = use_bounds.next()
210                    && let Some(bound2) = use_bounds.next()
211                {
212                    self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 });
213                }
214            }
215            TyKind::TraitObject(..) => self
216                .with_tilde_const(Some(TildeConstReason::TraitObject), |this| {
217                    visit::walk_ty(this, t)
218                }),
219            _ => visit::walk_ty(self, t),
220        }
221    }
222
223    fn dcx(&self) -> DiagCtxtHandle<'a> {
224        self.sess.dcx()
225    }
226
227    fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
228        if let VisibilityKind::Inherited = vis.kind {
229            return;
230        }
231
232        self.dcx().emit_err(errors::VisibilityNotPermitted {
233            span: vis.span,
234            note,
235            remove_qualifier_sugg: vis.span,
236        });
237    }
238
239    fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
240        for Param { pat, .. } in &decl.inputs {
241            match pat.kind {
242                PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
243                PatKind::Ident(BindingMode::MUT, ident, None) => {
244                    report_err(pat.span, Some(ident), true)
245                }
246                _ => report_err(pat.span, None, false),
247            }
248        }
249    }
250
251    fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
252        let Const::Yes(span) = constness else {
253            return;
254        };
255
256        let const_trait_impl = self.features.const_trait_impl();
257        let make_impl_const_sugg = if const_trait_impl
258            && let TraitOrTraitImpl::TraitImpl {
259                constness: Const::No,
260                polarity: ImplPolarity::Positive,
261                trait_ref_span,
262                ..
263            } = parent
264        {
265            Some(trait_ref_span.shrink_to_lo())
266        } else {
267            None
268        };
269
270        let make_trait_const_sugg = if const_trait_impl
271            && let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent
272        {
273            Some(span.shrink_to_lo())
274        } else {
275            None
276        };
277
278        let parent_constness = parent.constness();
279        self.dcx().emit_err(errors::TraitFnConst {
280            span,
281            in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
282            const_context_label: parent_constness,
283            remove_const_sugg: (
284                self.sess.source_map().span_extend_while_whitespace(span),
285                match parent_constness {
286                    Some(_) => rustc_errors::Applicability::MachineApplicable,
287                    None => rustc_errors::Applicability::MaybeIncorrect,
288                },
289            ),
290            requires_multiple_changes: make_impl_const_sugg.is_some()
291                || make_trait_const_sugg.is_some(),
292            make_impl_const_sugg,
293            make_trait_const_sugg,
294        });
295    }
296
297    fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
298        self.check_decl_num_args(fn_decl);
299        self.check_decl_cvariadic_pos(fn_decl);
300        self.check_decl_attrs(fn_decl);
301        self.check_decl_self_param(fn_decl, self_semantic);
302    }
303
304    /// Emits fatal error if function declaration has more than `u16::MAX` arguments
305    /// Error is fatal to prevent errors during typechecking
306    fn check_decl_num_args(&self, fn_decl: &FnDecl) {
307        let max_num_args: usize = u16::MAX.into();
308        if fn_decl.inputs.len() > max_num_args {
309            let Param { span, .. } = fn_decl.inputs[0];
310            self.dcx().emit_fatal(errors::FnParamTooMany { span, max_num_args });
311        }
312    }
313
314    /// Emits an error if a function declaration has a variadic parameter in the
315    /// beginning or middle of parameter list.
316    /// Example: `fn foo(..., x: i32)` will emit an error.
317    fn check_decl_cvariadic_pos(&self, fn_decl: &FnDecl) {
318        match &*fn_decl.inputs {
319            [ps @ .., _] => {
320                for Param { ty, span, .. } in ps {
321                    if let TyKind::CVarArgs = ty.kind {
322                        self.dcx().emit_err(errors::FnParamCVarArgsNotLast { span: *span });
323                    }
324                }
325            }
326            _ => {}
327        }
328    }
329
330    fn check_decl_attrs(&self, fn_decl: &FnDecl) {
331        fn_decl
332            .inputs
333            .iter()
334            .flat_map(|i| i.attrs.as_ref())
335            .filter(|attr| {
336                let arr = [
337                    sym::allow,
338                    sym::cfg_trace,
339                    sym::cfg_attr_trace,
340                    sym::deny,
341                    sym::expect,
342                    sym::forbid,
343                    sym::warn,
344                ];
345                !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)
346            })
347            .for_each(|attr| {
348                if attr.is_doc_comment() {
349                    self.dcx().emit_err(errors::FnParamDocComment { span: attr.span });
350                } else {
351                    self.dcx().emit_err(errors::FnParamForbiddenAttr { span: attr.span });
352                }
353            });
354    }
355
356    fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
357        if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
358            if param.is_self() {
359                self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span });
360            }
361        }
362    }
363
364    /// Check that the signature of this function does not violate the constraints of its ABI.
365    fn check_extern_fn_signature(&self, abi: ExternAbi, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
366        match AbiMap::from_target(&self.sess.target).canonize_abi(abi, false) {
367            AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => {
368                match canon_abi {
369                    CanonAbi::C
370                    | CanonAbi::Rust
371                    | CanonAbi::RustCold
372                    | CanonAbi::Arm(_)
373                    | CanonAbi::GpuKernel
374                    | CanonAbi::X86(_) => { /* nothing to check */ }
375
376                    CanonAbi::Custom => {
377                        // An `extern "custom"` function must be unsafe.
378                        self.reject_safe_fn(abi, ctxt, sig);
379
380                        // An `extern "custom"` function cannot be `async` and/or `gen`.
381                        self.reject_coroutine(abi, sig);
382
383                        // An `extern "custom"` function must have type `fn()`.
384                        self.reject_params_or_return(abi, ident, sig);
385                    }
386
387                    CanonAbi::Interrupt(interrupt_kind) => {
388                        // An interrupt handler cannot be `async` and/or `gen`.
389                        self.reject_coroutine(abi, sig);
390
391                        if let InterruptKind::X86 = interrupt_kind {
392                            // "x86-interrupt" is special because it does have arguments.
393                            // FIXME(workingjubilee): properly lint on acceptable input types.
394                            if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
395                                self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
396                                    span: ret_ty.span,
397                                    abi,
398                                });
399                            }
400                        } else {
401                            // An `extern "interrupt"` function must have type `fn()`.
402                            self.reject_params_or_return(abi, ident, sig);
403                        }
404                    }
405                }
406            }
407            AbiMapping::Invalid => { /* ignore */ }
408        }
409    }
410
411    fn reject_safe_fn(&self, abi: ExternAbi, ctxt: FnCtxt, sig: &FnSig) {
412        let dcx = self.dcx();
413
414        match sig.header.safety {
415            Safety::Unsafe(_) => { /* all good */ }
416            Safety::Safe(safe_span) => {
417                let source_map = self.sess.psess.source_map();
418                let safe_span = source_map.span_until_non_whitespace(safe_span.to(sig.span));
419                dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
420            }
421            Safety::Default => match ctxt {
422                FnCtxt::Foreign => { /* all good */ }
423                FnCtxt::Free | FnCtxt::Assoc(_) => {
424                    dcx.emit_err(errors::AbiCustomSafeFunction {
425                        span: sig.span,
426                        abi,
427                        unsafe_span: sig.span.shrink_to_lo(),
428                    });
429                }
430            },
431        }
432    }
433
434    fn reject_coroutine(&self, abi: ExternAbi, sig: &FnSig) {
435        if let Some(coroutine_kind) = sig.header.coroutine_kind {
436            let coroutine_kind_span = self
437                .sess
438                .psess
439                .source_map()
440                .span_until_non_whitespace(coroutine_kind.span().to(sig.span));
441
442            self.dcx().emit_err(errors::AbiCannotBeCoroutine {
443                span: sig.span,
444                abi,
445                coroutine_kind_span,
446                coroutine_kind_str: coroutine_kind.as_str(),
447            });
448        }
449    }
450
451    fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
452        let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
453        if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
454            spans.push(ret_ty.span);
455        }
456
457        if !spans.is_empty() {
458            let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
459            let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
460            let padding = if header_span.is_empty() { "" } else { " " };
461
462            self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType {
463                spans,
464                symbol: ident.name,
465                suggestion_span,
466                padding,
467                abi,
468            });
469        }
470    }
471
472    /// This ensures that items can only be `unsafe` (or unmarked) outside of extern
473    /// blocks.
474    ///
475    /// This additionally ensures that within extern blocks, items can only be
476    /// `safe`/`unsafe` inside of a `unsafe`-adorned extern block.
477    fn check_item_safety(&self, span: Span, safety: Safety) {
478        match self.extern_mod_safety {
479            Some(extern_safety) => {
480                if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
481                    && extern_safety == Safety::Default
482                {
483                    self.dcx().emit_err(errors::InvalidSafetyOnExtern {
484                        item_span: span,
485                        block: Some(self.current_extern_span().shrink_to_lo()),
486                    });
487                }
488            }
489            None => {
490                if matches!(safety, Safety::Safe(_)) {
491                    self.dcx().emit_err(errors::InvalidSafetyOnItem { span });
492                }
493            }
494        }
495    }
496
497    fn check_fn_ptr_safety(&self, span: Span, safety: Safety) {
498        if matches!(safety, Safety::Safe(_)) {
499            self.dcx().emit_err(errors::InvalidSafetyOnFnPtr { span });
500        }
501    }
502
503    fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
504        if let Defaultness::Default(def_span) = defaultness {
505            let span = self.sess.source_map().guess_head_span(span);
506            self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
507        }
508    }
509
510    /// If `sp` ends with a semicolon, returns it as a `Span`
511    /// Otherwise, returns `sp.shrink_to_hi()`
512    fn ending_semi_or_hi(&self, sp: Span) -> Span {
513        let source_map = self.sess.source_map();
514        let end = source_map.end_point(sp);
515
516        if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") {
517            end
518        } else {
519            sp.shrink_to_hi()
520        }
521    }
522
523    fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
524        let span = match bounds {
525            [] => return,
526            [b0] => b0.span(),
527            [b0, .., bl] => b0.span().to(bl.span()),
528        };
529        self.dcx().emit_err(errors::BoundInContext { span, ctx });
530    }
531
532    fn check_foreign_ty_genericless(
533        &self,
534        generics: &Generics,
535        where_clauses: &TyAliasWhereClauses,
536    ) {
537        let cannot_have = |span, descr, remove_descr| {
538            self.dcx().emit_err(errors::ExternTypesCannotHave {
539                span,
540                descr,
541                remove_descr,
542                block_span: self.current_extern_span(),
543            });
544        };
545
546        if !generics.params.is_empty() {
547            cannot_have(generics.span, "generic parameters", "generic parameters");
548        }
549
550        let check_where_clause = |where_clause: TyAliasWhereClause| {
551            if where_clause.has_where_token {
552                cannot_have(where_clause.span, "`where` clauses", "`where` clause");
553            }
554        };
555
556        check_where_clause(where_clauses.before);
557        check_where_clause(where_clauses.after);
558    }
559
560    fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body_span: Option<Span>) {
561        let Some(body_span) = body_span else {
562            return;
563        };
564        self.dcx().emit_err(errors::BodyInExtern {
565            span: ident.span,
566            body: body_span,
567            block: self.current_extern_span(),
568            kind,
569        });
570    }
571
572    /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
573    fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
574        let Some(body) = body else {
575            return;
576        };
577        self.dcx().emit_err(errors::FnBodyInExtern {
578            span: ident.span,
579            body: body.span,
580            block: self.current_extern_span(),
581        });
582    }
583
584    fn current_extern_span(&self) -> Span {
585        self.sess.source_map().guess_head_span(self.extern_mod_span.unwrap())
586    }
587
588    /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
589    fn check_foreign_fn_headerless(
590        &self,
591        // Deconstruct to ensure exhaustiveness
592        FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader,
593    ) {
594        let report_err = |span, kw| {
595            self.dcx().emit_err(errors::FnQualifierInExtern {
596                span,
597                kw,
598                block: self.current_extern_span(),
599            });
600        };
601        match coroutine_kind {
602            Some(kind) => report_err(kind.span(), kind.as_str()),
603            None => (),
604        }
605        match constness {
606            Const::Yes(span) => report_err(span, "const"),
607            Const::No => (),
608        }
609        match ext {
610            Extern::None => (),
611            Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span, "extern"),
612        }
613    }
614
615    /// An item in `extern { ... }` cannot use non-ascii identifier.
616    fn check_foreign_item_ascii_only(&self, ident: Ident) {
617        if !ident.as_str().is_ascii() {
618            self.dcx().emit_err(errors::ExternItemAscii {
619                span: ident.span,
620                block: self.current_extern_span(),
621            });
622        }
623    }
624
625    /// Reject invalid C-variadic types.
626    ///
627    /// C-variadics must be:
628    /// - Non-const
629    /// - Either foreign, or free and `unsafe extern "C"` semantically
630    fn check_c_variadic_type(&self, fk: FnKind<'a>) {
631        let variadic_spans: Vec<_> = fk
632            .decl()
633            .inputs
634            .iter()
635            .filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
636            .map(|arg| arg.span)
637            .collect();
638
639        if variadic_spans.is_empty() {
640            return;
641        }
642
643        if let Some(header) = fk.header()
644            && let Const::Yes(const_span) = header.constness
645        {
646            let mut spans = variadic_spans.clone();
647            spans.push(const_span);
648            self.dcx().emit_err(errors::ConstAndCVariadic {
649                spans,
650                const_span,
651                variadic_spans: variadic_spans.clone(),
652            });
653        }
654
655        match (fk.ctxt(), fk.header()) {
656            (Some(FnCtxt::Foreign), _) => return,
657            (Some(FnCtxt::Free), Some(header)) => match header.ext {
658                Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
659                | Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _)
660                | Extern::Implicit(_)
661                    if matches!(header.safety, Safety::Unsafe(_)) =>
662                {
663                    return;
664                }
665                _ => {}
666            },
667            _ => {}
668        };
669
670        self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans });
671    }
672
673    fn check_item_named(&self, ident: Ident, kind: &str) {
674        if ident.name != kw::Underscore {
675            return;
676        }
677        self.dcx().emit_err(errors::ItemUnderscore { span: ident.span, kind });
678    }
679
680    fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
681        if ident.name.as_str().is_ascii() {
682            return;
683        }
684        let span = self.sess.source_map().guess_head_span(item_span);
685        self.dcx().emit_err(errors::NoMangleAscii { span });
686    }
687
688    fn check_mod_file_item_asciionly(&self, ident: Ident) {
689        if ident.name.as_str().is_ascii() {
690            return;
691        }
692        self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
693    }
694
695    fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
696        if !generics.params.is_empty() {
697            self.dcx()
698                .emit_err(errors::AutoTraitGeneric { span: generics.span, ident: ident_span });
699        }
700    }
701
702    fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
703        if let [.., last] = &bounds[..] {
704            let span = ident_span.shrink_to_hi().to(last.span());
705            self.dcx().emit_err(errors::AutoTraitBounds { span, ident: ident_span });
706        }
707    }
708
709    fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
710        if !where_clause.predicates.is_empty() {
711            // FIXME: The current diagnostic is misleading since it only talks about
712            // super trait and lifetime bounds while we should just say “bounds”.
713            self.dcx()
714                .emit_err(errors::AutoTraitBounds { span: where_clause.span, ident: ident_span });
715        }
716    }
717
718    fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
719        if !trait_items.is_empty() {
720            let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect();
721            let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
722            self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident: ident_span });
723        }
724    }
725
726    fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
727        // Lifetimes always come first.
728        let lt_sugg = data.args.iter().filter_map(|arg| match arg {
729            AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
730                Some(pprust::to_string(|s| s.print_generic_arg(lt)))
731            }
732            _ => None,
733        });
734        let args_sugg = data.args.iter().filter_map(|a| match a {
735            AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
736                None
737            }
738            AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
739        });
740        // Constraints always come last.
741        let constraint_sugg = data.args.iter().filter_map(|a| match a {
742            AngleBracketedArg::Arg(_) => None,
743            AngleBracketedArg::Constraint(c) => {
744                Some(pprust::to_string(|s| s.print_assoc_item_constraint(c)))
745            }
746        });
747        format!(
748            "<{}>",
749            lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
750        )
751    }
752
753    /// Enforce generic args coming before constraints in `<...>` of a path segment.
754    fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
755        // Early exit in case it's partitioned as it should be.
756        if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
757            return;
758        }
759        // Find all generic argument coming after the first constraint...
760        let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
761            data.args.iter().partition_map(|arg| match arg {
762                AngleBracketedArg::Constraint(c) => Either::Left(c.span),
763                AngleBracketedArg::Arg(a) => Either::Right(a.span()),
764            });
765        let args_len = arg_spans.len();
766        let constraint_len = constraint_spans.len();
767        // ...and then error:
768        self.dcx().emit_err(errors::ArgsBeforeConstraint {
769            arg_spans: arg_spans.clone(),
770            constraints: constraint_spans[0],
771            args: *arg_spans.iter().last().unwrap(),
772            data: data.span,
773            constraint_spans: errors::EmptyLabelManySpans(constraint_spans),
774            arg_spans2: errors::EmptyLabelManySpans(arg_spans),
775            suggestion: self.correct_generic_order_suggestion(data),
776            constraint_len,
777            args_len,
778        });
779    }
780
781    fn visit_ty_common(&mut self, ty: &'a Ty) {
782        match &ty.kind {
783            TyKind::FnPtr(bfty) => {
784                self.check_fn_ptr_safety(bfty.decl_span, bfty.safety);
785                self.check_fn_decl(&bfty.decl, SelfSemantic::No);
786                Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
787                    self.dcx().emit_err(errors::PatternFnPointer { span });
788                });
789                if let Extern::Implicit(extern_span) = bfty.ext {
790                    self.handle_missing_abi(extern_span, ty.id);
791                }
792            }
793            TyKind::TraitObject(bounds, ..) => {
794                let mut any_lifetime_bounds = false;
795                for bound in bounds {
796                    if let GenericBound::Outlives(lifetime) = bound {
797                        if any_lifetime_bounds {
798                            self.dcx()
799                                .emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
800                            break;
801                        }
802                        any_lifetime_bounds = true;
803                    }
804                }
805            }
806            TyKind::ImplTrait(_, bounds) => {
807                if let Some(outer_impl_trait_sp) = self.outer_impl_trait_span {
808                    self.dcx().emit_err(errors::NestedImplTrait {
809                        span: ty.span,
810                        outer: outer_impl_trait_sp,
811                        inner: ty.span,
812                    });
813                }
814
815                if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
816                    self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span });
817                }
818            }
819            _ => {}
820        }
821    }
822
823    fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
824        // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
825        // call site which do not have a macro backtrace. See #61963.
826        if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {
827            self.dcx().emit_err(errors::MissingAbi { span });
828        } else if self
829            .sess
830            .source_map()
831            .span_to_snippet(span)
832            .is_ok_and(|snippet| !snippet.starts_with("#["))
833        {
834            self.lint_buffer.buffer_lint(
835                MISSING_ABI,
836                id,
837                span,
838                BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK),
839            )
840        }
841    }
842
843    // Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
844    fn visit_attrs_vis(&mut self, attrs: &'a AttrVec, vis: &'a Visibility) {
845        walk_list!(self, visit_attribute, attrs);
846        self.visit_vis(vis);
847    }
848
849    // Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
850    fn visit_attrs_vis_ident(&mut self, attrs: &'a AttrVec, vis: &'a Visibility, ident: &'a Ident) {
851        walk_list!(self, visit_attribute, attrs);
852        self.visit_vis(vis);
853        self.visit_ident(ident);
854    }
855}
856
857/// Checks that generic parameters are in the correct order,
858/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
859fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericParam], span: Span) {
860    let mut max_param: Option<ParamKindOrd> = None;
861    let mut out_of_order = FxIndexMap::default();
862    let mut param_idents = Vec::with_capacity(generics.len());
863
864    for (idx, param) in generics.iter().enumerate() {
865        let ident = param.ident;
866        let (kind, bounds, span) = (&param.kind, &param.bounds, ident.span);
867        let (ord_kind, ident) = match &param.kind {
868            GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
869            GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),
870            GenericParamKind::Const { ty, .. } => {
871                let ty = pprust::ty_to_string(ty);
872                (ParamKindOrd::TypeOrConst, format!("const {ident}: {ty}"))
873            }
874        };
875        param_idents.push((kind, ord_kind, bounds, idx, ident));
876        match max_param {
877            Some(max_param) if max_param > ord_kind => {
878                let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
879                entry.1.push(span);
880            }
881            Some(_) | None => max_param = Some(ord_kind),
882        };
883    }
884
885    if !out_of_order.is_empty() {
886        let mut ordered_params = "<".to_string();
887        param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
888        let mut first = true;
889        for (kind, _, bounds, _, ident) in param_idents {
890            if !first {
891                ordered_params += ", ";
892            }
893            ordered_params += &ident;
894
895            if !bounds.is_empty() {
896                ordered_params += ": ";
897                ordered_params += &pprust::bounds_to_string(bounds);
898            }
899
900            match kind {
901                GenericParamKind::Type { default: Some(default) } => {
902                    ordered_params += " = ";
903                    ordered_params += &pprust::ty_to_string(default);
904                }
905                GenericParamKind::Type { default: None } => (),
906                GenericParamKind::Lifetime => (),
907                GenericParamKind::Const { ty: _, span: _, default: Some(default) } => {
908                    ordered_params += " = ";
909                    ordered_params += &pprust::expr_to_string(&default.value);
910                }
911                GenericParamKind::Const { ty: _, span: _, default: None } => (),
912            }
913            first = false;
914        }
915
916        ordered_params += ">";
917
918        for (param_ord, (max_param, spans)) in &out_of_order {
919            dcx.emit_err(errors::OutOfOrderParams {
920                spans: spans.clone(),
921                sugg_span: span,
922                param_ord,
923                max_param,
924                ordered_params: &ordered_params,
925            });
926        }
927    }
928}
929
930impl<'a> Visitor<'a> for AstValidator<'a> {
931    fn visit_attribute(&mut self, attr: &Attribute) {
932        validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id);
933    }
934
935    fn visit_ty(&mut self, ty: &'a Ty) {
936        self.visit_ty_common(ty);
937        self.walk_ty(ty)
938    }
939
940    fn visit_item(&mut self, item: &'a Item) {
941        if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
942            self.has_proc_macro_decls = true;
943        }
944
945        let previous_lint_node_id = mem::replace(&mut self.lint_node_id, item.id);
946
947        if let Some(ident) = item.kind.ident()
948            && attr::contains_name(&item.attrs, sym::no_mangle)
949        {
950            self.check_nomangle_item_asciionly(ident, item.span);
951        }
952
953        match &item.kind {
954            ItemKind::Impl(box Impl {
955                safety,
956                polarity,
957                defaultness: _,
958                constness,
959                generics,
960                of_trait: Some(t),
961                self_ty,
962                items,
963            }) => {
964                self.visit_attrs_vis(&item.attrs, &item.vis);
965                self.visibility_not_permitted(
966                    &item.vis,
967                    errors::VisibilityNotPermittedNote::TraitImpl,
968                );
969                if let TyKind::Dummy = self_ty.kind {
970                    // Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering,
971                    // which isn't allowed. Not a problem for this obscure, obsolete syntax.
972                    self.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });
973                }
974                if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity) {
975                    self.dcx().emit_err(errors::UnsafeNegativeImpl {
976                        span: sp.to(t.path.span),
977                        negative: sp,
978                        r#unsafe: span,
979                    });
980                }
981
982                let disallowed = matches!(constness, Const::No)
983                    .then(|| TildeConstReason::TraitImpl { span: item.span });
984                self.with_tilde_const(disallowed, |this| this.visit_generics(generics));
985                self.visit_trait_ref(t);
986                self.visit_ty(self_ty);
987
988                self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
989                    walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
990                });
991            }
992            ItemKind::Impl(box Impl {
993                safety,
994                polarity,
995                defaultness,
996                constness,
997                generics,
998                of_trait: None,
999                self_ty,
1000                items,
1001            }) => {
1002                let error = |annotation_span, annotation, only_trait| errors::InherentImplCannot {
1003                    span: self_ty.span,
1004                    annotation_span,
1005                    annotation,
1006                    self_ty: self_ty.span,
1007                    only_trait,
1008                };
1009
1010                self.visit_attrs_vis(&item.attrs, &item.vis);
1011                self.visibility_not_permitted(
1012                    &item.vis,
1013                    errors::VisibilityNotPermittedNote::IndividualImplItems,
1014                );
1015                if let &Safety::Unsafe(span) = safety {
1016                    self.dcx().emit_err(errors::InherentImplCannotUnsafe {
1017                        span: self_ty.span,
1018                        annotation_span: span,
1019                        annotation: "unsafe",
1020                        self_ty: self_ty.span,
1021                    });
1022                }
1023                if let &ImplPolarity::Negative(span) = polarity {
1024                    self.dcx().emit_err(error(span, "negative", false));
1025                }
1026                if let &Defaultness::Default(def_span) = defaultness {
1027                    self.dcx().emit_err(error(def_span, "`default`", true));
1028                }
1029                if let &Const::Yes(span) = constness {
1030                    self.dcx().emit_err(error(span, "`const`", true));
1031                }
1032
1033                self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
1034                    this.visit_generics(generics)
1035                });
1036                self.visit_ty(self_ty);
1037                self.with_in_trait_impl(None, |this| {
1038                    walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
1039                });
1040            }
1041            ItemKind::Fn(
1042                func @ box Fn {
1043                    defaultness,
1044                    ident,
1045                    generics: _,
1046                    sig,
1047                    contract: _,
1048                    body,
1049                    define_opaque: _,
1050                },
1051            ) => {
1052                self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
1053                self.check_defaultness(item.span, *defaultness);
1054
1055                let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
1056                if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
1057                    self.dcx().emit_err(errors::FnWithoutBody {
1058                        span: item.span,
1059                        replace_span: self.ending_semi_or_hi(item.span),
1060                        extern_block_suggestion: match sig.header.ext {
1061                            Extern::None => None,
1062                            Extern::Implicit(start_span) => {
1063                                Some(errors::ExternBlockSuggestion::Implicit {
1064                                    start_span,
1065                                    end_span: item.span.shrink_to_hi(),
1066                                })
1067                            }
1068                            Extern::Explicit(abi, start_span) => {
1069                                Some(errors::ExternBlockSuggestion::Explicit {
1070                                    start_span,
1071                                    end_span: item.span.shrink_to_hi(),
1072                                    abi: abi.symbol_unescaped,
1073                                })
1074                            }
1075                        },
1076                    });
1077                }
1078
1079                let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);
1080                self.visit_fn(kind, item.span, item.id);
1081            }
1082            ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {
1083                let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span));
1084                self.visibility_not_permitted(
1085                    &item.vis,
1086                    errors::VisibilityNotPermittedNote::IndividualForeignItems,
1087                );
1088
1089                if &Safety::Default == safety {
1090                    if item.span.at_least_rust_2024() {
1091                        self.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });
1092                    } else {
1093                        self.lint_buffer.buffer_lint(
1094                            MISSING_UNSAFE_ON_EXTERN,
1095                            item.id,
1096                            item.span,
1097                            BuiltinLintDiag::MissingUnsafeOnExtern {
1098                                suggestion: item.span.shrink_to_lo(),
1099                            },
1100                        );
1101                    }
1102                }
1103
1104                if abi.is_none() {
1105                    self.handle_missing_abi(*extern_span, item.id);
1106                }
1107
1108                let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok());
1109                self.with_in_extern_mod(*safety, extern_abi, |this| {
1110                    visit::walk_item(this, item);
1111                });
1112                self.extern_mod_span = old_item;
1113            }
1114            ItemKind::Enum(_, _, def) => {
1115                for variant in &def.variants {
1116                    self.visibility_not_permitted(
1117                        &variant.vis,
1118                        errors::VisibilityNotPermittedNote::EnumVariant,
1119                    );
1120                    for field in variant.data.fields() {
1121                        self.visibility_not_permitted(
1122                            &field.vis,
1123                            errors::VisibilityNotPermittedNote::EnumVariant,
1124                        );
1125                    }
1126                }
1127                visit::walk_item(self, item)
1128            }
1129            ItemKind::Trait(box Trait {
1130                constness,
1131                is_auto,
1132                generics,
1133                ident,
1134                bounds,
1135                items,
1136                ..
1137            }) => {
1138                self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
1139                // FIXME(const_trait_impl) remove this
1140                let alt_const_trait_span =
1141                    attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
1142                let constness = match (*constness, alt_const_trait_span) {
1143                    (Const::Yes(span), _) | (Const::No, Some(span)) => Const::Yes(span),
1144                    (Const::No, None) => Const::No,
1145                };
1146                if *is_auto == IsAuto::Yes {
1147                    // Auto traits cannot have generics, super traits nor contain items.
1148                    self.deny_generic_params(generics, ident.span);
1149                    self.deny_super_traits(bounds, ident.span);
1150                    self.deny_where_clause(&generics.where_clause, ident.span);
1151                    self.deny_items(items, ident.span);
1152                }
1153
1154                // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1155                // context for the supertraits.
1156                let disallowed = matches!(constness, ast::Const::No)
1157                    .then(|| TildeConstReason::Trait { span: item.span });
1158                self.with_tilde_const(disallowed, |this| {
1159                    this.visit_generics(generics);
1160                    walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
1161                });
1162                self.with_in_trait(item.span, constness, |this| {
1163                    walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
1164                });
1165            }
1166            ItemKind::Mod(safety, ident, mod_kind) => {
1167                if let &Safety::Unsafe(span) = safety {
1168                    self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
1169                }
1170                // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1171                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
1172                    && !attr::contains_name(&item.attrs, sym::path)
1173                {
1174                    self.check_mod_file_item_asciionly(*ident);
1175                }
1176                visit::walk_item(self, item)
1177            }
1178            ItemKind::Struct(ident, generics, vdata) => match vdata {
1179                VariantData::Struct { fields, .. } => {
1180                    self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
1181                    self.visit_generics(generics);
1182                    walk_list!(self, visit_field_def, fields);
1183                }
1184                _ => visit::walk_item(self, item),
1185            },
1186            ItemKind::Union(ident, generics, vdata) => {
1187                if vdata.fields().is_empty() {
1188                    self.dcx().emit_err(errors::FieldlessUnion { span: item.span });
1189                }
1190                match vdata {
1191                    VariantData::Struct { fields, .. } => {
1192                        self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
1193                        self.visit_generics(generics);
1194                        walk_list!(self, visit_field_def, fields);
1195                    }
1196                    _ => visit::walk_item(self, item),
1197                }
1198            }
1199            ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
1200                self.check_defaultness(item.span, *defaultness);
1201                if expr.is_none() {
1202                    self.dcx().emit_err(errors::ConstWithoutBody {
1203                        span: item.span,
1204                        replace_span: self.ending_semi_or_hi(item.span),
1205                    });
1206                }
1207                visit::walk_item(self, item);
1208            }
1209            ItemKind::Static(box StaticItem { expr, safety, .. }) => {
1210                self.check_item_safety(item.span, *safety);
1211                if matches!(safety, Safety::Unsafe(_)) {
1212                    self.dcx().emit_err(errors::UnsafeStatic { span: item.span });
1213                }
1214
1215                if expr.is_none() {
1216                    self.dcx().emit_err(errors::StaticWithoutBody {
1217                        span: item.span,
1218                        replace_span: self.ending_semi_or_hi(item.span),
1219                    });
1220                }
1221                visit::walk_item(self, item);
1222            }
1223            ItemKind::TyAlias(
1224                ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
1225            ) => {
1226                self.check_defaultness(item.span, *defaultness);
1227                if ty.is_none() {
1228                    self.dcx().emit_err(errors::TyAliasWithoutBody {
1229                        span: item.span,
1230                        replace_span: self.ending_semi_or_hi(item.span),
1231                    });
1232                }
1233                self.check_type_no_bounds(bounds, "this context");
1234
1235                if self.features.lazy_type_alias() {
1236                    if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
1237                        self.dcx().emit_err(err);
1238                    }
1239                } else if where_clauses.after.has_where_token {
1240                    self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
1241                        span: where_clauses.after.span,
1242                        help: self.sess.is_nightly_build(),
1243                    });
1244                }
1245                visit::walk_item(self, item);
1246            }
1247            _ => visit::walk_item(self, item),
1248        }
1249
1250        self.lint_node_id = previous_lint_node_id;
1251    }
1252
1253    fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1254        match &fi.kind {
1255            ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
1256                self.check_defaultness(fi.span, *defaultness);
1257                self.check_foreign_fn_bodyless(*ident, body.as_deref());
1258                self.check_foreign_fn_headerless(sig.header);
1259                self.check_foreign_item_ascii_only(*ident);
1260                self.check_extern_fn_signature(
1261                    self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK),
1262                    FnCtxt::Foreign,
1263                    ident,
1264                    sig,
1265                );
1266            }
1267            ForeignItemKind::TyAlias(box TyAlias {
1268                defaultness,
1269                ident,
1270                generics,
1271                where_clauses,
1272                bounds,
1273                ty,
1274                ..
1275            }) => {
1276                self.check_defaultness(fi.span, *defaultness);
1277                self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
1278                self.check_type_no_bounds(bounds, "`extern` blocks");
1279                self.check_foreign_ty_genericless(generics, where_clauses);
1280                self.check_foreign_item_ascii_only(*ident);
1281            }
1282            ForeignItemKind::Static(box StaticItem { ident, safety, expr, .. }) => {
1283                self.check_item_safety(fi.span, *safety);
1284                self.check_foreign_kind_bodyless(*ident, "static", expr.as_ref().map(|b| b.span));
1285                self.check_foreign_item_ascii_only(*ident);
1286            }
1287            ForeignItemKind::MacCall(..) => {}
1288        }
1289
1290        visit::walk_item(self, fi)
1291    }
1292
1293    // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1294    fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
1295        match generic_args {
1296            GenericArgs::AngleBracketed(data) => {
1297                self.check_generic_args_before_constraints(data);
1298
1299                for arg in &data.args {
1300                    match arg {
1301                        AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1302                        // Associated type bindings such as `Item = impl Debug` in
1303                        // `Iterator<Item = Debug>` are allowed to contain nested `impl Trait`.
1304                        AngleBracketedArg::Constraint(constraint) => {
1305                            self.with_impl_trait(None, |this| {
1306                                this.visit_assoc_item_constraint(constraint);
1307                            });
1308                        }
1309                    }
1310                }
1311            }
1312            GenericArgs::Parenthesized(data) => {
1313                walk_list!(self, visit_ty, &data.inputs);
1314                if let FnRetTy::Ty(ty) = &data.output {
1315                    // `-> Foo` syntax is essentially an associated type binding,
1316                    // so it is also allowed to contain nested `impl Trait`.
1317                    self.with_impl_trait(None, |this| this.visit_ty(ty));
1318                }
1319            }
1320            GenericArgs::ParenthesizedElided(_span) => {}
1321        }
1322    }
1323
1324    fn visit_generics(&mut self, generics: &'a Generics) {
1325        let mut prev_param_default = None;
1326        for param in &generics.params {
1327            match param.kind {
1328                GenericParamKind::Lifetime => (),
1329                GenericParamKind::Type { default: Some(_), .. }
1330                | GenericParamKind::Const { default: Some(_), .. } => {
1331                    prev_param_default = Some(param.ident.span);
1332                }
1333                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1334                    if let Some(span) = prev_param_default {
1335                        self.dcx().emit_err(errors::GenericDefaultTrailing { span });
1336                        break;
1337                    }
1338                }
1339            }
1340        }
1341
1342        validate_generic_param_order(self.dcx(), &generics.params, generics.span);
1343
1344        for predicate in &generics.where_clause.predicates {
1345            let span = predicate.span;
1346            if let WherePredicateKind::EqPredicate(predicate) = &predicate.kind {
1347                deny_equality_constraints(self, predicate, span, generics);
1348            }
1349        }
1350        walk_list!(self, visit_generic_param, &generics.params);
1351        for predicate in &generics.where_clause.predicates {
1352            match &predicate.kind {
1353                WherePredicateKind::BoundPredicate(bound_pred) => {
1354                    // This is slightly complicated. Our representation for poly-trait-refs contains a single
1355                    // binder and thus we only allow a single level of quantification. However,
1356                    // the syntax of Rust permits quantification in two places in where clauses,
1357                    // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1358                    // defined, then error.
1359                    if !bound_pred.bound_generic_params.is_empty() {
1360                        for bound in &bound_pred.bounds {
1361                            match bound {
1362                                GenericBound::Trait(t) => {
1363                                    if !t.bound_generic_params.is_empty() {
1364                                        self.dcx()
1365                                            .emit_err(errors::NestedLifetimes { span: t.span });
1366                                    }
1367                                }
1368                                GenericBound::Outlives(_) => {}
1369                                GenericBound::Use(..) => {}
1370                            }
1371                        }
1372                    }
1373                }
1374                _ => {}
1375            }
1376            self.visit_where_predicate(predicate);
1377        }
1378    }
1379
1380    fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1381        match bound {
1382            GenericBound::Trait(trait_ref) => {
1383                match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
1384                    (
1385                        BoundKind::TraitObject,
1386                        BoundConstness::Always(_),
1387                        BoundPolarity::Positive,
1388                    ) => {
1389                        self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span });
1390                    }
1391                    (_, BoundConstness::Maybe(span), BoundPolarity::Positive)
1392                        if let Some(reason) = self.disallow_tilde_const =>
1393                    {
1394                        self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
1395                    }
1396                    _ => {}
1397                }
1398
1399                // Negative trait bounds are not allowed to have associated constraints
1400                if let BoundPolarity::Negative(_) = trait_ref.modifiers.polarity
1401                    && let Some(segment) = trait_ref.trait_ref.path.segments.last()
1402                {
1403                    match segment.args.as_deref() {
1404                        Some(ast::GenericArgs::AngleBracketed(args)) => {
1405                            for arg in &args.args {
1406                                if let ast::AngleBracketedArg::Constraint(constraint) = arg {
1407                                    self.dcx().emit_err(errors::ConstraintOnNegativeBound {
1408                                        span: constraint.span,
1409                                    });
1410                                }
1411                            }
1412                        }
1413                        // The lowered form of parenthesized generic args contains an associated type binding.
1414                        Some(ast::GenericArgs::Parenthesized(args)) => {
1415                            self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
1416                                span: args.span,
1417                            });
1418                        }
1419                        Some(ast::GenericArgs::ParenthesizedElided(_)) | None => {}
1420                    }
1421                }
1422            }
1423            GenericBound::Outlives(_) => {}
1424            GenericBound::Use(_, span) => match ctxt {
1425                BoundKind::Impl => {}
1426                BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => {
1427                    self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere {
1428                        loc: ctxt.descr(),
1429                        span: *span,
1430                    });
1431                }
1432            },
1433        }
1434
1435        visit::walk_param_bound(self, bound)
1436    }
1437
1438    fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1439        // Only associated `fn`s can have `self` parameters.
1440        let self_semantic = match fk.ctxt() {
1441            Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1442            _ => SelfSemantic::No,
1443        };
1444        self.check_fn_decl(fk.decl(), self_semantic);
1445
1446        if let Some(&FnHeader { safety, .. }) = fk.header() {
1447            self.check_item_safety(span, safety);
1448        }
1449
1450        if let FnKind::Fn(ctxt, _, fun) = fk
1451            && let Extern::Explicit(str_lit, _) = fun.sig.header.ext
1452            && let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str())
1453        {
1454            self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
1455        }
1456
1457        self.check_c_variadic_type(fk);
1458
1459        // Functions cannot both be `const async` or `const gen`
1460        if let Some(&FnHeader {
1461            constness: Const::Yes(const_span),
1462            coroutine_kind: Some(coroutine_kind),
1463            ..
1464        }) = fk.header()
1465        {
1466            self.dcx().emit_err(errors::ConstAndCoroutine {
1467                spans: vec![coroutine_kind.span(), const_span],
1468                const_span,
1469                coroutine_span: coroutine_kind.span(),
1470                coroutine_kind: coroutine_kind.as_str(),
1471                span,
1472            });
1473        }
1474
1475        if let FnKind::Fn(
1476            _,
1477            _,
1478            Fn {
1479                sig: FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. },
1480                ..
1481            },
1482        ) = fk
1483        {
1484            self.handle_missing_abi(*extern_span, id);
1485        }
1486
1487        // Functions without bodies cannot have patterns.
1488        if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk {
1489            Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1490                if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1491                    if let Some(ident) = ident {
1492                        self.lint_buffer.buffer_lint(
1493                            PATTERNS_IN_FNS_WITHOUT_BODY,
1494                            id,
1495                            span,
1496                            BuiltinLintDiag::PatternsInFnsWithoutBody {
1497                                span,
1498                                ident,
1499                                is_foreign: matches!(ctxt, FnCtxt::Foreign),
1500                            },
1501                        )
1502                    }
1503                } else {
1504                    match ctxt {
1505                        FnCtxt::Foreign => self.dcx().emit_err(errors::PatternInForeign { span }),
1506                        _ => self.dcx().emit_err(errors::PatternInBodiless { span }),
1507                    };
1508                }
1509            });
1510        }
1511
1512        let tilde_const_allowed =
1513            matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1514                || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
1515                    && self
1516                        .outer_trait_or_trait_impl
1517                        .as_ref()
1518                        .and_then(TraitOrTraitImpl::constness)
1519                        .is_some();
1520
1521        let disallowed = (!tilde_const_allowed).then(|| match fk {
1522            FnKind::Fn(_, _, f) => TildeConstReason::Function { ident: f.ident.span },
1523            FnKind::Closure(..) => TildeConstReason::Closure,
1524        });
1525        self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
1526    }
1527
1528    fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1529        if let Some(ident) = item.kind.ident()
1530            && attr::contains_name(&item.attrs, sym::no_mangle)
1531        {
1532            self.check_nomangle_item_asciionly(ident, item.span);
1533        }
1534
1535        if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
1536            self.check_defaultness(item.span, item.kind.defaultness());
1537        }
1538
1539        if let AssocCtxt::Impl { .. } = ctxt {
1540            match &item.kind {
1541                AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
1542                    self.dcx().emit_err(errors::AssocConstWithoutBody {
1543                        span: item.span,
1544                        replace_span: self.ending_semi_or_hi(item.span),
1545                    });
1546                }
1547                AssocItemKind::Fn(box Fn { body, .. }) => {
1548                    if body.is_none() && !self.is_sdylib_interface {
1549                        self.dcx().emit_err(errors::AssocFnWithoutBody {
1550                            span: item.span,
1551                            replace_span: self.ending_semi_or_hi(item.span),
1552                        });
1553                    }
1554                }
1555                AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
1556                    if ty.is_none() {
1557                        self.dcx().emit_err(errors::AssocTypeWithoutBody {
1558                            span: item.span,
1559                            replace_span: self.ending_semi_or_hi(item.span),
1560                        });
1561                    }
1562                    self.check_type_no_bounds(bounds, "`impl`s");
1563                }
1564                _ => {}
1565            }
1566        }
1567
1568        if let AssocItemKind::Type(ty_alias) = &item.kind
1569            && let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
1570        {
1571            let sugg = match err.sugg {
1572                errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
1573                errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
1574                    Some((right, snippet))
1575                }
1576            };
1577            self.lint_buffer.buffer_lint(
1578                DEPRECATED_WHERE_CLAUSE_LOCATION,
1579                item.id,
1580                err.span,
1581                BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
1582            );
1583        }
1584
1585        if let Some(parent) = &self.outer_trait_or_trait_impl {
1586            self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
1587            if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1588                self.check_trait_fn_not_const(sig.header.constness, parent);
1589            }
1590        }
1591
1592        if let AssocItemKind::Const(ci) = &item.kind {
1593            self.check_item_named(ci.ident, "const");
1594        }
1595
1596        let parent_is_const =
1597            self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
1598
1599        match &item.kind {
1600            AssocItemKind::Fn(func)
1601                if parent_is_const
1602                    || ctxt == AssocCtxt::Trait
1603                    || matches!(func.sig.header.constness, Const::Yes(_)) =>
1604            {
1605                self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);
1606                let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);
1607                self.visit_fn(kind, item.span, item.id);
1608            }
1609            AssocItemKind::Type(_) => {
1610                let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
1611                    Some(TraitOrTraitImpl::Trait { .. }) => {
1612                        TildeConstReason::TraitAssocTy { span: item.span }
1613                    }
1614                    Some(TraitOrTraitImpl::TraitImpl { .. }) => {
1615                        TildeConstReason::TraitImplAssocTy { span: item.span }
1616                    }
1617                    None => TildeConstReason::InherentAssocTy { span: item.span },
1618                });
1619                self.with_tilde_const(disallowed, |this| {
1620                    this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
1621                })
1622            }
1623            _ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
1624        }
1625    }
1626}
1627
1628/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1629/// like it's setting an associated type, provide an appropriate suggestion.
1630fn deny_equality_constraints(
1631    this: &AstValidator<'_>,
1632    predicate: &WhereEqPredicate,
1633    predicate_span: Span,
1634    generics: &Generics,
1635) {
1636    let mut err = errors::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None };
1637
1638    // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1639    if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind
1640        && let TyKind::Path(None, path) = &qself.ty.kind
1641        && let [PathSegment { ident, args: None, .. }] = &path.segments[..]
1642    {
1643        for param in &generics.params {
1644            if param.ident == *ident
1645                && let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..]
1646            {
1647                // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1648                let mut assoc_path = full_path.clone();
1649                // Remove `Bar` from `Foo::Bar`.
1650                assoc_path.segments.pop();
1651                let len = assoc_path.segments.len() - 1;
1652                let gen_args = args.as_deref().cloned();
1653                // Build `<Bar = RhsTy>`.
1654                let arg = AngleBracketedArg::Constraint(AssocItemConstraint {
1655                    id: rustc_ast::node_id::DUMMY_NODE_ID,
1656                    ident: *ident,
1657                    gen_args,
1658                    kind: AssocItemConstraintKind::Equality {
1659                        term: predicate.rhs_ty.clone().into(),
1660                    },
1661                    span: ident.span,
1662                });
1663                // Add `<Bar = RhsTy>` to `Foo`.
1664                match &mut assoc_path.segments[len].args {
1665                    Some(args) => match args.deref_mut() {
1666                        GenericArgs::Parenthesized(_) | GenericArgs::ParenthesizedElided(..) => {
1667                            continue;
1668                        }
1669                        GenericArgs::AngleBracketed(args) => {
1670                            args.args.push(arg);
1671                        }
1672                    },
1673                    empty_args => {
1674                        *empty_args = Some(
1675                            AngleBracketedArgs { span: ident.span, args: thin_vec![arg] }.into(),
1676                        );
1677                    }
1678                }
1679                err.assoc = Some(errors::AssociatedSuggestion {
1680                    span: predicate_span,
1681                    ident: *ident,
1682                    param: param.ident,
1683                    path: pprust::path_to_string(&assoc_path),
1684                })
1685            }
1686        }
1687    }
1688
1689    let mut suggest =
1690        |poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| {
1691            if let [trait_segment] = &poly.trait_ref.path.segments[..] {
1692                let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident));
1693                let ty = pprust::ty_to_string(&predicate.rhs_ty);
1694                let (args, span) = match &trait_segment.args {
1695                    Some(args) => match args.deref() {
1696                        ast::GenericArgs::AngleBracketed(args) => {
1697                            let Some(arg) = args.args.last() else {
1698                                return;
1699                            };
1700                            (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
1701                        }
1702                        _ => return,
1703                    },
1704                    None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()),
1705                };
1706                let removal_span = if generics.where_clause.predicates.len() == 1 {
1707                    // We're removing th eonly where bound left, remove the whole thing.
1708                    generics.where_clause.span
1709                } else {
1710                    let mut span = predicate_span;
1711                    let mut prev_span: Option<Span> = None;
1712                    let mut preds = generics.where_clause.predicates.iter().peekable();
1713                    // Find the predicate that shouldn't have been in the where bound list.
1714                    while let Some(pred) = preds.next() {
1715                        if let WherePredicateKind::EqPredicate(_) = pred.kind
1716                            && pred.span == predicate_span
1717                        {
1718                            if let Some(next) = preds.peek() {
1719                                // This is the first predicate, remove the trailing comma as well.
1720                                span = span.with_hi(next.span.lo());
1721                            } else if let Some(prev_span) = prev_span {
1722                                // Remove the previous comma as well.
1723                                span = span.with_lo(prev_span.hi());
1724                            }
1725                        }
1726                        prev_span = Some(pred.span);
1727                    }
1728                    span
1729                };
1730                err.assoc2 = Some(errors::AssociatedSuggestion2 {
1731                    span,
1732                    args,
1733                    predicate: removal_span,
1734                    trait_segment: trait_segment.ident,
1735                    potential_assoc: potential_assoc.ident,
1736                });
1737            }
1738        };
1739
1740    if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1741        // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1742        for bounds in generics.params.iter().map(|p| &p.bounds).chain(
1743            generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
1744                WherePredicateKind::BoundPredicate(p) => Some(&p.bounds),
1745                _ => None,
1746            }),
1747        ) {
1748            for bound in bounds {
1749                if let GenericBound::Trait(poly) = bound
1750                    && poly.modifiers == TraitBoundModifiers::NONE
1751                {
1752                    if full_path.segments[..full_path.segments.len() - 1]
1753                        .iter()
1754                        .map(|segment| segment.ident.name)
1755                        .zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
1756                        .all(|(a, b)| a == b)
1757                        && let Some(potential_assoc) = full_path.segments.iter().last()
1758                    {
1759                        suggest(poly, potential_assoc, predicate);
1760                    }
1761                }
1762            }
1763        }
1764        // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1765        if let [potential_param, potential_assoc] = &full_path.segments[..] {
1766            for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
1767                generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
1768                    WherePredicateKind::BoundPredicate(p)
1769                        if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
1770                            && let [segment] = &path.segments[..] =>
1771                    {
1772                        Some((segment.ident, &p.bounds))
1773                    }
1774                    _ => None,
1775                }),
1776            ) {
1777                if ident == potential_param.ident {
1778                    for bound in bounds {
1779                        if let ast::GenericBound::Trait(poly) = bound
1780                            && poly.modifiers == TraitBoundModifiers::NONE
1781                        {
1782                            suggest(poly, potential_assoc, predicate);
1783                        }
1784                    }
1785                }
1786            }
1787        }
1788    }
1789    this.dcx().emit_err(err);
1790}
1791
1792pub fn check_crate(
1793    sess: &Session,
1794    features: &Features,
1795    krate: &Crate,
1796    is_sdylib_interface: bool,
1797    lints: &mut LintBuffer,
1798) -> bool {
1799    let mut validator = AstValidator {
1800        sess,
1801        features,
1802        extern_mod_span: None,
1803        outer_trait_or_trait_impl: None,
1804        has_proc_macro_decls: false,
1805        outer_impl_trait_span: None,
1806        disallow_tilde_const: Some(TildeConstReason::Item),
1807        extern_mod_safety: None,
1808        extern_mod_abi: None,
1809        lint_node_id: CRATE_NODE_ID,
1810        is_sdylib_interface,
1811        lint_buffer: lints,
1812    };
1813    visit::walk_crate(&mut validator, krate);
1814
1815    validator.has_proc_macro_decls
1816}