File is large — showing lines 1–2,000 of 2,142.
1//! Validate AST before lowering it to HIR.2//!3//! This pass intends to check that the constructed AST is *syntactically valid* to allow the rest4//! of the compiler to assume that the AST is valid. These checks cannot be performed during parsing5//! because attribute macros are allowed to accept certain pieces of invalid syntax such as a6//! function without body outside of a trait definition:7//!8//! ```ignore (illustrative)9//! #[my_attribute]10//! mod foo {11//! fn missing_body();12//! }13//! ```14//!15//! These checks are run post-expansion, after AST is frozen, to be able to check for erroneous16//! constructions produced by proc macros. This pass is only intended for simple checks that do not17//! require name resolution or type checking, or other kinds of complex analysis.1819use std::mem;20use std::ops::{Deref, DerefMut};21use std::str::FromStr;2223use itertools::{Either, Itertools};24use rustc_abi::{CVariadicStatus, CanonAbi, ExternAbi, InterruptKind};25use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};26use rustc_ast::*;27use rustc_ast_pretty::pprust::{self, State};28use rustc_attr_parsing::validate_attr;29use rustc_data_structures::fx::FxIndexMap;30use rustc_errors::{DiagCtxtHandle, Diagnostic, LintBuffer};31use rustc_feature::Features;32use rustc_session::Session;33use rustc_session::errors::feature_err;34use rustc_session::lint::builtin::{35 DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,36 PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES,37};38use rustc_span::{Ident, Span, kw, sym};39use rustc_target::spec::{AbiMap, AbiMapping};40use thin_vec::thin_vec;4142use crate::errors::{self, TildeConstReason};4344/// Is `self` allowed semantically as the first parameter in an `FnDecl`?45enum SelfSemantic {46 Yes,47 No,48}4950enum TraitOrImpl {51 Trait { vis: Span, constness: Const },52 TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },53 Impl { constness: Const },54}5556impl TraitOrImpl {57 fn constness(&self) -> Option<Span> {58 match self {59 Self::Trait { constness: Const::Yes(span), .. }60 | Self::Impl { constness: Const::Yes(span), .. }61 | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),62 _ => None,63 }64 }65}6667enum AllowDefault {68 Yes,69 No,70}7172impl AllowDefault {73 fn when(b: bool) -> Self {74 if b { Self::Yes } else { Self::No }75 }76}7778enum AllowFinal {79 Yes,80 No,81}8283impl AllowFinal {84 fn when(b: bool) -> Self {85 if b { Self::Yes } else { Self::No }86 }87}8889struct AstValidator<'a> {90 sess: &'a Session,91 features: &'a Features,9293 /// The span of the `extern` in an `extern { ... }` block, if any.94 extern_mod_span: Option<Span>,9596 outer_trait_or_trait_impl: Option<TraitOrImpl>,9798 has_proc_macro_decls: bool,99100 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.101 /// Nested `impl Trait` _is_ allowed in associated type position,102 /// e.g., `impl Iterator<Item = impl Debug>`.103 outer_impl_trait_span: Option<Span>,104105 disallow_tilde_const: Option<TildeConstReason>,106107 /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.108 extern_mod_safety: Option<Safety>,109 extern_mod_abi: Option<ExternAbi>,110111 lint_node_id: NodeId,112113 is_sdylib_interface: bool,114115 lint_buffer: &'a mut LintBuffer,116}117118impl<'a> AstValidator<'a> {119 fn with_in_trait_or_impl(120 &mut self,121 in_trait_or_impl: Option<TraitOrImpl>,122 f: impl FnOnce(&mut Self),123 ) {124 let old = mem::replace(&mut self.outer_trait_or_trait_impl, in_trait_or_impl);125 f(self);126 self.outer_trait_or_trait_impl = old;127 }128129 fn with_in_trait(&mut self, vis: Span, constness: Const, f: impl FnOnce(&mut Self)) {130 let old = mem::replace(131 &mut self.outer_trait_or_trait_impl,132 Some(TraitOrImpl::Trait { vis, constness }),133 );134 f(self);135 self.outer_trait_or_trait_impl = old;136 }137138 fn with_in_extern_mod(139 &mut self,140 extern_mod_safety: Safety,141 abi: Option<ExternAbi>,142 f: impl FnOnce(&mut Self),143 ) {144 let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));145 let old_abi = mem::replace(&mut self.extern_mod_abi, abi);146 f(self);147 self.extern_mod_safety = old_safety;148 self.extern_mod_abi = old_abi;149 }150151 fn with_tilde_const(152 &mut self,153 disallowed: Option<TildeConstReason>,154 f: impl FnOnce(&mut Self),155 ) {156 let old = mem::replace(&mut self.disallow_tilde_const, disallowed);157 f(self);158 self.disallow_tilde_const = old;159 }160161 fn check_type_alias_where_clause_location(162 &mut self,163 ty_alias: &TyAlias,164 ) -> Result<(), errors::WhereClauseBeforeTypeAlias> {165 if ty_alias.ty.is_none() || !ty_alias.generics.where_clause.has_where_token {166 return Ok(());167 }168169 let span = ty_alias.generics.where_clause.span;170171 let sugg = if !ty_alias.generics.where_clause.predicates.is_empty()172 || !ty_alias.after_where_clause.has_where_token173 {174 let mut state = State::new();175176 let mut needs_comma = !ty_alias.after_where_clause.predicates.is_empty();177 if !ty_alias.after_where_clause.has_where_token {178 state.space();179 state.word_space("where");180 } else if !needs_comma {181 state.space();182 }183184 for p in &ty_alias.generics.where_clause.predicates {185 if needs_comma {186 state.word_space(",");187 }188 needs_comma = true;189 state.print_where_predicate(p);190 }191192 errors::WhereClauseBeforeTypeAliasSugg::Move {193 left: span,194 snippet: state.s.eof(),195 right: ty_alias.after_where_clause.span.shrink_to_hi(),196 }197 } else {198 errors::WhereClauseBeforeTypeAliasSugg::Remove { span }199 };200201 Err(errors::WhereClauseBeforeTypeAlias { span, sugg })202 }203204 fn with_impl_trait(&mut self, outer_span: Option<Span>, f: impl FnOnce(&mut Self)) {205 let old = mem::replace(&mut self.outer_impl_trait_span, outer_span);206 f(self);207 self.outer_impl_trait_span = old;208 }209210 // Mirrors `visit::walk_ty`, but tracks relevant state.211 fn walk_ty(&mut self, t: &Ty) {212 match &t.kind {213 TyKind::ImplTrait(_, bounds) => {214 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));215216 // FIXME(precise_capturing): If we were to allow `use` in other positions217 // (e.g. GATs), then we must validate those as well. However, we don't have218 // a good way of doing this with the current `Visitor` structure.219 let mut use_bounds = bounds220 .iter()221 .filter_map(|bound| match bound {222 GenericBound::Use(_, span) => Some(span),223 _ => None,224 })225 .copied();226 if let Some(bound1) = use_bounds.next()227 && let Some(bound2) = use_bounds.next()228 {229 self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 });230 }231 }232 TyKind::TraitObject(..) => self233 .with_tilde_const(Some(TildeConstReason::TraitObject), |this| {234 visit::walk_ty(this, t)235 }),236 _ => visit::walk_ty(self, t),237 }238 }239240 fn dcx(&self) -> DiagCtxtHandle<'a> {241 self.sess.dcx()242 }243244 fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {245 if let VisibilityKind::Inherited = vis.kind {246 return;247 }248249 self.dcx().emit_err(errors::VisibilityNotPermitted {250 span: vis.span,251 note,252 remove_qualifier_sugg: vis.span,253 });254 }255256 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {257 for Param { pat, .. } in &decl.inputs {258 match pat.kind {259 PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}260 PatKind::Ident(BindingMode::MUT, ident, None) => {261 report_err(pat.span, Some(ident), true)262 }263 _ => report_err(pat.span, None, false),264 }265 }266 }267268 fn check_impl_fn_not_const(&self, constness: Const, parent_constness: Const) {269 let Const::Yes(span) = constness else {270 return;271 };272273 let span = self.sess.source_map().span_extend_while_whitespace(span);274275 let Const::Yes(parent_constness) = parent_constness else {276 return;277 };278279 self.dcx().emit_err(errors::ImplFnConst { span, parent_constness });280 }281282 fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) {283 let Const::Yes(span) = constness else {284 return;285 };286287 let const_trait_impl = self.features.const_trait_impl();288 let make_impl_const_sugg = if const_trait_impl289 && let TraitOrImpl::TraitImpl {290 constness: Const::No,291 polarity: ImplPolarity::Positive,292 trait_ref_span,293 ..294 } = parent295 {296 Some(trait_ref_span.shrink_to_lo())297 } else {298 None299 };300301 let map = self.sess.source_map();302303 let make_trait_const_sugg = if const_trait_impl304 && let &TraitOrImpl::Trait { vis, constness: ast::Const::No } = parent305 {306 Some(map.span_extend_while_whitespace(vis).shrink_to_hi())307 } else {308 None309 };310311 let parent_constness = parent.constness();312 self.dcx().emit_err(errors::TraitFnConst {313 span,314 in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),315 const_context_label: parent_constness,316 remove_const_sugg: (317 map.span_extend_while_whitespace(span),318 match parent_constness {319 Some(_) => rustc_errors::Applicability::MachineApplicable,320 None => rustc_errors::Applicability::MaybeIncorrect,321 },322 ),323 requires_multiple_changes: make_impl_const_sugg.is_some()324 || make_trait_const_sugg.is_some(),325 make_impl_const_sugg,326 make_trait_const_sugg,327 });328 }329330 fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrImpl) {331 let Some(const_keyword) = parent.constness() else { return };332333 let Some(CoroutineKind::Async { span: async_keyword, .. }) = sig.header.coroutine_kind334 else {335 return;336 };337338 let context = match parent {339 TraitOrImpl::Trait { .. } => "trait",340 TraitOrImpl::TraitImpl { .. } => "trait_impl",341 TraitOrImpl::Impl { .. } => "impl",342 };343344 self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl {345 async_keyword,346 context,347 const_keyword,348 });349 }350351 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {352 self.check_decl_num_args(fn_decl);353 self.check_decl_cvariadic_pos(fn_decl);354 self.check_decl_attrs(fn_decl);355 self.check_decl_self_param(fn_decl, self_semantic);356 }357358 /// Emits fatal error if function declaration has more than `u16::MAX` arguments359 /// Error is fatal to prevent errors during typechecking360 fn check_decl_num_args(&self, fn_decl: &FnDecl) {361 let max_num_args: usize = u16::MAX.into();362 if fn_decl.inputs.len() > max_num_args {363 let Param { span, .. } = fn_decl.inputs[0];364 self.dcx().emit_fatal(errors::FnParamTooMany { span, max_num_args });365 }366 }367368 /// Emits an error if a function declaration has a variadic parameter in the369 /// beginning or middle of parameter list.370 /// Example: `fn foo(..., x: i32)` will emit an error.371 fn check_decl_cvariadic_pos(&self, fn_decl: &FnDecl) {372 match &*fn_decl.inputs {373 [ps @ .., _] => {374 for Param { ty, span, .. } in ps {375 if let TyKind::CVarArgs = ty.kind {376 self.dcx().emit_err(errors::FnParamCVarArgsNotLast { span: *span });377 }378 }379 }380 _ => {}381 }382 }383384 fn check_decl_attrs(&self, fn_decl: &FnDecl) {385 fn_decl386 .inputs387 .iter()388 .flat_map(|i| i.attrs.as_ref())389 .filter(|attr| {390 let arr = [391 sym::allow,392 sym::cfg_trace,393 sym::cfg_attr_trace,394 sym::deny,395 sym::expect,396 sym::forbid,397 sym::warn,398 ];399 !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)400 })401 .for_each(|attr| {402 if attr.is_doc_comment() {403 self.dcx().emit_err(errors::FnParamDocComment { span: attr.span });404 } else {405 self.dcx().emit_err(errors::FnParamForbiddenAttr { span: attr.span });406 }407 });408 }409410 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {411 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {412 if param.is_self() {413 self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span });414 }415 }416 }417418 /// Check that the signature of this function does not violate the constraints of its ABI.419 fn check_extern_fn_signature(&self, abi: ExternAbi, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {420 match AbiMap::from_target(&self.sess.target).canonize_abi(abi, false) {421 AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => {422 match canon_abi {423 CanonAbi::C424 | CanonAbi::Rust425 | CanonAbi::RustCold426 | CanonAbi::RustPreserveNone427 | CanonAbi::Arm(_)428 | CanonAbi::X86(_) => { /* nothing to check */ }429430 CanonAbi::GpuKernel => {431 // An `extern "gpu-kernel"` function cannot be `async` and/or `gen`.432 self.reject_coroutine(abi, sig);433434 // An `extern "gpu-kernel"` function cannot return a value.435 self.reject_return(abi, sig);436 }437438 CanonAbi::Custom => {439 // An `extern "custom"` function must be unsafe.440 self.reject_safe_fn(abi, ctxt, sig);441442 // An `extern "custom"` function cannot be `async` and/or `gen`.443 self.reject_coroutine(abi, sig);444445 // An `extern "custom"` function must have type `fn()`.446 self.reject_params_or_return(abi, ident, sig);447 }448449 CanonAbi::Interrupt(interrupt_kind) => {450 // An interrupt handler cannot be `async` and/or `gen`.451 self.reject_coroutine(abi, sig);452453 if let InterruptKind::X86 = interrupt_kind {454 // "x86-interrupt" is special because it does have arguments.455 // FIXME(workingjubilee): properly lint on acceptable input types.456 let inputs = &sig.decl.inputs;457 let param_count = inputs.len();458 if !matches!(param_count, 1 | 2) {459 let mut spans: Vec<Span> =460 inputs.iter().map(|arg| arg.span).collect();461 if spans.is_empty() {462 spans = vec![sig.span];463 }464 self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count });465 }466467 self.reject_return(abi, sig);468 } else {469 // An `extern "interrupt"` function must have type `fn()`.470 self.reject_params_or_return(abi, ident, sig);471 }472 }473 }474 }475 AbiMapping::Invalid => { /* ignore */ }476 }477 }478479 fn reject_safe_fn(&self, abi: ExternAbi, ctxt: FnCtxt, sig: &FnSig) {480 let dcx = self.dcx();481482 match sig.header.safety {483 Safety::Unsafe(_) => { /* all good */ }484 Safety::Safe(safe_span) => {485 let source_map = self.sess.psess.source_map();486 let safe_span = source_map.span_until_non_whitespace(safe_span.to(sig.span));487 dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });488 }489 Safety::Default => match ctxt {490 FnCtxt::Foreign => { /* all good */ }491 FnCtxt::Free | FnCtxt::Assoc(_) => {492 dcx.emit_err(errors::AbiCustomSafeFunction {493 span: sig.span,494 abi,495 unsafe_span: sig.span.shrink_to_lo(),496 });497 }498 },499 }500 }501502 fn reject_coroutine(&self, abi: ExternAbi, sig: &FnSig) {503 if let Some(coroutine_kind) = sig.header.coroutine_kind {504 let coroutine_kind_span = self505 .sess506 .psess507 .source_map()508 .span_until_non_whitespace(coroutine_kind.span().to(sig.span));509510 self.dcx().emit_err(errors::AbiCannotBeCoroutine {511 span: sig.span,512 abi,513 coroutine_kind_span,514 coroutine_kind_str: coroutine_kind.as_str(),515 });516 }517 }518519 fn reject_return(&self, abi: ExternAbi, sig: &FnSig) {520 if let FnRetTy::Ty(ref ret_ty) = sig.decl.output521 && match &ret_ty.kind {522 TyKind::Never => false,523 TyKind::Tup(tup) if tup.is_empty() => false,524 _ => true,525 }526 {527 self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi });528 }529 }530531 fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {532 let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();533 if let FnRetTy::Ty(ref ret_ty) = sig.decl.output534 && match &ret_ty.kind {535 TyKind::Never => false,536 TyKind::Tup(tup) if tup.is_empty() => false,537 _ => true,538 }539 {540 spans.push(ret_ty.span);541 }542543 if !spans.is_empty() {544 let header_span = sig.header_span();545 let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());546 let padding = if header_span.is_empty() { "" } else { " " };547548 self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType {549 spans,550 symbol: ident.name,551 suggestion_span,552 padding,553 abi,554 });555 }556 }557558 /// This ensures that items can only be `unsafe` (or unmarked) outside of extern559 /// blocks.560 ///561 /// This additionally ensures that within extern blocks, items can only be562 /// `safe`/`unsafe` inside of a `unsafe`-adorned extern block.563 fn check_item_safety(&self, span: Span, safety: Safety) {564 match self.extern_mod_safety {565 Some(extern_safety) => {566 if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))567 && extern_safety == Safety::Default568 {569 self.dcx().emit_err(errors::InvalidSafetyOnExtern {570 item_span: span,571 block: Some(self.current_extern_span().shrink_to_lo()),572 });573 }574 }575 None => {576 if matches!(safety, Safety::Safe(_)) {577 self.dcx().emit_err(errors::InvalidSafetyOnItem { span });578 }579 }580 }581 }582583 fn check_fn_ptr_safety(&self, span: Span, safety: Safety) {584 if matches!(safety, Safety::Safe(_)) {585 self.dcx().emit_err(errors::InvalidSafetyOnFnPtr { span });586 }587 }588589 fn check_defaultness(590 &self,591 span: Span,592 defaultness: Defaultness,593 allow_default: AllowDefault,594 allow_final: AllowFinal,595 ) {596 match defaultness {597 Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => {598 let span = self.sess.source_map().guess_head_span(span);599 self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });600 }601 Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => {602 let span = self.sess.source_map().guess_head_span(span);603 self.dcx().emit_err(errors::ForbiddenFinal { span, def_span });604 }605 _ => (),606 }607 }608609 fn check_final_has_body(&self, item: &Item<AssocItemKind>, defaultness: Defaultness) {610 if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind611 && let Defaultness::Final(def_span) = defaultness612 {613 let span = self.sess.source_map().guess_head_span(item.span);614 self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span });615 }616 }617618 /// If `sp` ends with a semicolon, returns it as a `Span`619 /// Otherwise, returns `sp.shrink_to_hi()`620 fn ending_semi_or_hi(&self, sp: Span) -> Span {621 let source_map = self.sess.source_map();622 let end = source_map.end_point(sp);623624 if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") {625 end626 } else {627 sp.shrink_to_hi()628 }629 }630631 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {632 let span = match bounds {633 [] => return,634 [b0] => b0.span(),635 [b0, .., bl] => b0.span().to(bl.span()),636 };637 self.dcx().emit_err(errors::BoundInContext { span, ctx });638 }639640 fn check_foreign_ty_genericless(&self, generics: &Generics, after_where_clause: &WhereClause) {641 let cannot_have = |span, descr, remove_descr| {642 self.dcx().emit_err(errors::ExternTypesCannotHave {643 span,644 descr,645 remove_descr,646 block_span: self.current_extern_span(),647 });648 };649650 if !generics.params.is_empty() {651 cannot_have(generics.span, "generic parameters", "generic parameters");652 }653654 let check_where_clause = |where_clause: &WhereClause| {655 if where_clause.has_where_token {656 cannot_have(where_clause.span, "`where` clauses", "`where` clause");657 }658 };659660 check_where_clause(&generics.where_clause);661 check_where_clause(&after_where_clause);662 }663664 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body_span: Option<Span>) {665 let Some(body_span) = body_span else {666 return;667 };668 self.dcx().emit_err(errors::BodyInExtern {669 span: ident.span,670 body: body_span,671 block: self.current_extern_span(),672 kind,673 });674 }675676 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.677 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {678 let Some(body) = body else {679 return;680 };681 self.dcx().emit_err(errors::FnBodyInExtern {682 span: ident.span,683 body: body.span,684 block: self.current_extern_span(),685 });686 }687688 fn current_extern_span(&self) -> Span {689 self.sess.source_map().guess_head_span(self.extern_mod_span.unwrap())690 }691692 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.693 fn check_foreign_fn_headerless(694 &self,695 // Deconstruct to ensure exhaustiveness696 FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader,697 ) {698 let report_err = |span, kw| {699 self.dcx().emit_err(errors::FnQualifierInExtern {700 span,701 kw,702 block: self.current_extern_span(),703 });704 };705 match coroutine_kind {706 Some(kind) => report_err(kind.span(), kind.as_str()),707 None => (),708 }709 match constness {710 Const::Yes(span) => report_err(span, "const"),711 Const::No => (),712 }713 match ext {714 Extern::None => (),715 Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span, "extern"),716 }717 }718719 /// An item in `extern { ... }` cannot use non-ascii identifier.720 fn check_foreign_item_ascii_only(&self, ident: Ident) {721 if !ident.as_str().is_ascii() {722 self.dcx().emit_err(errors::ExternItemAscii {723 span: ident.span,724 block: self.current_extern_span(),725 });726 }727 }728729 /// Reject invalid C-variadic types.730 ///731 /// C-variadics must be:732 /// - Non-const733 /// - Either foreign, or free and `unsafe extern "C"` semantically734 fn check_c_variadic_type(&self, fk: FnKind<'_>, attrs: &AttrVec) {735 // `...` is already rejected when it is not the final parameter.736 let variadic_param = match fk.decl().inputs.last() {737 Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,738 _ => return,739 };740741 let FnKind::Fn(fn_ctxt, _, Fn { sig, .. }) = fk else {742 // Unreachable because the parser already rejects `...` in closures.743 unreachable!("C variable argument list cannot be used in closures")744 };745746 if let Const::Yes(_) = sig.header.constness747 && !self.features.enabled(sym::const_c_variadic)748 {749 let msg = format!("c-variadic const function definitions are unstable");750 feature_err(&self.sess, sym::const_c_variadic, sig.span, msg).emit();751 }752753 if let Some(coroutine_kind) = sig.header.coroutine_kind {754 self.dcx().emit_err(errors::CoroutineAndCVariadic {755 spans: vec![coroutine_kind.span(), variadic_param.span],756 coroutine_kind: coroutine_kind.as_str(),757 coroutine_span: coroutine_kind.span(),758 variadic_span: variadic_param.span,759 });760 }761762 match fn_ctxt {763 FnCtxt::Foreign => return,764 FnCtxt::Free | FnCtxt::Assoc(_) => {765 match self.sess.target.supports_c_variadic_definitions() {766 CVariadicStatus::NotSupported => {767 self.dcx().emit_err(errors::CVariadicNotSupported {768 variadic_span: variadic_param.span,769 target: &*self.sess.target.llvm_target,770 });771 return;772 }773 CVariadicStatus::Unstable { feature } if !self.features.enabled(feature) => {774 let msg =775 format!("C-variadic function definitions on this target are unstable");776 feature_err(&self.sess, feature, variadic_param.span, msg).emit();777 return;778 }779 CVariadicStatus::Unstable { .. } | CVariadicStatus::Stable => {780 /* fall through */781 }782 }783784 match sig.header.ext {785 Extern::Implicit(_) => {786 if !matches!(sig.header.safety, Safety::Unsafe(_)) {787 self.dcx().emit_err(errors::CVariadicMustBeUnsafe {788 span: variadic_param.span,789 unsafe_span: sig.safety_span(),790 });791 }792 }793 Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {794 // Just bail if the ABI is not even recognized.795 let Ok(abi) = ExternAbi::from_str(symbol_unescaped.as_str()) else {796 return;797 };798799 self.check_c_variadic_abi(abi, attrs, variadic_param.span, sig);800801 if !matches!(sig.header.safety, Safety::Unsafe(_)) {802 self.dcx().emit_err(errors::CVariadicMustBeUnsafe {803 span: variadic_param.span,804 unsafe_span: sig.safety_span(),805 });806 }807 }808 Extern::None => {809 let err = errors::CVariadicNoExtern { span: variadic_param.span };810 self.dcx().emit_err(err);811 }812 }813 }814 }815 }816817 fn check_c_variadic_abi(818 &self,819 abi: ExternAbi,820 attrs: &AttrVec,821 dotdotdot_span: Span,822 sig: &FnSig,823 ) {824 // For naked functions we accept any ABI that is accepted on c-variadic825 // foreign functions, if the c_variadic_naked_functions feature is enabled.826 if attr::contains_name(attrs, sym::naked) {827 match abi.supports_c_variadic() {828 CVariadicStatus::Stable if let ExternAbi::C { .. } = abi => {829 // With `c_variadic` naked c-variadic `extern "C"` functions are allowed.830 }831 CVariadicStatus::Stable => {832 // For e.g. aapcs or sysv64 `c_variadic_naked_functions` must also be enabled.833 if !self.features.enabled(sym::c_variadic_naked_functions) {834 let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");835 feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)836 .emit();837 }838 }839 CVariadicStatus::Unstable { feature } => {840 // Some ABIs need additional features.841 if !self.features.enabled(sym::c_variadic_naked_functions) {842 let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");843 feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)844 .emit();845 }846847 if !self.features.enabled(feature) {848 let msg = format!(849 "C-variadic functions with the {abi} calling convention are unstable"850 );851 feature_err(&self.sess, feature, sig.span, msg).emit();852 }853 }854 CVariadicStatus::NotSupported => {855 // Some ABIs, e.g. `extern "Rust"`, never support c-variadic functions.856 self.dcx().emit_err(errors::CVariadicBadNakedExtern {857 span: dotdotdot_span,858 abi: abi.as_str(),859 extern_span: sig.extern_span(),860 });861 }862 }863 } else if !matches!(abi, ExternAbi::C { .. }) {864 self.dcx().emit_err(errors::CVariadicBadExtern {865 span: dotdotdot_span,866 abi: abi.as_str(),867 extern_span: sig.extern_span(),868 });869 }870 }871872 fn check_item_named(&self, ident: Ident, kind: &str) {873 if ident.name != kw::Underscore {874 return;875 }876 self.dcx().emit_err(errors::ItemUnderscore { span: ident.span, kind });877 }878879 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {880 if ident.name.as_str().is_ascii() {881 return;882 }883 let span = self.sess.source_map().guess_head_span(item_span);884 self.dcx().emit_err(errors::NoMangleAscii { span });885 }886887 fn check_mod_file_item_asciionly(&self, ident: Ident) {888 if ident.name.as_str().is_ascii() {889 return;890 }891 self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });892 }893894 fn deny_const_auto_traits(&self, constness: Const) {895 if let Const::Yes(span) = constness {896 self.dcx().emit_err(errors::ConstAutoTrait { span });897 }898 }899900 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {901 if !generics.params.is_empty() {902 self.dcx()903 .emit_err(errors::AutoTraitGeneric { span: generics.span, ident: ident_span });904 }905 }906907 fn deny_super_traits(&self, bounds: &GenericBounds, ident: Span) {908 if let [.., last] = &bounds[..] {909 let span = bounds.iter().map(|b| b.span()).collect();910 let removal = ident.shrink_to_hi().to(last.span());911 self.dcx().emit_err(errors::AutoTraitBounds { span, removal, ident });912 }913 }914915 fn deny_where_clause(&self, where_clause: &WhereClause, ident: Span) {916 if !where_clause.predicates.is_empty() {917 // FIXME: The current diagnostic is misleading since it only talks about918 // super trait and lifetime bounds while we should just say “bounds”.919 self.dcx().emit_err(errors::AutoTraitBounds {920 span: vec![where_clause.span],921 removal: where_clause.span,922 ident,923 });924 }925 }926927 fn deny_items(&self, trait_items: &[Box<AssocItem>], ident_span: Span) {928 if !trait_items.is_empty() {929 let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect();930 let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);931 self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident: ident_span });932 }933 }934935 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {936 // Lifetimes always come first.937 let lt_sugg = data.args.iter().filter_map(|arg| match arg {938 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {939 Some(pprust::to_string(|s| s.print_generic_arg(lt)))940 }941 _ => None,942 });943 let args_sugg = data.args.iter().filter_map(|a| match a {944 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {945 None946 }947 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),948 });949 // Constraints always come last.950 let constraint_sugg = data.args.iter().filter_map(|a| match a {951 AngleBracketedArg::Arg(_) => None,952 AngleBracketedArg::Constraint(c) => {953 Some(pprust::to_string(|s| s.print_assoc_item_constraint(c)))954 }955 });956 format!(957 "<{}>",958 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")959 )960 }961962 /// Enforce generic args coming before constraints in `<...>` of a path segment.963 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {964 // Early exit in case it's partitioned as it should be.965 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {966 return;967 }968 // Find all generic argument coming after the first constraint...969 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =970 data.args.iter().partition_map(|arg| match arg {971 AngleBracketedArg::Constraint(c) => Either::Left(c.span),972 AngleBracketedArg::Arg(a) => Either::Right(a.span()),973 });974 let args_len = arg_spans.len();975 let constraint_len = constraint_spans.len();976 // ...and then error:977 self.dcx().emit_err(errors::ArgsBeforeConstraint {978 arg_spans: arg_spans.clone(),979 constraints: constraint_spans[0],980 args: *arg_spans.iter().last().unwrap(),981 data: data.span,982 constraint_spans: errors::EmptyLabelManySpans(constraint_spans),983 arg_spans2: errors::EmptyLabelManySpans(arg_spans),984 suggestion: self.correct_generic_order_suggestion(data),985 constraint_len,986 args_len,987 });988 }989990 fn visit_ty_common(&mut self, ty: &Ty) {991 match &ty.kind {992 TyKind::FnPtr(bfty) => {993 self.check_fn_ptr_safety(bfty.decl_span, bfty.safety);994 self.check_fn_decl(&bfty.decl, SelfSemantic::No);995 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {996 self.dcx().emit_err(errors::PatternFnPointer { span });997 });998 if let Extern::Implicit(extern_span) = bfty.ext {999 self.handle_missing_abi(extern_span, ty.id);1000 }1001 }1002 TyKind::TraitObject(bounds, ..) => {1003 let mut any_lifetime_bounds = false;1004 for bound in bounds {1005 if let GenericBound::Outlives(lifetime) = bound {1006 if any_lifetime_bounds {1007 self.dcx()1008 .emit_err(errors::TraitObjectBound { span: lifetime.ident.span });1009 break;1010 }1011 any_lifetime_bounds = true;1012 }1013 }1014 }1015 TyKind::ImplTrait(_, bounds) => {1016 if let Some(outer_impl_trait_sp) = self.outer_impl_trait_span {1017 self.dcx().emit_err(errors::NestedImplTrait {1018 span: ty.span,1019 outer: outer_impl_trait_sp,1020 inner: ty.span,1021 });1022 }10231024 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {1025 self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span });1026 }1027 }1028 _ => {}1029 }1030 }10311032 fn handle_missing_abi(&mut self, span: Span, id: NodeId) {1033 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the1034 // call site which do not have a macro backtrace. See #61963.1035 if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {1036 self.dcx().emit_err(errors::MissingAbi { span });1037 } else if self1038 .sess1039 .source_map()1040 .span_to_snippet(span)1041 .is_ok_and(|snippet| !snippet.starts_with("#["))1042 {1043 self.lint_buffer.buffer_lint(1044 MISSING_ABI,1045 id,1046 span,1047 errors::MissingAbiSugg { span, default_abi: ExternAbi::FALLBACK },1048 )1049 }1050 }10511052 // Used within `visit_item` for item kinds where we don't call `visit::walk_item`.1053 fn visit_attrs_vis(&mut self, attrs: &AttrVec, vis: &Visibility) {1054 walk_list!(self, visit_attribute, attrs);1055 self.visit_vis(vis);1056 }10571058 // Used within `visit_item` for item kinds where we don't call `visit::walk_item`.1059 fn visit_attrs_vis_ident(&mut self, attrs: &AttrVec, vis: &Visibility, ident: &Ident) {1060 walk_list!(self, visit_attribute, attrs);1061 self.visit_vis(vis);1062 self.visit_ident(ident);1063 }1064}10651066/// Checks that generic parameters are in the correct order,1067/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)1068fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericParam], span: Span) {1069 let mut max_param: Option<ParamKindOrd> = None;1070 let mut out_of_order = FxIndexMap::default();1071 let mut param_idents = Vec::with_capacity(generics.len());10721073 for (idx, param) in generics.iter().enumerate() {1074 let ident = param.ident;1075 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);1076 let (ord_kind, ident) = match ¶m.kind {1077 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),1078 GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),1079 GenericParamKind::Const { ty, .. } => {1080 let ty = pprust::ty_to_string(ty);1081 (ParamKindOrd::TypeOrConst, format!("const {ident}: {ty}"))1082 }1083 };1084 param_idents.push((kind, ord_kind, bounds, idx, ident));1085 match max_param {1086 Some(max_param) if max_param > ord_kind => {1087 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));1088 entry.1.push(span);1089 }1090 Some(_) | None => max_param = Some(ord_kind),1091 };1092 }10931094 if !out_of_order.is_empty() {1095 let mut ordered_params = "<".to_string();1096 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));1097 let mut first = true;1098 for (kind, _, bounds, _, ident) in param_idents {1099 if !first {1100 ordered_params += ", ";1101 }1102 ordered_params += &ident;11031104 if !bounds.is_empty() {1105 ordered_params += ": ";1106 ordered_params += &pprust::bounds_to_string(bounds);1107 }11081109 match kind {1110 GenericParamKind::Type { default: Some(default) } => {1111 ordered_params += " = ";1112 ordered_params += &pprust::ty_to_string(default);1113 }1114 GenericParamKind::Type { default: None } => (),1115 GenericParamKind::Lifetime => (),1116 GenericParamKind::Const { ty: _, span: _, default: Some(default) } => {1117 ordered_params += " = ";1118 ordered_params += &pprust::expr_to_string(&default.value);1119 }1120 GenericParamKind::Const { ty: _, span: _, default: None } => (),1121 }1122 first = false;1123 }11241125 ordered_params += ">";11261127 for (param_ord, (max_param, spans)) in &out_of_order {1128 dcx.emit_err(errors::OutOfOrderParams {1129 spans: spans.clone(),1130 sugg_span: span,1131 param_ord: param_ord.to_string(),1132 max_param: max_param.to_string(),1133 ordered_params: &ordered_params,1134 });1135 }1136 }1137}11381139impl Visitor<'_> for AstValidator<'_> {1140 fn visit_attribute(&mut self, attr: &Attribute) {1141 validate_attr::check_attr(&self.sess.psess, attr);1142 }11431144 fn visit_ty(&mut self, ty: &Ty) {1145 self.visit_ty_common(ty);1146 self.walk_ty(ty)1147 }11481149 fn visit_item(&mut self, item: &Item) {1150 if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {1151 self.has_proc_macro_decls = true;1152 }11531154 let previous_lint_node_id = mem::replace(&mut self.lint_node_id, item.id);11551156 if let Some(ident) = item.kind.ident()1157 && attr::contains_name(&item.attrs, sym::no_mangle)1158 {1159 self.check_nomangle_item_asciionly(ident, item.span);1160 }11611162 match &item.kind {1163 ItemKind::Impl(Impl {1164 generics,1165 constness,1166 of_trait:1167 Some(box TraitImplHeader { safety, polarity, defaultness: _, trait_ref: t }),1168 self_ty,1169 items,1170 }) => {1171 self.visit_attrs_vis(&item.attrs, &item.vis);1172 self.visibility_not_permitted(1173 &item.vis,1174 errors::VisibilityNotPermittedNote::TraitImpl,1175 );1176 if let TyKind::Dummy = self_ty.kind {1177 // Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering,1178 // which isn't allowed. Not a problem for this obscure, obsolete syntax.1179 self.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });1180 }1181 if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity) {1182 self.dcx().emit_err(errors::UnsafeNegativeImpl {1183 span: sp.to(t.path.span),1184 negative: sp,1185 r#unsafe: span,1186 });1187 }11881189 let disallowed = matches!(constness, Const::No)1190 .then(|| TildeConstReason::TraitImpl { span: item.span });1191 self.with_tilde_const(disallowed, |this| this.visit_generics(generics));1192 self.visit_trait_ref(t);1193 self.visit_ty(self_ty);11941195 self.with_in_trait_or_impl(1196 Some(TraitOrImpl::TraitImpl {1197 constness: *constness,1198 polarity: *polarity,1199 trait_ref_span: t.path.span,1200 }),1201 |this| {1202 walk_list!(1203 this,1204 visit_assoc_item,1205 items,1206 AssocCtxt::Impl { of_trait: true }1207 );1208 },1209 );1210 }1211 ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness }) => {1212 self.visit_attrs_vis(&item.attrs, &item.vis);1213 self.visibility_not_permitted(1214 &item.vis,1215 errors::VisibilityNotPermittedNote::IndividualImplItems,1216 );12171218 let disallowed = matches!(constness, ast::Const::No)1219 .then(|| TildeConstReason::Impl { span: item.span });12201221 self.with_tilde_const(disallowed, |this| this.visit_generics(generics));12221223 self.visit_ty(self_ty);1224 self.with_in_trait_or_impl(1225 Some(TraitOrImpl::Impl { constness: *constness }),1226 |this| {1227 walk_list!(1228 this,1229 visit_assoc_item,1230 items,1231 AssocCtxt::Impl { of_trait: false }1232 );1233 },1234 );1235 }1236 ItemKind::Fn(1237 func @ box Fn {1238 defaultness,1239 ident,1240 generics: _,1241 sig,1242 contract: _,1243 body,1244 define_opaque: _,1245 eii_impls,1246 },1247 ) => {1248 self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);1249 self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);12501251 for EiiImpl { eii_macro_path, .. } in eii_impls {1252 self.visit_path(eii_macro_path);1253 }12541255 let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));1256 if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {1257 self.dcx().emit_err(errors::FnWithoutBody {1258 span: item.span,1259 replace_span: self.ending_semi_or_hi(item.span),1260 extern_block_suggestion: match sig.header.ext {1261 Extern::None => None,1262 Extern::Implicit(start_span) => {1263 Some(errors::ExternBlockSuggestion::Implicit {1264 start_span,1265 end_span: item.span.shrink_to_hi(),1266 })1267 }1268 Extern::Explicit(abi, start_span) => {1269 Some(errors::ExternBlockSuggestion::Explicit {1270 start_span,1271 end_span: item.span.shrink_to_hi(),1272 abi: abi.symbol_unescaped,1273 })1274 }1275 },1276 });1277 }12781279 let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);1280 self.visit_fn(kind, &item.attrs, item.span, item.id);1281 }1282 ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {1283 let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span));1284 self.visibility_not_permitted(1285 &item.vis,1286 errors::VisibilityNotPermittedNote::IndividualForeignItems,1287 );12881289 if &Safety::Default == safety {1290 if item.span.at_least_rust_2024() {1291 self.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });1292 } else {1293 self.lint_buffer.buffer_lint(1294 MISSING_UNSAFE_ON_EXTERN,1295 item.id,1296 item.span,1297 errors::MissingUnsafeOnExternLint {1298 suggestion: item.span.shrink_to_lo(),1299 },1300 );1301 }1302 }13031304 if abi.is_none() {1305 self.handle_missing_abi(*extern_span, item.id);1306 }13071308 let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok());1309 self.with_in_extern_mod(*safety, extern_abi, |this| {1310 visit::walk_item(this, item);1311 });1312 self.extern_mod_span = old_item;1313 }1314 ItemKind::Enum(_, _, def) => {1315 for variant in &def.variants {1316 self.visibility_not_permitted(1317 &variant.vis,1318 errors::VisibilityNotPermittedNote::EnumVariant,1319 );1320 for field in variant.data.fields() {1321 self.visibility_not_permitted(1322 &field.vis,1323 errors::VisibilityNotPermittedNote::EnumVariant,1324 );1325 }1326 }1327 self.with_tilde_const(Some(TildeConstReason::Enum { span: item.span }), |this| {1328 visit::walk_item(this, item)1329 });1330 }1331 ItemKind::Trait(box Trait {1332 constness,1333 is_auto,1334 generics,1335 ident,1336 bounds,1337 items,1338 ..1339 }) => {1340 self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);1341 if *is_auto == IsAuto::Yes {1342 // For why we reject `const auto trait`, see rust-lang/rust#149285.1343 self.deny_const_auto_traits(*constness);1344 // Auto traits cannot have generics, super traits nor contain items.1345 self.deny_generic_params(generics, ident.span);1346 self.deny_super_traits(bounds, ident.span);1347 self.deny_where_clause(&generics.where_clause, ident.span);1348 self.deny_items(items, ident.span);1349 }13501351 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound1352 // context for the supertraits.1353 let disallowed = matches!(constness, ast::Const::No)1354 .then(|| TildeConstReason::Trait { span: item.span });1355 self.with_tilde_const(disallowed, |this| {1356 this.visit_generics(generics);1357 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)1358 });1359 self.with_in_trait(item.span, *constness, |this| {1360 walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);1361 });1362 }1363 ItemKind::TraitAlias(box TraitAlias { constness, generics, bounds, .. }) => {1364 let disallowed = matches!(constness, ast::Const::No)1365 .then(|| TildeConstReason::Trait { span: item.span });1366 self.with_tilde_const(disallowed, |this| {1367 this.visit_generics(generics);1368 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)1369 });1370 }1371 ItemKind::Mod(safety, ident, mod_kind) => {1372 if let &Safety::Unsafe(span) = safety {1373 self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });1374 }1375 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).1376 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))1377 && !attr::contains_name(&item.attrs, sym::path)1378 {1379 self.check_mod_file_item_asciionly(*ident);1380 }1381 visit::walk_item(self, item)1382 }1383 ItemKind::Struct(ident, generics, vdata) => {1384 self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {1385 // Scalable vectors can only be tuple structs1386 let scalable_vector_attr =1387 item.attrs.iter().find(|attr| attr.has_name(sym::rustc_scalable_vector));1388 if let Some(attr) = scalable_vector_attr {1389 if !matches!(vdata, VariantData::Tuple(..)) {1390 this.dcx()1391 .emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });1392 }1393 if !self.sess.target.arch.supports_scalable_vectors()1394 && !self.sess.opts.actually_rustdoc1395 {1396 this.dcx().emit_err(errors::ScalableVectorBadArch { span: attr.span });1397 }1398 }13991400 match vdata {1401 VariantData::Struct { fields, .. } => {1402 this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);1403 this.visit_generics(generics);1404 walk_list!(this, visit_field_def, fields);1405 }1406 _ => visit::walk_item(this, item),1407 }1408 })1409 }1410 ItemKind::Union(ident, generics, vdata) => {1411 if vdata.fields().is_empty() {1412 self.dcx().emit_err(errors::FieldlessUnion { span: item.span });1413 }1414 self.with_tilde_const(Some(TildeConstReason::Union { span: item.span }), |this| {1415 match vdata {1416 VariantData::Struct { fields, .. } => {1417 this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);1418 this.visit_generics(generics);1419 walk_list!(this, visit_field_def, fields);1420 }1421 _ => visit::walk_item(this, item),1422 }1423 });1424 }1425 ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {1426 self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);1427 if !rhs_kind.has_expr() {1428 self.dcx().emit_err(errors::ConstWithoutBody {1429 span: item.span,1430 replace_span: self.ending_semi_or_hi(item.span),1431 });1432 }1433 if ident.name == kw::Underscore1434 && !matches!(item.vis.kind, VisibilityKind::Inherited)1435 && ident.span.eq_ctxt(item.vis.span)1436 {1437 self.lint_buffer.buffer_lint(1438 UNUSED_VISIBILITIES,1439 item.id,1440 item.vis.span,1441 errors::UnusedVisibility { span: item.vis.span },1442 )1443 }14441445 visit::walk_item(self, item);1446 }1447 ItemKind::Static(box StaticItem { expr, safety, .. }) => {1448 self.check_item_safety(item.span, *safety);1449 if matches!(safety, Safety::Unsafe(_)) {1450 self.dcx().emit_err(errors::UnsafeStatic { span: item.span });1451 }14521453 if expr.is_none() {1454 self.dcx().emit_err(errors::StaticWithoutBody {1455 span: item.span,1456 replace_span: self.ending_semi_or_hi(item.span),1457 });1458 }1459 visit::walk_item(self, item);1460 }1461 ItemKind::TyAlias(1462 ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },1463 ) => {1464 self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);1465 if ty.is_none() {1466 self.dcx().emit_err(errors::TyAliasWithoutBody {1467 span: item.span,1468 replace_span: self.ending_semi_or_hi(item.span),1469 });1470 }1471 self.check_type_no_bounds(bounds, "this context");14721473 if self.features.lazy_type_alias() {1474 if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {1475 self.dcx().emit_err(err);1476 }1477 } else if after_where_clause.has_where_token {1478 self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {1479 span: after_where_clause.span,1480 help: self.sess.is_nightly_build(),1481 });1482 }1483 visit::walk_item(self, item);1484 }1485 _ => visit::walk_item(self, item),1486 }14871488 self.lint_node_id = previous_lint_node_id;1489 }14901491 fn visit_foreign_item(&mut self, fi: &ForeignItem) {1492 match &fi.kind {1493 ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {1494 self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);1495 self.check_foreign_fn_bodyless(*ident, body.as_deref());1496 self.check_foreign_fn_headerless(sig.header);1497 self.check_foreign_item_ascii_only(*ident);1498 self.check_extern_fn_signature(1499 self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK),1500 FnCtxt::Foreign,1501 ident,1502 sig,1503 );15041505 if let Some(attr) = attr::find_by_name(fi.attrs(), sym::track_caller)1506 && self.extern_mod_abi != Some(ExternAbi::Rust)1507 {1508 self.dcx().emit_err(errors::RequiresRustAbi {1509 track_caller_span: attr.span,1510 extern_abi_span: self.current_extern_span(),1511 });1512 }1513 }1514 ForeignItemKind::TyAlias(box TyAlias {1515 defaultness,1516 ident,1517 generics,1518 after_where_clause,1519 bounds,1520 ty,1521 ..1522 }) => {1523 self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);1524 self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));1525 self.check_type_no_bounds(bounds, "`extern` blocks");1526 self.check_foreign_ty_genericless(generics, after_where_clause);1527 self.check_foreign_item_ascii_only(*ident);1528 }1529 ForeignItemKind::Static(box StaticItem { ident, safety, expr, .. }) => {1530 self.check_item_safety(fi.span, *safety);1531 self.check_foreign_kind_bodyless(*ident, "static", expr.as_ref().map(|b| b.span));1532 self.check_foreign_item_ascii_only(*ident);1533 }1534 ForeignItemKind::MacCall(..) => {}1535 }15361537 visit::walk_item(self, fi)1538 }15391540 // Mirrors `visit::walk_generic_args`, but tracks relevant state.1541 fn visit_generic_args(&mut self, generic_args: &GenericArgs) {1542 match generic_args {1543 GenericArgs::AngleBracketed(data) => {1544 self.check_generic_args_before_constraints(data);15451546 for arg in &data.args {1547 match arg {1548 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),1549 // Associated type bindings such as `Item = impl Debug` in1550 // `Iterator<Item = Debug>` are allowed to contain nested `impl Trait`.1551 AngleBracketedArg::Constraint(constraint) => {1552 self.with_impl_trait(None, |this| {1553 this.visit_assoc_item_constraint(constraint);1554 });1555 }1556 }1557 }1558 }1559 GenericArgs::Parenthesized(data) => {1560 walk_list!(self, visit_ty, &data.inputs);1561 if let FnRetTy::Ty(ty) = &data.output {1562 // `-> Foo` syntax is essentially an associated type binding,1563 // so it is also allowed to contain nested `impl Trait`.1564 self.with_impl_trait(None, |this| this.visit_ty(ty));1565 }1566 }1567 GenericArgs::ParenthesizedElided(_span) => {}1568 }1569 }15701571 fn visit_generics(&mut self, generics: &Generics) {1572 let mut prev_param_default = None;1573 for param in &generics.params {1574 match param.kind {1575 GenericParamKind::Lifetime => (),1576 GenericParamKind::Type { default: Some(_), .. }1577 | GenericParamKind::Const { default: Some(_), .. } => {1578 prev_param_default = Some(param.ident.span);1579 }1580 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {1581 if let Some(span) = prev_param_default {1582 self.dcx().emit_err(errors::GenericDefaultTrailing { span });1583 break;1584 }1585 }1586 }1587 }15881589 validate_generic_param_order(self.dcx(), &generics.params, generics.span);15901591 for predicate in &generics.where_clause.predicates {1592 let span = predicate.span;1593 if let WherePredicateKind::EqPredicate(predicate) = &predicate.kind {1594 deny_equality_constraints(self, predicate, span, generics);1595 }1596 }1597 walk_list!(self, visit_generic_param, &generics.params);1598 for predicate in &generics.where_clause.predicates {1599 match &predicate.kind {1600 WherePredicateKind::BoundPredicate(bound_pred) => {1601 // This is slightly complicated. Our representation for poly-trait-refs contains a single1602 // binder and thus we only allow a single level of quantification. However,1603 // the syntax of Rust permits quantification in two places in where clauses,1604 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are1605 // defined, then error.1606 if !bound_pred.bound_generic_params.is_empty() {1607 for bound in &bound_pred.bounds {1608 match bound {1609 GenericBound::Trait(t) => {1610 if !t.bound_generic_params.is_empty() {1611 self.dcx()1612 .emit_err(errors::NestedLifetimes { span: t.span });1613 }1614 }1615 GenericBound::Outlives(_) => {}1616 GenericBound::Use(..) => {}1617 }1618 }1619 }1620 }1621 _ => {}1622 }1623 self.visit_where_predicate(predicate);1624 }1625 }16261627 fn visit_param_bound(&mut self, bound: &GenericBound, ctxt: BoundKind) {1628 match bound {1629 GenericBound::Trait(trait_ref) => {1630 match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {1631 (1632 BoundKind::TraitObject,1633 BoundConstness::Always(_),1634 BoundPolarity::Positive,1635 ) => {1636 self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span });1637 }1638 (_, BoundConstness::Maybe(span), BoundPolarity::Positive)1639 if let Some(reason) = self.disallow_tilde_const =>1640 {1641 self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });1642 }1643 _ => {}1644 }16451646 // Negative trait bounds are not allowed to have associated constraints1647 if let BoundPolarity::Negative(_) = trait_ref.modifiers.polarity1648 && let Some(segment) = trait_ref.trait_ref.path.segments.last()1649 {1650 match segment.args.as_deref() {1651 Some(ast::GenericArgs::AngleBracketed(args)) => {1652 for arg in &args.args {1653 if let ast::AngleBracketedArg::Constraint(constraint) = arg {1654 self.dcx().emit_err(errors::ConstraintOnNegativeBound {1655 span: constraint.span,1656 });1657 }1658 }1659 }1660 // The lowered form of parenthesized generic args contains an associated type binding.1661 Some(ast::GenericArgs::Parenthesized(args)) => {1662 self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {1663 span: args.span,1664 });1665 }1666 Some(ast::GenericArgs::ParenthesizedElided(_)) | None => {}1667 }1668 }1669 }1670 GenericBound::Outlives(_) => {}1671 GenericBound::Use(_, span) => match ctxt {1672 BoundKind::Impl => {}1673 BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => {1674 self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere {1675 loc: ctxt.descr(),1676 span: *span,1677 });1678 }1679 },1680 }16811682 visit::walk_param_bound(self, bound)1683 }16841685 fn visit_fn(&mut self, fk: FnKind<'_>, attrs: &AttrVec, span: Span, id: NodeId) {1686 // Only associated `fn`s can have `self` parameters.1687 let self_semantic = match fk.ctxt() {1688 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,1689 _ => SelfSemantic::No,1690 };1691 self.check_fn_decl(fk.decl(), self_semantic);16921693 if let Some(&FnHeader { safety, .. }) = fk.header() {1694 self.check_item_safety(span, safety);1695 }16961697 if let FnKind::Fn(ctxt, _, fun) = fk {1698 let ext = match fun.sig.header.ext {1699 Extern::None => None,1700 Extern::Implicit(span) => Some((ExternAbi::FALLBACK, span)),1701 Extern::Explicit(str_lit, span) => {1702 ExternAbi::from_str(str_lit.symbol.as_str()).ok().map(|abi| (abi, span))1703 }1704 };17051706 if let Some((extern_abi, extern_abi_span)) = ext {1707 // Some ABIs impose special restrictions on the signature.1708 self.check_extern_fn_signature(extern_abi, ctxt, &fun.ident, &fun.sig);17091710 // #[track_caller] can only be used with the rust ABI.1711 if let Some(attr) = attr::find_by_name(attrs, sym::track_caller)1712 && extern_abi != ExternAbi::Rust1713 {1714 self.dcx().emit_err(errors::RequiresRustAbi {1715 track_caller_span: attr.span,1716 extern_abi_span,1717 });1718 }1719 }1720 }17211722 self.check_c_variadic_type(fk, attrs);17231724 // Functions cannot both be `const async` or `const gen`1725 if let Some(&FnHeader {1726 constness: Const::Yes(const_span),1727 coroutine_kind: Some(coroutine_kind),1728 ..1729 }) = fk.header()1730 {1731 self.dcx().emit_err(errors::ConstAndCoroutine {1732 spans: vec![coroutine_kind.span(), const_span],1733 const_span,1734 coroutine_span: coroutine_kind.span(),1735 coroutine_kind: coroutine_kind.as_str(),1736 span,1737 });1738 }17391740 if let FnKind::Fn(1741 _,1742 _,1743 Fn {1744 sig: FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. },1745 ..1746 },1747 ) = fk1748 {1749 self.handle_missing_abi(*extern_span, id);1750 }17511752 // Functions without bodies cannot have patterns.1753 if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk {1754 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {1755 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {1756 if let Some(ident) = ident {1757 let is_foreign = matches!(ctxt, FnCtxt::Foreign);1758 self.lint_buffer.dyn_buffer_lint(1759 PATTERNS_IN_FNS_WITHOUT_BODY,1760 id,1761 span,1762 move |dcx, level| {1763 let sub = errors::PatternsInFnsWithoutBodySub { ident, span };1764 if is_foreign {1765 errors::PatternsInFnsWithoutBody::Foreign { sub }1766 } else {1767 errors::PatternsInFnsWithoutBody::Bodiless { sub }1768 }1769 .into_diag(dcx, level)1770 },1771 )1772 }1773 } else {1774 match ctxt {1775 FnCtxt::Foreign => self.dcx().emit_err(errors::PatternInForeign { span }),1776 _ => self.dcx().emit_err(errors::PatternInBodiless { span }),1777 };1778 }1779 });1780 }17811782 let tilde_const_allowed =1783 matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))1784 || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))1785 && self1786 .outer_trait_or_trait_impl1787 .as_ref()1788 .and_then(TraitOrImpl::constness)1789 .is_some();17901791 let disallowed = (!tilde_const_allowed).then(|| match fk {1792 FnKind::Fn(_, _, f) => TildeConstReason::Function { ident: f.ident.span },1793 FnKind::Closure(..) => TildeConstReason::Closure,1794 });1795 self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));1796 }17971798 fn visit_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {1799 if let Some(ident) = item.kind.ident()1800 && attr::contains_name(&item.attrs, sym::no_mangle)1801 {1802 self.check_nomangle_item_asciionly(ident, item.span);1803 }18041805 let defaultness = item.kind.defaultness();1806 self.check_defaultness(1807 item.span,1808 defaultness,1809 // `default` is allowed on all associated items in impls.1810 AllowDefault::when(matches!(ctxt, AssocCtxt::Impl { .. })),1811 // `final` is allowed on all associated *functions* in traits.1812 AllowFinal::when(1813 ctxt == AssocCtxt::Trait && matches!(item.kind, AssocItemKind::Fn(..)),1814 ),1815 );18161817 self.check_final_has_body(item, defaultness);18181819 if let AssocCtxt::Impl { .. } = ctxt {1820 match &item.kind {1821 AssocItemKind::Const(box ConstItem { rhs_kind, .. }) => {1822 if !rhs_kind.has_expr() {1823 self.dcx().emit_err(errors::AssocConstWithoutBody {1824 span: item.span,1825 replace_span: self.ending_semi_or_hi(item.span),1826 });1827 }1828 }1829 AssocItemKind::Fn(box Fn { body, .. }) => {1830 if body.is_none() && !self.is_sdylib_interface {1831 self.dcx().emit_err(errors::AssocFnWithoutBody {1832 span: item.span,1833 replace_span: self.ending_semi_or_hi(item.span),1834 });1835 }1836 }1837 AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {1838 if ty.is_none() {1839 self.dcx().emit_err(errors::AssocTypeWithoutBody {1840 span: item.span,1841 replace_span: self.ending_semi_or_hi(item.span),1842 });1843 }1844 self.check_type_no_bounds(bounds, "`impl`s");1845 }1846 _ => {}1847 }1848 }18491850 if let AssocItemKind::Type(ty_alias) = &item.kind1851 && let Err(err) = self.check_type_alias_where_clause_location(ty_alias)1852 {1853 let sugg = match err.sugg {1854 errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,1855 errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {1856 Some((right, snippet))1857 }1858 };1859 let left_sp = self1860 .sess1861 .source_map()1862 .span_extend_prev_while(err.span, char::is_whitespace)1863 .unwrap_or(err.span);1864 self.lint_buffer.dyn_buffer_lint(1865 DEPRECATED_WHERE_CLAUSE_LOCATION,1866 item.id,1867 err.span,1868 move |dcx, level| {1869 let suggestion = match sugg {1870 Some((right_sp, sugg)) => {1871 errors::DeprecatedWhereClauseLocationSugg::MoveToEnd {1872 left: left_sp,1873 right: right_sp,1874 sugg,1875 }1876 }1877 None => errors::DeprecatedWhereClauseLocationSugg::RemoveWhere {1878 span: err.span,1879 },1880 };1881 errors::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level)1882 },1883 );1884 }18851886 match &self.outer_trait_or_trait_impl {1887 Some(parent @ (TraitOrImpl::Trait { .. } | TraitOrImpl::TraitImpl { .. })) => {1888 self.visibility_not_permitted(1889 &item.vis,1890 errors::VisibilityNotPermittedNote::TraitImpl,1891 );1892 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {1893 self.check_trait_fn_not_const(sig.header.constness, parent);1894 self.check_async_fn_in_const_trait_or_impl(sig, parent);1895 }1896 }1897 Some(parent @ TraitOrImpl::Impl { constness }) => {1898 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {1899 self.check_impl_fn_not_const(sig.header.constness, *constness);1900 self.check_async_fn_in_const_trait_or_impl(sig, parent);1901 }1902 }1903 None => {}1904 }19051906 if let AssocItemKind::Const(ci) = &item.kind {1907 self.check_item_named(ci.ident, "const");1908 }19091910 let parent_is_const =1911 self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrImpl::constness).is_some();19121913 match &item.kind {1914 AssocItemKind::Fn(func)1915 if parent_is_const1916 || ctxt == AssocCtxt::Trait1917 || matches!(func.sig.header.constness, Const::Yes(_)) =>1918 {1919 self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);1920 let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);1921 self.visit_fn(kind, &item.attrs, item.span, item.id);1922 }1923 AssocItemKind::Type(_) => {1924 let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {1925 Some(TraitOrImpl::Trait { .. }) => {1926 TildeConstReason::TraitAssocTy { span: item.span }1927 }1928 Some(TraitOrImpl::TraitImpl { .. }) => {1929 TildeConstReason::TraitImplAssocTy { span: item.span }1930 }1931 Some(TraitOrImpl::Impl { .. }) | None => {1932 TildeConstReason::InherentAssocTy { span: item.span }1933 }1934 });1935 self.with_tilde_const(disallowed, |this| {1936 this.with_in_trait_or_impl(None, |this| {1937 visit::walk_assoc_item(this, item, ctxt)1938 })1939 })1940 }1941 _ => self.with_in_trait_or_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),1942 }1943 }19441945 fn visit_anon_const(&mut self, anon_const: &AnonConst) {1946 self.with_tilde_const(1947 Some(TildeConstReason::AnonConst { span: anon_const.value.span }),1948 |this| visit::walk_anon_const(this, anon_const),1949 )1950 }1951}19521953/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems1954/// like it's setting an associated type, provide an appropriate suggestion.1955fn deny_equality_constraints(1956 this: &AstValidator<'_>,1957 predicate: &WhereEqPredicate,1958 predicate_span: Span,1959 generics: &Generics,1960) {1961 let mut err = errors::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None };19621963 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.1964 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind1965 && let TyKind::Path(None, path) = &qself.ty.kind1966 && let [PathSegment { ident, args: None, .. }] = &path.segments[..]1967 {1968 for param in &generics.params {1969 if param.ident == *ident1970 && let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..]1971 {1972 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.1973 let mut assoc_path = full_path.clone();1974 // Remove `Bar` from `Foo::Bar`.1975 assoc_path.segments.pop();1976 let len = assoc_path.segments.len() - 1;1977 let gen_args = args.as_deref().cloned();1978 // Build `<Bar = RhsTy>`.1979 let arg = AngleBracketedArg::Constraint(AssocItemConstraint {1980 id: rustc_ast::node_id::DUMMY_NODE_ID,1981 ident: *ident,1982 gen_args,1983 kind: AssocItemConstraintKind::Equality {1984 term: predicate.rhs_ty.clone().into(),1985 },1986 span: ident.span,1987 });1988 // Add `<Bar = RhsTy>` to `Foo`.1989 match &mut assoc_path.segments[len].args {1990 Some(args) => match args.deref_mut() {1991 GenericArgs::Parenthesized(_) | GenericArgs::ParenthesizedElided(..) => {1992 continue;1993 }1994 GenericArgs::AngleBracketed(args) => {1995 args.args.push(arg);1996 }1997 },1998 empty_args => {1999 *empty_args = Some(2000 AngleBracketedArgs { span: ident.span, args: thin_vec![arg] }.into(),