1 // Validate AST before lowering it to HIR.
2 //
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.
8
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::*;
13 use rustc_ast::{walk_list, StaticItem};
14 use rustc_ast_pretty::pprust::{self, State};
15 use rustc_data_structures::fx::FxIndexMap;
16 use rustc_macros::Subdiagnostic;
17 use rustc_parse::validate_attr;
18 use rustc_session::lint::builtin::{
19 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
20 };
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};
25 use rustc_span::Span;
26 use rustc_target::spec::abi;
27 use std::mem;
28 use std::ops::{Deref, DerefMut};
29 use thin_vec::thin_vec;
30
31 use crate::errors;
32 use crate::fluent_generated as fluent;
33
34 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
35 enum SelfSemantic {
36 Yes,
37 No,
38 }
39
40 /// What is the context that prevents using `~const`?
41 enum DisallowTildeConstContext<'a> {
42 TraitObject,
43 Fn(FnKind<'a>),
44 }
45
46 struct AstValidator<'a> {
47 session: &'a Session,
48
49 /// The span of the `extern` in an `extern { ... }` block, if any.
50 extern_mod: Option<&'a Item>,
51
52 /// Are we inside a trait impl?
53 in_trait_impl: bool,
54
55 in_const_trait_impl: bool,
56
57 has_proc_macro_decls: bool,
58
59 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
60 /// Nested `impl Trait` _is_ allowed in associated type position,
61 /// e.g., `impl Iterator<Item = impl Debug>`.
62 outer_impl_trait: Option<Span>,
63
64 disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
65
66 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
67 /// or `Foo::Bar<impl Trait>`
68 is_impl_trait_banned: bool,
69
70 /// See [ForbiddenLetReason]
71 forbidden_let_reason: Option<ForbiddenLetReason>,
72
73 lint_buffer: &'a mut LintBuffer,
74 }
75
76 impl<'a> AstValidator<'a> {
with_in_trait_impl( &mut self, is_in: bool, constness: Option<Const>, f: impl FnOnce(&mut Self), )77 fn with_in_trait_impl(
78 &mut self,
79 is_in: bool,
80 constness: Option<Const>,
81 f: impl FnOnce(&mut Self),
82 ) {
83 let old = mem::replace(&mut self.in_trait_impl, is_in);
84 let old_const =
85 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
86 f(self);
87 self.in_trait_impl = old;
88 self.in_const_trait_impl = old_const;
89 }
90
with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self))91 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
92 let old = mem::replace(&mut self.is_impl_trait_banned, true);
93 f(self);
94 self.is_impl_trait_banned = old;
95 }
96
with_tilde_const( &mut self, disallowed: Option<DisallowTildeConstContext<'a>>, f: impl FnOnce(&mut Self), )97 fn with_tilde_const(
98 &mut self,
99 disallowed: Option<DisallowTildeConstContext<'a>>,
100 f: impl FnOnce(&mut Self),
101 ) {
102 let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
103 f(self);
104 self.disallow_tilde_const = old;
105 }
106
with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self))107 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
108 self.with_tilde_const(None, f)
109 }
110
with_banned_tilde_const( &mut self, ctx: DisallowTildeConstContext<'a>, f: impl FnOnce(&mut Self), )111 fn with_banned_tilde_const(
112 &mut self,
113 ctx: DisallowTildeConstContext<'a>,
114 f: impl FnOnce(&mut Self),
115 ) {
116 self.with_tilde_const(Some(ctx), f)
117 }
118
with_let_management( &mut self, forbidden_let_reason: Option<ForbiddenLetReason>, f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>), )119 fn with_let_management(
120 &mut self,
121 forbidden_let_reason: Option<ForbiddenLetReason>,
122 f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
123 ) {
124 let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
125 f(self, old);
126 self.forbidden_let_reason = old;
127 }
128
129 /// Emits an error banning the `let` expression provided in the given location.
ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason)130 fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
131 let sess = &self.session;
132 if sess.opts.unstable_features.is_nightly_build() {
133 sess.emit_err(errors::ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
134 } else {
135 sess.emit_err(errors::ForbiddenLetStable { span: expr.span });
136 }
137 }
138
check_gat_where( &mut self, id: NodeId, before_predicates: &[WherePredicate], where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause), )139 fn check_gat_where(
140 &mut self,
141 id: NodeId,
142 before_predicates: &[WherePredicate],
143 where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
144 ) {
145 if !before_predicates.is_empty() {
146 let mut state = State::new();
147 if !where_clauses.1.0 {
148 state.space();
149 state.word_space("where");
150 } else {
151 state.word_space(",");
152 }
153 let mut first = true;
154 for p in before_predicates.iter() {
155 if !first {
156 state.word_space(",");
157 }
158 first = false;
159 state.print_where_predicate(p);
160 }
161 let suggestion = state.s.eof();
162 self.lint_buffer.buffer_lint_with_diagnostic(
163 DEPRECATED_WHERE_CLAUSE_LOCATION,
164 id,
165 where_clauses.0.1,
166 fluent::ast_passes_deprecated_where_clause_location,
167 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
168 where_clauses.1.1.shrink_to_hi(),
169 suggestion,
170 ),
171 );
172 }
173 }
174
with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self))175 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
176 let old = mem::replace(&mut self.outer_impl_trait, outer);
177 f(self);
178 self.outer_impl_trait = old;
179 }
180
181 // Mirrors `visit::walk_ty`, but tracks relevant state.
walk_ty(&mut self, t: &'a Ty)182 fn walk_ty(&mut self, t: &'a Ty) {
183 match &t.kind {
184 TyKind::ImplTrait(..) => {
185 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
186 }
187 TyKind::TraitObject(..) => self
188 .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
189 visit::walk_ty(this, t)
190 }),
191 TyKind::Path(qself, path) => {
192 // We allow these:
193 // - `Option<impl Trait>`
194 // - `option::Option<impl Trait>`
195 // - `option::Option<T>::Foo<impl Trait>`
196 //
197 // But not these:
198 // - `<impl Trait>::Foo`
199 // - `option::Option<impl Trait>::Foo`.
200 //
201 // To implement this, we disallow `impl Trait` from `qself`
202 // (for cases like `<impl Trait>::Foo>`)
203 // but we allow `impl Trait` in `GenericArgs`
204 // iff there are no more PathSegments.
205 if let Some(qself) = qself {
206 // `impl Trait` in `qself` is always illegal
207 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
208 }
209
210 // Note that there should be a call to visit_path here,
211 // so if any logic is added to process `Path`s a call to it should be
212 // added both in visit_path and here. This code mirrors visit::walk_path.
213 for (i, segment) in path.segments.iter().enumerate() {
214 // Allow `impl Trait` iff we're on the final path segment
215 if i == path.segments.len() - 1 {
216 self.visit_path_segment(segment);
217 } else {
218 self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
219 }
220 }
221 }
222 _ => visit::walk_ty(self, t),
223 }
224 }
225
err_handler(&self) -> &rustc_errors::Handler226 fn err_handler(&self) -> &rustc_errors::Handler {
227 &self.session.diagnostic()
228 }
229
check_lifetime(&self, ident: Ident)230 fn check_lifetime(&self, ident: Ident) {
231 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
232 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
233 self.session.emit_err(errors::KeywordLifetime { span: ident.span });
234 }
235 }
236
check_label(&self, ident: Ident)237 fn check_label(&self, ident: Ident) {
238 if ident.without_first_quote().is_reserved() {
239 self.session.emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
240 }
241 }
242
visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote)243 fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
244 if let VisibilityKind::Inherited = vis.kind {
245 return;
246 }
247
248 self.session.emit_err(errors::VisibilityNotPermitted { span: vis.span, note });
249 }
250
check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool))251 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
252 for Param { pat, .. } in &decl.inputs {
253 match pat.kind {
254 PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {}
255 PatKind::Ident(BindingAnnotation::MUT, ident, None) => {
256 report_err(pat.span, Some(ident), true)
257 }
258 _ => report_err(pat.span, None, false),
259 }
260 }
261 }
262
check_trait_fn_not_const(&self, constness: Const)263 fn check_trait_fn_not_const(&self, constness: Const) {
264 if let Const::Yes(span) = constness {
265 self.session.emit_err(errors::TraitFnConst { span });
266 }
267 }
268
check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic)269 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
270 self.check_decl_num_args(fn_decl);
271 self.check_decl_cvaradic_pos(fn_decl);
272 self.check_decl_attrs(fn_decl);
273 self.check_decl_self_param(fn_decl, self_semantic);
274 }
275
276 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
277 /// Error is fatal to prevent errors during typechecking
check_decl_num_args(&self, fn_decl: &FnDecl)278 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
279 let max_num_args: usize = u16::MAX.into();
280 if fn_decl.inputs.len() > max_num_args {
281 let Param { span, .. } = fn_decl.inputs[0];
282 self.session.emit_fatal(errors::FnParamTooMany { span, max_num_args });
283 }
284 }
285
check_decl_cvaradic_pos(&self, fn_decl: &FnDecl)286 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
287 match &*fn_decl.inputs {
288 [Param { ty, span, .. }] => {
289 if let TyKind::CVarArgs = ty.kind {
290 self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span });
291 }
292 }
293 [ps @ .., _] => {
294 for Param { ty, span, .. } in ps {
295 if let TyKind::CVarArgs = ty.kind {
296 self.session.emit_err(errors::FnParamCVarArgsNotLast { span: *span });
297 }
298 }
299 }
300 _ => {}
301 }
302 }
303
check_decl_attrs(&self, fn_decl: &FnDecl)304 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
305 fn_decl
306 .inputs
307 .iter()
308 .flat_map(|i| i.attrs.as_ref())
309 .filter(|attr| {
310 let arr = [
311 sym::allow,
312 sym::cfg,
313 sym::cfg_attr,
314 sym::deny,
315 sym::expect,
316 sym::forbid,
317 sym::warn,
318 ];
319 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
320 })
321 .for_each(|attr| {
322 if attr.is_doc_comment() {
323 self.session.emit_err(errors::FnParamDocComment { span: attr.span });
324 } else {
325 self.session.emit_err(errors::FnParamForbiddenAttr { span: attr.span });
326 }
327 });
328 }
329
check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic)330 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
331 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
332 if param.is_self() {
333 self.session.emit_err(errors::FnParamForbiddenSelf { span: param.span });
334 }
335 }
336 }
337
check_defaultness(&self, span: Span, defaultness: Defaultness)338 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
339 if let Defaultness::Default(def_span) = defaultness {
340 let span = self.session.source_map().guess_head_span(span);
341 self.session.emit_err(errors::ForbiddenDefault { span, def_span });
342 }
343 }
344
345 /// If `sp` ends with a semicolon, returns it as a `Span`
346 /// Otherwise, returns `sp.shrink_to_hi()`
ending_semi_or_hi(&self, sp: Span) -> Span347 fn ending_semi_or_hi(&self, sp: Span) -> Span {
348 let source_map = self.session.source_map();
349 let end = source_map.end_point(sp);
350
351 if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") {
352 end
353 } else {
354 sp.shrink_to_hi()
355 }
356 }
357
check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str)358 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
359 let span = match bounds {
360 [] => return,
361 [b0] => b0.span(),
362 [b0, .., bl] => b0.span().to(bl.span()),
363 };
364 self.err_handler().emit_err(errors::BoundInContext { span, ctx });
365 }
366
check_foreign_ty_genericless( &self, generics: &Generics, before_where_clause: &TyAliasWhereClause, after_where_clause: &TyAliasWhereClause, )367 fn check_foreign_ty_genericless(
368 &self,
369 generics: &Generics,
370 before_where_clause: &TyAliasWhereClause,
371 after_where_clause: &TyAliasWhereClause,
372 ) {
373 let cannot_have = |span, descr, remove_descr| {
374 self.err_handler().emit_err(errors::ExternTypesCannotHave {
375 span,
376 descr,
377 remove_descr,
378 block_span: self.current_extern_span(),
379 });
380 };
381
382 if !generics.params.is_empty() {
383 cannot_have(generics.span, "generic parameters", "generic parameters");
384 }
385
386 let check_where_clause = |where_clause: &TyAliasWhereClause| {
387 if let TyAliasWhereClause(true, where_clause_span) = where_clause {
388 cannot_have(*where_clause_span, "`where` clauses", "`where` clause");
389 }
390 };
391
392 check_where_clause(before_where_clause);
393 check_where_clause(after_where_clause);
394 }
395
check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>)396 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
397 let Some(body) = body else {
398 return;
399 };
400 self.err_handler().emit_err(errors::BodyInExtern {
401 span: ident.span,
402 body,
403 block: self.current_extern_span(),
404 kind,
405 });
406 }
407
408 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>)409 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
410 let Some(body) = body else {
411 return;
412 };
413 self.err_handler().emit_err(errors::FnBodyInExtern {
414 span: ident.span,
415 body: body.span,
416 block: self.current_extern_span(),
417 });
418 }
419
current_extern_span(&self) -> Span420 fn current_extern_span(&self) -> Span {
421 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
422 }
423
424 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader)425 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
426 if header.has_qualifiers() {
427 self.err_handler().emit_err(errors::FnQualifierInExtern {
428 span: ident.span,
429 block: self.current_extern_span(),
430 sugg_span: span.until(ident.span.shrink_to_lo()),
431 });
432 }
433 }
434
435 /// An item in `extern { ... }` cannot use non-ascii identifier.
check_foreign_item_ascii_only(&self, ident: Ident)436 fn check_foreign_item_ascii_only(&self, ident: Ident) {
437 if !ident.as_str().is_ascii() {
438 self.err_handler().emit_err(errors::ExternItemAscii {
439 span: ident.span,
440 block: self.current_extern_span(),
441 });
442 }
443 }
444
445 /// Reject C-variadic type unless the function is foreign,
446 /// or free and `unsafe extern "C"` semantically.
check_c_variadic_type(&self, fk: FnKind<'a>)447 fn check_c_variadic_type(&self, fk: FnKind<'a>) {
448 match (fk.ctxt(), fk.header()) {
449 (Some(FnCtxt::Foreign), _) => return,
450 (Some(FnCtxt::Free), Some(header)) => match header.ext {
451 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
452 | Extern::Implicit(_)
453 if matches!(header.unsafety, Unsafe::Yes(_)) =>
454 {
455 return;
456 }
457 _ => {}
458 },
459 _ => {}
460 };
461
462 for Param { ty, span, .. } in &fk.decl().inputs {
463 if let TyKind::CVarArgs = ty.kind {
464 self.err_handler().emit_err(errors::BadCVariadic { span: *span });
465 }
466 }
467 }
468
check_item_named(&self, ident: Ident, kind: &str)469 fn check_item_named(&self, ident: Ident, kind: &str) {
470 if ident.name != kw::Underscore {
471 return;
472 }
473 self.err_handler().emit_err(errors::ItemUnderscore { span: ident.span, kind });
474 }
475
check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span)476 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
477 if ident.name.as_str().is_ascii() {
478 return;
479 }
480 let span = self.session.source_map().guess_head_span(item_span);
481 self.session.emit_err(errors::NoMangleAscii { span });
482 }
483
check_mod_file_item_asciionly(&self, ident: Ident)484 fn check_mod_file_item_asciionly(&self, ident: Ident) {
485 if ident.name.as_str().is_ascii() {
486 return;
487 }
488 self.session.emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
489 }
490
deny_generic_params(&self, generics: &Generics, ident: Span)491 fn deny_generic_params(&self, generics: &Generics, ident: Span) {
492 if !generics.params.is_empty() {
493 self.session.emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
494 }
495 }
496
emit_e0568(&self, span: Span, ident: Span)497 fn emit_e0568(&self, span: Span, ident: Span) {
498 self.session.emit_err(errors::AutoTraitBounds { span, ident });
499 }
500
deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span)501 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
502 if let [.., last] = &bounds[..] {
503 let span = ident_span.shrink_to_hi().to(last.span());
504 self.emit_e0568(span, ident_span);
505 }
506 }
507
deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span)508 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
509 if !where_clause.predicates.is_empty() {
510 self.emit_e0568(where_clause.span, ident_span);
511 }
512 }
513
deny_items(&self, trait_items: &[P<AssocItem>], ident: Span)514 fn deny_items(&self, trait_items: &[P<AssocItem>], ident: Span) {
515 if !trait_items.is_empty() {
516 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
517 let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
518 self.session.emit_err(errors::AutoTraitItems { spans, total, ident });
519 }
520 }
521
correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String522 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
523 // Lifetimes always come first.
524 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
525 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
526 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
527 }
528 _ => None,
529 });
530 let args_sugg = data.args.iter().filter_map(|a| match a {
531 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
532 None
533 }
534 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
535 });
536 // Constraints always come last.
537 let constraint_sugg = data.args.iter().filter_map(|a| match a {
538 AngleBracketedArg::Arg(_) => None,
539 AngleBracketedArg::Constraint(c) => {
540 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
541 }
542 });
543 format!(
544 "<{}>",
545 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
546 )
547 }
548
549 /// Enforce generic args coming before constraints in `<...>` of a path segment.
check_generic_args_before_constraints(&self, data: &AngleBracketedArgs)550 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
551 // Early exit in case it's partitioned as it should be.
552 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
553 return;
554 }
555 // Find all generic argument coming after the first constraint...
556 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
557 data.args.iter().partition_map(|arg| match arg {
558 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
559 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
560 });
561 let args_len = arg_spans.len();
562 let constraint_len = constraint_spans.len();
563 // ...and then error:
564 self.err_handler().emit_err(errors::ArgsBeforeConstraint {
565 arg_spans: arg_spans.clone(),
566 constraints: constraint_spans[0],
567 args: *arg_spans.iter().last().unwrap(),
568 data: data.span,
569 constraint_spans: errors::EmptyLabelManySpans(constraint_spans),
570 arg_spans2: errors::EmptyLabelManySpans(arg_spans),
571 suggestion: self.correct_generic_order_suggestion(&data),
572 constraint_len,
573 args_len,
574 });
575 }
576
visit_ty_common(&mut self, ty: &'a Ty)577 fn visit_ty_common(&mut self, ty: &'a Ty) {
578 match &ty.kind {
579 TyKind::BareFn(bfty) => {
580 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
581 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
582 self.session.emit_err(errors::PatternFnPointer { span });
583 });
584 if let Extern::Implicit(_) = bfty.ext {
585 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
586 self.maybe_lint_missing_abi(sig_span, ty.id);
587 }
588 }
589 TyKind::TraitObject(bounds, ..) => {
590 let mut any_lifetime_bounds = false;
591 for bound in bounds {
592 if let GenericBound::Outlives(lifetime) = bound {
593 if any_lifetime_bounds {
594 self.session
595 .emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
596 break;
597 }
598 any_lifetime_bounds = true;
599 }
600 }
601 }
602 TyKind::ImplTrait(_, bounds) => {
603 if self.is_impl_trait_banned {
604 self.session.emit_err(errors::ImplTraitPath { span: ty.span });
605 }
606
607 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
608 self.session.emit_err(errors::NestedImplTrait {
609 span: ty.span,
610 outer: outer_impl_trait_sp,
611 inner: ty.span,
612 });
613 }
614
615 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
616 self.err_handler().emit_err(errors::AtLeastOneTrait { span: ty.span });
617 }
618 }
619 _ => {}
620 }
621 }
622
maybe_lint_missing_abi(&mut self, span: Span, id: NodeId)623 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
624 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
625 // call site which do not have a macro backtrace. See #61963.
626 if self
627 .session
628 .source_map()
629 .span_to_snippet(span)
630 .is_ok_and(|snippet| !snippet.starts_with("#["))
631 {
632 self.lint_buffer.buffer_lint_with_diagnostic(
633 MISSING_ABI,
634 id,
635 span,
636 fluent::ast_passes_extern_without_abi,
637 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
638 )
639 }
640 }
641 }
642
643 /// Checks that generic parameters are in the correct order,
644 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
validate_generic_param_order( handler: &rustc_errors::Handler, generics: &[GenericParam], span: Span, )645 fn validate_generic_param_order(
646 handler: &rustc_errors::Handler,
647 generics: &[GenericParam],
648 span: Span,
649 ) {
650 let mut max_param: Option<ParamKindOrd> = None;
651 let mut out_of_order = FxIndexMap::default();
652 let mut param_idents = Vec::with_capacity(generics.len());
653
654 for (idx, param) in generics.iter().enumerate() {
655 let ident = param.ident;
656 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
657 let (ord_kind, ident) = match ¶m.kind {
658 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
659 GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),
660 GenericParamKind::Const { ty, .. } => {
661 let ty = pprust::ty_to_string(ty);
662 (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
663 }
664 };
665 param_idents.push((kind, ord_kind, bounds, idx, ident));
666 match max_param {
667 Some(max_param) if max_param > ord_kind => {
668 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
669 entry.1.push(span);
670 }
671 Some(_) | None => max_param = Some(ord_kind),
672 };
673 }
674
675 if !out_of_order.is_empty() {
676 let mut ordered_params = "<".to_string();
677 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
678 let mut first = true;
679 for (kind, _, bounds, _, ident) in param_idents {
680 if !first {
681 ordered_params += ", ";
682 }
683 ordered_params += &ident;
684
685 if !bounds.is_empty() {
686 ordered_params += ": ";
687 ordered_params += &pprust::bounds_to_string(&bounds);
688 }
689
690 match kind {
691 GenericParamKind::Type { default: Some(default) } => {
692 ordered_params += " = ";
693 ordered_params += &pprust::ty_to_string(default);
694 }
695 GenericParamKind::Type { default: None } => (),
696 GenericParamKind::Lifetime => (),
697 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
698 ordered_params += " = ";
699 ordered_params += &pprust::expr_to_string(&default.value);
700 }
701 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
702 }
703 first = false;
704 }
705
706 ordered_params += ">";
707
708 for (param_ord, (max_param, spans)) in &out_of_order {
709 handler.emit_err(errors::OutOfOrderParams {
710 spans: spans.clone(),
711 sugg_span: span,
712 param_ord,
713 max_param,
714 ordered_params: &ordered_params,
715 });
716 }
717 }
718 }
719
720 impl<'a> Visitor<'a> for AstValidator<'a> {
visit_attribute(&mut self, attr: &Attribute)721 fn visit_attribute(&mut self, attr: &Attribute) {
722 validate_attr::check_attr(&self.session.parse_sess, attr);
723 }
724
visit_expr(&mut self, expr: &'a Expr)725 fn visit_expr(&mut self, expr: &'a Expr) {
726 self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
727 match &expr.kind {
728 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
729 let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
730 this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
731 this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
732 }
733 ExprKind::If(cond, then, opt_else) => {
734 this.visit_block(then);
735 walk_list!(this, visit_expr, opt_else);
736 this.with_let_management(None, |this, _| this.visit_expr(cond));
737 return;
738 }
739 ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
740 this.ban_let_expr(expr, elem);
741 },
742 ExprKind::Match(scrutinee, arms) => {
743 this.visit_expr(scrutinee);
744 for arm in arms {
745 this.visit_expr(&arm.body);
746 this.visit_pat(&arm.pat);
747 walk_list!(this, visit_attribute, &arm.attrs);
748 if let Some(guard) = &arm.guard {
749 this.with_let_management(None, |this, _| {
750 this.visit_expr(guard)
751 });
752 }
753 }
754 }
755 ExprKind::Paren(local_expr) => {
756 fn has_let_expr(expr: &Expr) -> bool {
757 match &expr.kind {
758 ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
759 ExprKind::Let(..) => true,
760 _ => false,
761 }
762 }
763 let local_reason = if has_let_expr(local_expr) {
764 Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
765 }
766 else {
767 forbidden_let_reason
768 };
769 this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
770 }
771 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
772 this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
773 return;
774 }
775 ExprKind::While(cond, then, opt_label) => {
776 walk_list!(this, visit_label, opt_label);
777 this.visit_block(then);
778 this.with_let_management(None, |this, _| this.visit_expr(cond));
779 return;
780 }
781 _ => visit::walk_expr(this, expr),
782 }
783 });
784 }
785
visit_ty(&mut self, ty: &'a Ty)786 fn visit_ty(&mut self, ty: &'a Ty) {
787 self.visit_ty_common(ty);
788 self.walk_ty(ty)
789 }
790
visit_label(&mut self, label: &'a Label)791 fn visit_label(&mut self, label: &'a Label) {
792 self.check_label(label.ident);
793 visit::walk_label(self, label);
794 }
795
visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt)796 fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
797 self.check_lifetime(lifetime.ident);
798 visit::walk_lifetime(self, lifetime);
799 }
800
visit_field_def(&mut self, field: &'a FieldDef)801 fn visit_field_def(&mut self, field: &'a FieldDef) {
802 visit::walk_field_def(self, field)
803 }
804
visit_item(&mut self, item: &'a Item)805 fn visit_item(&mut self, item: &'a Item) {
806 if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
807 self.has_proc_macro_decls = true;
808 }
809
810 if attr::contains_name(&item.attrs, sym::no_mangle) {
811 self.check_nomangle_item_asciionly(item.ident, item.span);
812 }
813
814 match &item.kind {
815 ItemKind::Impl(box Impl {
816 unsafety,
817 polarity,
818 defaultness: _,
819 constness,
820 generics,
821 of_trait: Some(t),
822 self_ty,
823 items,
824 }) => {
825 self.with_in_trait_impl(true, Some(*constness), |this| {
826 this.visibility_not_permitted(
827 &item.vis,
828 errors::VisibilityNotPermittedNote::TraitImpl,
829 );
830 if let TyKind::Err = self_ty.kind {
831 this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span });
832 }
833 if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
834 {
835 this.session.emit_err(errors::UnsafeNegativeImpl {
836 span: sp.to(t.path.span),
837 negative: sp,
838 r#unsafe: span,
839 });
840 }
841
842 this.visit_vis(&item.vis);
843 this.visit_ident(item.ident);
844 if let Const::Yes(_) = constness {
845 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
846 } else {
847 this.visit_generics(generics);
848 }
849 this.visit_trait_ref(t);
850 this.visit_ty(self_ty);
851
852 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
853 });
854 walk_list!(self, visit_attribute, &item.attrs);
855 return; // Avoid visiting again.
856 }
857 ItemKind::Impl(box Impl {
858 unsafety,
859 polarity,
860 defaultness,
861 constness,
862 generics: _,
863 of_trait: None,
864 self_ty,
865 items: _,
866 }) => {
867 let error =
868 |annotation_span, annotation, only_trait: bool| errors::InherentImplCannot {
869 span: self_ty.span,
870 annotation_span,
871 annotation,
872 self_ty: self_ty.span,
873 only_trait: only_trait.then_some(()),
874 };
875
876 self.visibility_not_permitted(
877 &item.vis,
878 errors::VisibilityNotPermittedNote::IndividualImplItems,
879 );
880 if let &Unsafe::Yes(span) = unsafety {
881 self.err_handler().emit_err(errors::InherentImplCannotUnsafe {
882 span: self_ty.span,
883 annotation_span: span,
884 annotation: "unsafe",
885 self_ty: self_ty.span,
886 });
887 }
888 if let &ImplPolarity::Negative(span) = polarity {
889 self.err_handler().emit_err(error(span, "negative", false));
890 }
891 if let &Defaultness::Default(def_span) = defaultness {
892 self.err_handler().emit_err(error(def_span, "`default`", true));
893 }
894 if let &Const::Yes(span) = constness {
895 self.err_handler().emit_err(error(span, "`const`", true));
896 }
897 }
898 ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
899 self.check_defaultness(item.span, *defaultness);
900
901 if body.is_none() {
902 self.session.emit_err(errors::FnWithoutBody {
903 span: item.span,
904 replace_span: self.ending_semi_or_hi(item.span),
905 extern_block_suggestion: match sig.header.ext {
906 Extern::None => None,
907 Extern::Implicit(start_span) => {
908 Some(errors::ExternBlockSuggestion::Implicit {
909 start_span,
910 end_span: item.span.shrink_to_hi(),
911 })
912 }
913 Extern::Explicit(abi, start_span) => {
914 Some(errors::ExternBlockSuggestion::Explicit {
915 start_span,
916 end_span: item.span.shrink_to_hi(),
917 abi: abi.symbol_unescaped,
918 })
919 }
920 },
921 });
922 }
923
924 self.visit_vis(&item.vis);
925 self.visit_ident(item.ident);
926 let kind =
927 FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
928 self.visit_fn(kind, item.span, item.id);
929 walk_list!(self, visit_attribute, &item.attrs);
930 return; // Avoid visiting again.
931 }
932 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
933 let old_item = mem::replace(&mut self.extern_mod, Some(item));
934 self.visibility_not_permitted(
935 &item.vis,
936 errors::VisibilityNotPermittedNote::IndividualForeignItems,
937 );
938 if let &Unsafe::Yes(span) = unsafety {
939 self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" });
940 }
941 if abi.is_none() {
942 self.maybe_lint_missing_abi(item.span, item.id);
943 }
944 visit::walk_item(self, item);
945 self.extern_mod = old_item;
946 return; // Avoid visiting again.
947 }
948 ItemKind::Enum(def, _) => {
949 for variant in &def.variants {
950 self.visibility_not_permitted(
951 &variant.vis,
952 errors::VisibilityNotPermittedNote::EnumVariant,
953 );
954 for field in variant.data.fields() {
955 self.visibility_not_permitted(
956 &field.vis,
957 errors::VisibilityNotPermittedNote::EnumVariant,
958 );
959 }
960 }
961 }
962 ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
963 if *is_auto == IsAuto::Yes {
964 // Auto traits cannot have generics, super traits nor contain items.
965 self.deny_generic_params(generics, item.ident.span);
966 self.deny_super_traits(bounds, item.ident.span);
967 self.deny_where_clause(&generics.where_clause, item.ident.span);
968 self.deny_items(items, item.ident.span);
969 }
970
971 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
972 // context for the supertraits.
973 self.visit_vis(&item.vis);
974 self.visit_ident(item.ident);
975 self.visit_generics(generics);
976 self.with_tilde_const_allowed(|this| {
977 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
978 });
979 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
980 walk_list!(self, visit_attribute, &item.attrs);
981 return; // Avoid visiting again
982 }
983 ItemKind::Mod(unsafety, mod_kind) => {
984 if let &Unsafe::Yes(span) = unsafety {
985 self.err_handler().emit_err(errors::UnsafeItem { span, kind: "module" });
986 }
987 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
988 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
989 && !attr::contains_name(&item.attrs, sym::path)
990 {
991 self.check_mod_file_item_asciionly(item.ident);
992 }
993 }
994 ItemKind::Union(vdata, ..) => {
995 if vdata.fields().is_empty() {
996 self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
997 }
998 }
999 ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => {
1000 self.check_defaultness(item.span, *defaultness);
1001 self.session.emit_err(errors::ConstWithoutBody {
1002 span: item.span,
1003 replace_span: self.ending_semi_or_hi(item.span),
1004 });
1005 }
1006 ItemKind::Static(box StaticItem { expr: None, .. }) => {
1007 self.session.emit_err(errors::StaticWithoutBody {
1008 span: item.span,
1009 replace_span: self.ending_semi_or_hi(item.span),
1010 });
1011 }
1012 ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
1013 self.check_defaultness(item.span, *defaultness);
1014 if ty.is_none() {
1015 self.session.emit_err(errors::TyAliasWithoutBody {
1016 span: item.span,
1017 replace_span: self.ending_semi_or_hi(item.span),
1018 });
1019 }
1020 self.check_type_no_bounds(bounds, "this context");
1021 if where_clauses.1.0 {
1022 self.err_handler()
1023 .emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 });
1024 }
1025 }
1026 _ => {}
1027 }
1028
1029 visit::walk_item(self, item);
1030 }
1031
visit_foreign_item(&mut self, fi: &'a ForeignItem)1032 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1033 match &fi.kind {
1034 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1035 self.check_defaultness(fi.span, *defaultness);
1036 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1037 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1038 self.check_foreign_item_ascii_only(fi.ident);
1039 }
1040 ForeignItemKind::TyAlias(box TyAlias {
1041 defaultness,
1042 generics,
1043 where_clauses,
1044 bounds,
1045 ty,
1046 ..
1047 }) => {
1048 self.check_defaultness(fi.span, *defaultness);
1049 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1050 self.check_type_no_bounds(bounds, "`extern` blocks");
1051 self.check_foreign_ty_genericless(generics, &where_clauses.0, &where_clauses.1);
1052 self.check_foreign_item_ascii_only(fi.ident);
1053 }
1054 ForeignItemKind::Static(_, _, body) => {
1055 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1056 self.check_foreign_item_ascii_only(fi.ident);
1057 }
1058 ForeignItemKind::MacCall(..) => {}
1059 }
1060
1061 visit::walk_foreign_item(self, fi)
1062 }
1063
1064 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
visit_generic_args(&mut self, generic_args: &'a GenericArgs)1065 fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
1066 match generic_args {
1067 GenericArgs::AngleBracketed(data) => {
1068 self.check_generic_args_before_constraints(data);
1069
1070 for arg in &data.args {
1071 match arg {
1072 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1073 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1074 // are allowed to contain nested `impl Trait`.
1075 AngleBracketedArg::Constraint(constraint) => {
1076 self.with_impl_trait(None, |this| {
1077 this.visit_assoc_constraint(constraint);
1078 });
1079 }
1080 }
1081 }
1082 }
1083 GenericArgs::Parenthesized(data) => {
1084 walk_list!(self, visit_ty, &data.inputs);
1085 if let FnRetTy::Ty(ty) = &data.output {
1086 // `-> Foo` syntax is essentially an associated type binding,
1087 // so it is also allowed to contain nested `impl Trait`.
1088 self.with_impl_trait(None, |this| this.visit_ty(ty));
1089 }
1090 }
1091 }
1092 }
1093
visit_generics(&mut self, generics: &'a Generics)1094 fn visit_generics(&mut self, generics: &'a Generics) {
1095 let mut prev_param_default = None;
1096 for param in &generics.params {
1097 match param.kind {
1098 GenericParamKind::Lifetime => (),
1099 GenericParamKind::Type { default: Some(_), .. }
1100 | GenericParamKind::Const { default: Some(_), .. } => {
1101 prev_param_default = Some(param.ident.span);
1102 }
1103 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1104 if let Some(span) = prev_param_default {
1105 self.err_handler().emit_err(errors::GenericDefaultTrailing { span });
1106 break;
1107 }
1108 }
1109 }
1110 }
1111
1112 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1113
1114 for predicate in &generics.where_clause.predicates {
1115 if let WherePredicate::EqPredicate(predicate) = predicate {
1116 deny_equality_constraints(self, predicate, generics);
1117 }
1118 }
1119 walk_list!(self, visit_generic_param, &generics.params);
1120 for predicate in &generics.where_clause.predicates {
1121 match predicate {
1122 WherePredicate::BoundPredicate(bound_pred) => {
1123 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1124 // binder and thus we only allow a single level of quantification. However,
1125 // the syntax of Rust permits quantification in two places in where clauses,
1126 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1127 // defined, then error.
1128 if !bound_pred.bound_generic_params.is_empty() {
1129 for bound in &bound_pred.bounds {
1130 match bound {
1131 GenericBound::Trait(t, _) => {
1132 if !t.bound_generic_params.is_empty() {
1133 self.err_handler()
1134 .emit_err(errors::NestedLifetimes { span: t.span });
1135 }
1136 }
1137 GenericBound::Outlives(_) => {}
1138 }
1139 }
1140 }
1141 }
1142 _ => {}
1143 }
1144 self.visit_where_predicate(predicate);
1145 }
1146 }
1147
visit_generic_param(&mut self, param: &'a GenericParam)1148 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1149 if let GenericParamKind::Lifetime { .. } = param.kind {
1150 self.check_lifetime(param.ident);
1151 }
1152 visit::walk_generic_param(self, param);
1153 }
1154
visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind)1155 fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1156 if let GenericBound::Trait(poly, modify) = bound {
1157 match (ctxt, modify) {
1158 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1159 self.err_handler().emit_err(errors::OptionalTraitSupertrait {
1160 span: poly.span,
1161 path_str: pprust::path_to_string(&poly.trait_ref.path)
1162 });
1163 }
1164 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1165 self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span});
1166 }
1167 (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
1168 let reason = match reason {
1169 DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject,
1170 DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure,
1171 DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span },
1172 };
1173 self.err_handler().emit_err(errors::TildeConstDisallowed {
1174 span: bound.span(),
1175 reason
1176 });
1177 }
1178 (_, TraitBoundModifier::MaybeConstMaybe) => {
1179 self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "?" });
1180 }
1181 (_, TraitBoundModifier::MaybeConstNegative) => {
1182 self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "!" });
1183 }
1184 _ => {}
1185 }
1186 }
1187
1188 // Negative trait bounds are not allowed to have associated constraints
1189 if let GenericBound::Trait(trait_ref, TraitBoundModifier::Negative) = bound
1190 && let Some(segment) = trait_ref.trait_ref.path.segments.last()
1191 && let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
1192 {
1193 for arg in &args.args {
1194 if let ast::AngleBracketedArg::Constraint(constraint) = arg {
1195 self.err_handler().emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
1196 }
1197 }
1198 }
1199
1200 visit::walk_param_bound(self, bound)
1201 }
1202
visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId)1203 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1204 // Only associated `fn`s can have `self` parameters.
1205 let self_semantic = match fk.ctxt() {
1206 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1207 _ => SelfSemantic::No,
1208 };
1209 self.check_fn_decl(fk.decl(), self_semantic);
1210
1211 self.check_c_variadic_type(fk);
1212
1213 // Functions cannot both be `const async`
1214 if let Some(&FnHeader {
1215 constness: Const::Yes(cspan),
1216 asyncness: Async::Yes { span: aspan, .. },
1217 ..
1218 }) = fk.header()
1219 {
1220 self.err_handler().emit_err(errors::ConstAndAsync {
1221 spans: vec![cspan, aspan],
1222 cspan,
1223 aspan,
1224 span,
1225 });
1226 }
1227
1228 if let FnKind::Fn(
1229 _,
1230 _,
1231 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
1232 _,
1233 _,
1234 _,
1235 ) = fk
1236 {
1237 self.maybe_lint_missing_abi(*sig_span, id);
1238 }
1239
1240 // Functions without bodies cannot have patterns.
1241 if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
1242 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1243 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1244 if let Some(ident) = ident {
1245 let msg = match ctxt {
1246 FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
1247 _ => fluent::ast_passes_pattern_in_bodiless,
1248 };
1249 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1250 self.lint_buffer.buffer_lint_with_diagnostic(
1251 PATTERNS_IN_FNS_WITHOUT_BODY,
1252 id,
1253 span,
1254 msg,
1255 diag,
1256 )
1257 }
1258 } else {
1259 match ctxt {
1260 FnCtxt::Foreign => {
1261 self.err_handler().emit_err(errors::PatternInForeign { span })
1262 }
1263 _ => self.err_handler().emit_err(errors::PatternInBodiless { span }),
1264 };
1265 }
1266 });
1267 }
1268
1269 let tilde_const_allowed =
1270 matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1271 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1272
1273 let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
1274
1275 self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
1276 }
1277
visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt)1278 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1279 if attr::contains_name(&item.attrs, sym::no_mangle) {
1280 self.check_nomangle_item_asciionly(item.ident, item.span);
1281 }
1282
1283 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1284 self.check_defaultness(item.span, item.kind.defaultness());
1285 }
1286
1287 if ctxt == AssocCtxt::Impl {
1288 match &item.kind {
1289 AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
1290 self.session.emit_err(errors::AssocConstWithoutBody {
1291 span: item.span,
1292 replace_span: self.ending_semi_or_hi(item.span),
1293 });
1294 }
1295 AssocItemKind::Fn(box Fn { body, .. }) => {
1296 if body.is_none() {
1297 self.session.emit_err(errors::AssocFnWithoutBody {
1298 span: item.span,
1299 replace_span: self.ending_semi_or_hi(item.span),
1300 });
1301 }
1302 }
1303 AssocItemKind::Type(box TyAlias {
1304 generics,
1305 where_clauses,
1306 where_predicates_split,
1307 bounds,
1308 ty,
1309 ..
1310 }) => {
1311 if ty.is_none() {
1312 self.session.emit_err(errors::AssocTypeWithoutBody {
1313 span: item.span,
1314 replace_span: self.ending_semi_or_hi(item.span),
1315 });
1316 }
1317 self.check_type_no_bounds(bounds, "`impl`s");
1318 if ty.is_some() {
1319 self.check_gat_where(
1320 item.id,
1321 generics.where_clause.predicates.split_at(*where_predicates_split).0,
1322 *where_clauses,
1323 );
1324 }
1325 }
1326 _ => {}
1327 }
1328 }
1329
1330 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1331 self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
1332 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1333 self.check_trait_fn_not_const(sig.header.constness);
1334 }
1335 }
1336
1337 if let AssocItemKind::Const(..) = item.kind {
1338 self.check_item_named(item.ident, "const");
1339 }
1340
1341 match &item.kind {
1342 AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. })
1343 if ctxt == AssocCtxt::Trait =>
1344 {
1345 self.visit_vis(&item.vis);
1346 self.visit_ident(item.ident);
1347 walk_list!(self, visit_attribute, &item.attrs);
1348 self.with_tilde_const_allowed(|this| {
1349 this.visit_generics(generics);
1350 walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
1351 });
1352 walk_list!(self, visit_ty, ty);
1353 }
1354 AssocItemKind::Fn(box Fn { sig, generics, body, .. })
1355 if self.in_const_trait_impl
1356 || ctxt == AssocCtxt::Trait
1357 || matches!(sig.header.constness, Const::Yes(_)) =>
1358 {
1359 self.visit_vis(&item.vis);
1360 self.visit_ident(item.ident);
1361 let kind = FnKind::Fn(
1362 FnCtxt::Assoc(ctxt),
1363 item.ident,
1364 sig,
1365 &item.vis,
1366 generics,
1367 body.as_deref(),
1368 );
1369 self.visit_fn(kind, item.span, item.id);
1370 }
1371 _ => self
1372 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1373 }
1374 }
1375 }
1376
1377 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1378 /// like it's setting an associated type, provide an appropriate suggestion.
deny_equality_constraints( this: &mut AstValidator<'_>, predicate: &WhereEqPredicate, generics: &Generics, )1379 fn deny_equality_constraints(
1380 this: &mut AstValidator<'_>,
1381 predicate: &WhereEqPredicate,
1382 generics: &Generics,
1383 ) {
1384 let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None };
1385
1386 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1387 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1388 if let TyKind::Path(None, path) = &qself.ty.kind {
1389 match &path.segments[..] {
1390 [PathSegment { ident, args: None, .. }] => {
1391 for param in &generics.params {
1392 if param.ident == *ident {
1393 let param = ident;
1394 match &full_path.segments[qself.position..] {
1395 [PathSegment { ident, args, .. }] => {
1396 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1397 let mut assoc_path = full_path.clone();
1398 // Remove `Bar` from `Foo::Bar`.
1399 assoc_path.segments.pop();
1400 let len = assoc_path.segments.len() - 1;
1401 let gen_args = args.as_deref().cloned();
1402 // Build `<Bar = RhsTy>`.
1403 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1404 id: rustc_ast::node_id::DUMMY_NODE_ID,
1405 ident: *ident,
1406 gen_args,
1407 kind: AssocConstraintKind::Equality {
1408 term: predicate.rhs_ty.clone().into(),
1409 },
1410 span: ident.span,
1411 });
1412 // Add `<Bar = RhsTy>` to `Foo`.
1413 match &mut assoc_path.segments[len].args {
1414 Some(args) => match args.deref_mut() {
1415 GenericArgs::Parenthesized(_) => continue,
1416 GenericArgs::AngleBracketed(args) => {
1417 args.args.push(arg);
1418 }
1419 },
1420 empty_args => {
1421 *empty_args = Some(
1422 AngleBracketedArgs {
1423 span: ident.span,
1424 args: thin_vec![arg],
1425 }
1426 .into(),
1427 );
1428 }
1429 }
1430 err.assoc = Some(errors::AssociatedSuggestion {
1431 span: predicate.span,
1432 ident: *ident,
1433 param: *param,
1434 path: pprust::path_to_string(&assoc_path),
1435 })
1436 }
1437 _ => {}
1438 };
1439 }
1440 }
1441 }
1442 _ => {}
1443 }
1444 }
1445 }
1446 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1447 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1448 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1449 for param in &generics.params {
1450 if param.ident == potential_param.ident {
1451 for bound in ¶m.bounds {
1452 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1453 {
1454 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1455 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1456 potential_assoc.ident,
1457 ));
1458 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1459 let (args, span) = match &trait_segment.args {
1460 Some(args) => match args.deref() {
1461 ast::GenericArgs::AngleBracketed(args) => {
1462 let Some(arg) = args.args.last() else {
1463 continue;
1464 };
1465 (
1466 format!(", {} = {}", assoc, ty),
1467 arg.span().shrink_to_hi(),
1468 )
1469 }
1470 _ => continue,
1471 },
1472 None => (
1473 format!("<{} = {}>", assoc, ty),
1474 trait_segment.span().shrink_to_hi(),
1475 ),
1476 };
1477 err.assoc2 = Some(errors::AssociatedSuggestion2 {
1478 span,
1479 args,
1480 predicate: predicate.span,
1481 trait_segment: trait_segment.ident,
1482 potential_assoc: potential_assoc.ident,
1483 });
1484 }
1485 }
1486 }
1487 }
1488 }
1489 }
1490 }
1491 this.err_handler().emit_err(err);
1492 }
1493
check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool1494 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1495 let mut validator = AstValidator {
1496 session,
1497 extern_mod: None,
1498 in_trait_impl: false,
1499 in_const_trait_impl: false,
1500 has_proc_macro_decls: false,
1501 outer_impl_trait: None,
1502 disallow_tilde_const: None,
1503 is_impl_trait_banned: false,
1504 forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
1505 lint_buffer: lints,
1506 };
1507 visit::walk_crate(&mut validator, krate);
1508
1509 validator.has_proc_macro_decls
1510 }
1511
1512 /// Used to forbid `let` expressions in certain syntactic locations.
1513 #[derive(Clone, Copy, Subdiagnostic)]
1514 pub(crate) enum ForbiddenLetReason {
1515 /// `let` is not valid and the source environment is not important
1516 GenericForbidden,
1517 /// A let chain with the `||` operator
1518 #[note(ast_passes_not_supported_or)]
1519 NotSupportedOr(#[primary_span] Span),
1520 /// A let chain with invalid parentheses
1521 ///
1522 /// For example, `let 1 = 1 && (expr && expr)` is allowed
1523 /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1524 #[note(ast_passes_not_supported_parentheses)]
1525 NotSupportedParentheses(#[primary_span] Span),
1526 }
1527