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