File is large — showing lines 1–2,000 of 2,309.
1use std::cell::LazyCell;2use std::ops::ControlFlow;34use rustc_abi::{ExternAbi, FieldIdx, ScalableElt};5use rustc_data_structures::unord::{UnordMap, UnordSet};6use rustc_errors::codes::*;7use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan};8use rustc_hir as hir;9use rustc_hir::attrs::ReprAttr::ReprPacked;10use rustc_hir::def::{CtorKind, DefKind};11use rustc_hir::{LangItem, Node, find_attr, intravisit};12use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};13use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc};14use rustc_lint_defs::builtin::{REPR_TRANSPARENT_NON_ZST_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS};15use rustc_macros::Diagnostic;16use rustc_middle::hir::nested_filter;17use rustc_middle::middle::resolve_bound_vars::ResolvedArg;18use rustc_middle::middle::stability::EvalResult;19use rustc_middle::ty::error::TypeErrorToStringExt;20use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};21use rustc_middle::ty::util::Discr;22use rustc_middle::ty::{23 AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,24 TypeVisitable, TypeVisitableExt, Unnormalized, fold_regions,25};26use rustc_session::lint::builtin::UNINHABITED_STATIC;27use rustc_target::spec::{AbiMap, AbiMapping};28use rustc_trait_selection::error_reporting::InferCtxtErrorExt;29use rustc_trait_selection::traits;30use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;31use tracing::{debug, instrument};32use ty::TypingMode;3334use super::compare_impl_item::check_type_bounds;35use super::*;36use crate::check::wfcheck::{37 check_associated_item, check_trait_item, check_variances_for_type_defn, check_where_clauses,38 enter_wf_checking_ctxt,39};4041fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {42 if let ExternAbi::Cdecl { unwind } = abi {43 let c_abi = ExternAbi::C { unwind };44 diag.help(format!("use `extern {c_abi}` instead",));45 } else if let ExternAbi::Stdcall { unwind } = abi {46 let c_abi = ExternAbi::C { unwind };47 let system_abi = ExternAbi::System { unwind };48 diag.help(format!(49 "if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \50 use `extern {system_abi}`"51 ));52 }53}5455pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {56 struct UnsupportedCallingConventions {57 abi: ExternAbi,58 }5960 impl<'a> Diagnostic<'a, ()> for UnsupportedCallingConventions {61 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {62 let Self { abi } = self;63 let mut lint = Diag::new(64 dcx,65 level,66 format!("{abi} is not a supported ABI for the current target"),67 );68 add_abi_diag_help(abi, &mut lint);69 lint70 }71 }72 // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this73 // currently only guards function imports, function definitions, and function pointer types.74 // Functions in trait declarations can still use "deprecated" ABIs without any warning.7576 match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {77 AbiMapping::Direct(..) => (),78 // already erred in rustc_ast_lowering79 AbiMapping::Invalid => {80 tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering"));81 }82 AbiMapping::Deprecated(..) => {83 tcx.emit_node_span_lint(84 UNSUPPORTED_CALLING_CONVENTIONS,85 hir_id,86 span,87 UnsupportedCallingConventions { abi },88 );89 }90 }91}9293pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) {94 if fn_sig.abi() == ExternAbi::Custom {95 // Function definitions that use `extern "custom"` must be naked functions.96 if !find_attr!(tcx, def_id, Naked(_)) {97 tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction {98 span: fn_sig_span,99 naked_span: tcx.def_span(def_id).shrink_to_lo(),100 });101 }102 }103}104105fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {106 let def = tcx.adt_def(def_id);107 let span = tcx.def_span(def_id);108 def.destructor(tcx); // force the destructor to be evaluated109110 if let Some(scalable) = def.repr().scalable {111 check_scalable_vector(tcx, span, def_id, scalable);112 } else if def.repr().simd() {113 check_simd(tcx, span, def_id);114 }115116 check_transparent(tcx, def);117 check_packed(tcx, span, def);118}119120fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {121 let def = tcx.adt_def(def_id);122 let span = tcx.def_span(def_id);123 def.destructor(tcx); // force the destructor to be evaluated124 check_transparent(tcx, def);125 check_union_fields(tcx, span, def_id);126 check_packed(tcx, span, def);127}128129fn allowed_union_or_unsafe_field<'tcx>(130 tcx: TyCtxt<'tcx>,131 ty: Ty<'tcx>,132 typing_env: ty::TypingEnv<'tcx>,133 span: Span,134) -> bool {135 // HACK (not that bad of a hack don't worry): Some codegen tests don't even define proper136 // impls for `Copy`. Let's short-circuit here for this validity check, since a lot of them137 // use unions. We should eventually fix all the tests to define that lang item or use138 // minicore stubs.139 if ty.is_trivially_pure_clone_copy() {140 return true;141 }142 // If `BikeshedGuaranteedNoDrop` is not defined in a `#[no_core]` test, fall back to `Copy`.143 // This is an underapproximation of `BikeshedGuaranteedNoDrop`,144 let def_id = tcx145 .lang_items()146 .get(LangItem::BikeshedGuaranteedNoDrop)147 .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, span));148 let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)) else {149 tcx.dcx().span_delayed_bug(span, "could not normalize field type");150 return true;151 };152 let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);153 infcx.predicate_must_hold_modulo_regions(&Obligation::new(154 tcx,155 ObligationCause::dummy_with_span(span),156 param_env,157 ty::TraitRef::new(tcx, def_id, [ty]),158 ))159}160161/// Check that the fields of the `union` do not need dropping.162fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {163 let def = tcx.adt_def(item_def_id);164 assert!(def.is_union());165166 let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);167 let args = ty::GenericArgs::identity_for_item(tcx, item_def_id);168169 for field in &def.non_enum_variant().fields {170 if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) {171 let (field_span, ty_span) = match tcx.hir_get_if_local(field.did) {172 // We are currently checking the type this field came from, so it must be local.173 Some(Node::Field(field)) => (field.span, field.ty.span),174 _ => unreachable!("mir field has to correspond to hir field"),175 };176 tcx.dcx().emit_err(errors::InvalidUnionField {177 field_span,178 sugg: errors::InvalidUnionFieldSuggestion {179 lo: ty_span.shrink_to_lo(),180 hi: ty_span.shrink_to_hi(),181 },182 note: (),183 });184 return false;185 }186 }187188 true189}190191/// Check that a `static` is inhabited.192fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {193 #[derive(Diagnostic)]194 #[diag("static of uninhabited type")]195 #[note("uninhabited statics cannot be initialized, and any access would be an immediate error")]196 struct StaticOfUninhabitedType;197198 // Make sure statics are inhabited.199 // Other parts of the compiler assume that there are no uninhabited places. In principle it200 // would be enough to check this for `extern` statics, as statics with an initializer will201 // have UB during initialization if they are uninhabited, but there also seems to be no good202 // reason to allow any statics to be uninhabited.203 let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();204 let span = tcx.def_span(def_id);205 let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {206 Ok(l) => l,207 // Foreign statics that overflow their allowed size should emit an error208 Err(LayoutError::SizeOverflow(_))209 if matches!(tcx.def_kind(def_id), DefKind::Static{ .. }210 if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>211 {212 tcx.dcx().emit_err(errors::TooLargeStatic { span });213 return;214 }215 // SIMD types with invalid layout (e.g., zero-length) should emit an error216 Err(e @ LayoutError::InvalidSimd { .. }) => {217 let ty_span = tcx.ty_span(def_id);218 tcx.dcx().span_err(ty_span, e.to_string());219 return;220 }221 // Generic statics are rejected, but we still reach this case.222 Err(e) => {223 tcx.dcx().span_delayed_bug(span, format!("{e:?}"));224 return;225 }226 };227 if layout.is_uninhabited() {228 tcx.emit_node_span_lint(229 UNINHABITED_STATIC,230 tcx.local_def_id_to_hir_id(def_id),231 span,232 StaticOfUninhabitedType,233 );234 }235}236237/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`238/// projections that would result in "inheriting lifetimes".239fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {240 let hir::OpaqueTy { origin, .. } = *tcx.hir_expect_opaque_ty(def_id);241242 // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting243 // `async-std` (and `pub async fn` in general).244 // Since rustdoc doesn't care about the hidden type behind `impl Trait`, just don't look at it!245 // See https://github.com/rust-lang/rust/issues/75100246 if tcx.sess.opts.actually_rustdoc {247 return;248 }249250 if tcx.type_of(def_id).instantiate_identity().skip_norm_wip().references_error() {251 return;252 }253 if check_opaque_for_cycles(tcx, def_id).is_err() {254 return;255 }256257 let _ = check_opaque_meets_bounds(tcx, def_id, origin);258}259260/// Checks that an opaque type does not contain cycles.261pub(super) fn check_opaque_for_cycles<'tcx>(262 tcx: TyCtxt<'tcx>,263 def_id: LocalDefId,264) -> Result<(), ErrorGuaranteed> {265 let args = GenericArgs::identity_for_item(tcx, def_id);266267 // First, try to look at any opaque expansion cycles, considering coroutine fields268 // (even though these aren't necessarily true errors).269 if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {270 let reported = opaque_type_cycle_error(tcx, def_id);271 return Err(reported);272 }273274 Ok(())275}276277/// Check that the hidden type behind `impl Trait` actually implements `Trait`.278///279/// This is mostly checked at the places that specify the opaque type, but we280/// check those cases in the `param_env` of that function, which may have281/// bounds not on this opaque type:282///283/// ```ignore (illustrative)284/// type X<T> = impl Clone;285/// fn f<T: Clone>(t: T) -> X<T> {286/// t287/// }288/// ```289///290/// Without this check the above code is incorrectly accepted: we would ICE if291/// some tried, for example, to clone an `Option<X<&mut ()>>`.292#[instrument(level = "debug", skip(tcx))]293fn check_opaque_meets_bounds<'tcx>(294 tcx: TyCtxt<'tcx>,295 def_id: LocalDefId,296 origin: hir::OpaqueTyOrigin<LocalDefId>,297) -> Result<(), ErrorGuaranteed> {298 let (span, definition_def_id) =299 if let Some((span, def_id)) = best_definition_site_of_opaque(tcx, def_id, origin) {300 (span, Some(def_id))301 } else {302 (tcx.def_span(def_id), None)303 };304305 let defining_use_anchor = match origin {306 hir::OpaqueTyOrigin::FnReturn { parent, .. }307 | hir::OpaqueTyOrigin::AsyncFn { parent, .. }308 | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,309 };310 let param_env = tcx.param_env(defining_use_anchor);311312 // FIXME(#132279): Once `PostBorrowckAnalysis` is supported in the old solver, this branch should be removed.313 let infcx = tcx.infer_ctxt().build(if tcx.next_trait_solver_globally() {314 TypingMode::post_borrowck_analysis(tcx, defining_use_anchor)315 } else {316 TypingMode::analysis_in_body(tcx, defining_use_anchor)317 });318 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);319320 let args = match origin {321 hir::OpaqueTyOrigin::FnReturn { parent, .. }322 | hir::OpaqueTyOrigin::AsyncFn { parent, .. }323 | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(324 tcx, parent,325 )326 .extend_to(tcx, def_id.to_def_id(), |param, _| {327 tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()328 }),329 };330331 let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);332333 // `ReErased` regions appear in the "parent_args" of closures/coroutines.334 // We're ignoring them here and replacing them with fresh region variables.335 // See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs.336 //337 // FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it338 // here rather than using ReErased.339 let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args).skip_norm_wip();340 let hidden_ty = fold_regions(tcx, hidden_ty, |re, _dbi| match re.kind() {341 ty::ReErased => infcx.next_region_var(RegionVariableOrigin::Misc(span)),342 _ => re,343 });344345 // HACK: We eagerly instantiate some bounds to report better errors for them...346 // This isn't necessary for correctness, since we register these bounds when347 // equating the opaque below, but we should clean this up in the new solver.348 for (predicate, pred_span) in tcx349 .explicit_item_bounds(def_id)350 .iter_instantiated_copied(tcx, args)351 .map(Unnormalized::skip_norm_wip)352 {353 let predicate = predicate.fold_with(&mut BottomUpFolder {354 tcx,355 ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty },356 lt_op: |lt| lt,357 ct_op: |ct| ct,358 });359360 ocx.register_obligation(Obligation::new(361 tcx,362 ObligationCause::new(363 span,364 def_id,365 ObligationCauseCode::OpaqueTypeBound(pred_span, definition_def_id),366 ),367 param_env,368 predicate,369 ));370 }371372 let misc_cause = ObligationCause::misc(span, def_id);373 // FIXME: We should just register the item bounds here, rather than equating.374 // FIXME(const_trait_impl): When we do that, please make sure to also register375 // the `[const]` bounds.376 match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {377 Ok(()) => {}378 Err(ty_err) => {379 // Some types may be left "stranded" if they can't be reached380 // from a lowered rustc_middle bound but they're mentioned in the HIR.381 // This will happen, e.g., when a nested opaque is inside of a non-382 // existent associated type, like `impl Trait<Missing = impl Trait>`.383 // See <tests/ui/impl-trait/stranded-opaque.rs>.384 let ty_err = ty_err.to_string(tcx);385 let guar = tcx.dcx().span_delayed_bug(386 span,387 format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),388 );389 return Err(guar);390 }391 }392393 // Additionally require the hidden type to be well-formed with only the generics of the opaque type.394 // Defining use functions may have more bounds than the opaque type, which is ok, as long as the395 // hidden type is well formed even without those bounds.396 let predicate =397 ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));398 ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate));399400 // Check that all obligations are satisfied by the implementation's401 // version.402 let errors = ocx.evaluate_obligations_error_on_ambiguity();403 if !errors.is_empty() {404 let guar = infcx.err_ctxt().report_fulfillment_errors(errors);405 return Err(guar);406 }407408 let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?;409 ocx.resolve_regions_and_report_errors(defining_use_anchor, param_env, wf_tys)?;410411 if infcx.next_trait_solver() {412 Ok(())413 } else if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } =414 origin415 {416 // HACK: this should also fall through to the hidden type check below, but the original417 // implementation had a bug where equivalent lifetimes are not identical. This caused us418 // to reject existing stable code that is otherwise completely fine. The real fix is to419 // compare the hidden types via our type equivalence/relation infra instead of doing an420 // identity check.421 let _ = infcx.take_opaque_types();422 Ok(())423 } else {424 // Check that any hidden types found during wf checking match the hidden types that `type_of` sees.425 for (mut key, mut ty) in infcx.take_opaque_types() {426 ty.ty = infcx.resolve_vars_if_possible(ty.ty);427 key = infcx.resolve_vars_if_possible(key);428 sanity_check_found_hidden_type(tcx, key, ty)?;429 }430 Ok(())431 }432}433434fn best_definition_site_of_opaque<'tcx>(435 tcx: TyCtxt<'tcx>,436 opaque_def_id: LocalDefId,437 origin: hir::OpaqueTyOrigin<LocalDefId>,438) -> Option<(Span, LocalDefId)> {439 struct TaitConstraintLocator<'tcx> {440 opaque_def_id: LocalDefId,441 tcx: TyCtxt<'tcx>,442 }443 impl<'tcx> TaitConstraintLocator<'tcx> {444 fn check(&self, item_def_id: LocalDefId) -> ControlFlow<(Span, LocalDefId)> {445 if !self.tcx.has_typeck_results(item_def_id) {446 return ControlFlow::Continue(());447 }448449 let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);450 // Don't try to check items that cannot possibly constrain the type.451 if !opaque_types_defined_by.contains(&self.opaque_def_id) {452 return ControlFlow::Continue(());453 }454455 if let Some(hidden_ty) = self456 .tcx457 .mir_borrowck(item_def_id)458 .ok()459 .and_then(|opaque_types| opaque_types.get(&self.opaque_def_id))460 {461 ControlFlow::Break((hidden_ty.span, item_def_id))462 } else {463 ControlFlow::Continue(())464 }465 }466 }467 impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {468 type NestedFilter = nested_filter::All;469 type Result = ControlFlow<(Span, LocalDefId)>;470 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {471 self.tcx472 }473 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {474 intravisit::walk_expr(self, ex)475 }476 fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result {477 self.check(it.owner_id.def_id)?;478 intravisit::walk_item(self, it)479 }480 fn visit_impl_item(&mut self, it: &'tcx hir::ImplItem<'tcx>) -> Self::Result {481 self.check(it.owner_id.def_id)?;482 intravisit::walk_impl_item(self, it)483 }484 fn visit_trait_item(&mut self, it: &'tcx hir::TraitItem<'tcx>) -> Self::Result {485 self.check(it.owner_id.def_id)?;486 intravisit::walk_trait_item(self, it)487 }488 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Result {489 intravisit::walk_foreign_item(self, it)490 }491 }492493 let mut locator = TaitConstraintLocator { tcx, opaque_def_id };494 match origin {495 hir::OpaqueTyOrigin::FnReturn { parent, .. }496 | hir::OpaqueTyOrigin::AsyncFn { parent, .. } => locator.check(parent).break_value(),497 hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty: true } => {498 let impl_def_id = tcx.local_parent(parent);499 for assoc in tcx.associated_items(impl_def_id).in_definition_order() {500 match assoc.kind {501 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {502 if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())503 {504 return Some(span);505 }506 }507 ty::AssocKind::Type { .. } => {}508 }509 }510511 None512 }513 hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {514 tcx.hir_walk_toplevel_module(&mut locator).break_value()515 }516 }517}518519fn sanity_check_found_hidden_type<'tcx>(520 tcx: TyCtxt<'tcx>,521 key: ty::OpaqueTypeKey<'tcx>,522 mut ty: ty::ProvisionalHiddenType<'tcx>,523) -> Result<(), ErrorGuaranteed> {524 if ty.ty.is_ty_var() {525 // Nothing was actually constrained.526 return Ok(());527 }528 if let &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = ty.ty.kind() {529 if def_id == key.def_id.to_def_id() && args == key.args {530 // Nothing was actually constrained, this is an opaque usage that was531 // only discovered to be opaque after inference vars resolved.532 return Ok(());533 }534 }535 let erase_re_vars = |ty: Ty<'tcx>| {536 fold_regions(tcx, ty, |r, _| match r.kind() {537 RegionKind::ReVar(_) => tcx.lifetimes.re_erased,538 _ => r,539 })540 };541 // Closures frequently end up containing erased lifetimes in their final representation.542 // These correspond to lifetime variables that never got resolved, so we patch this up here.543 ty.ty = erase_re_vars(ty.ty);544 // Get the hidden type.545 let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args).skip_norm_wip();546 let hidden_ty = erase_re_vars(hidden_ty);547548 // If the hidden types differ, emit a type mismatch diagnostic.549 if hidden_ty == ty.ty {550 Ok(())551 } else {552 let span = tcx.def_span(key.def_id);553 let other = ty::ProvisionalHiddenType { ty: hidden_ty, span };554 Err(ty.build_mismatch_error(&other, tcx)?.emit())555 }556}557558/// Check that the opaque's precise captures list is valid (if present).559/// We check this for regular `impl Trait`s and also RPITITs, even though the latter560/// are technically GATs.561///562/// This function is responsible for:563/// 1. Checking that all type/const params are mention in the captures list.564/// 2. Checking that all lifetimes that are implicitly captured are mentioned.565/// 3. Asserting that all parameters mentioned in the captures list are invariant.566fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {567 let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();568 let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {569 hir::GenericBound::Use(bounds, ..) => Some(bounds),570 _ => None,571 }) else {572 // No precise capturing args; nothing to validate573 return;574 };575576 let mut expected_captures = UnordSet::default();577 let mut shadowed_captures = UnordSet::default();578 let mut seen_params = UnordMap::default();579 let mut prev_non_lifetime_param = None;580 for arg in precise_capturing_args {581 let (hir_id, ident) = match *arg {582 hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {583 hir_id,584 ident,585 ..586 }) => {587 if prev_non_lifetime_param.is_none() {588 prev_non_lifetime_param = Some(ident);589 }590 (hir_id, ident)591 }592 hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => {593 if let Some(prev_non_lifetime_param) = prev_non_lifetime_param {594 tcx.dcx().emit_err(errors::LifetimesMustBeFirst {595 lifetime_span: ident.span,596 name: ident.name,597 other_span: prev_non_lifetime_param.span,598 });599 }600 (hir_id, ident)601 }602 };603604 let ident = ident.normalize_to_macros_2_0();605 if let Some(span) = seen_params.insert(ident, ident.span) {606 tcx.dcx().emit_err(errors::DuplicatePreciseCapture {607 name: ident.name,608 first_span: span,609 second_span: ident.span,610 });611 }612613 match tcx.named_bound_var(hir_id) {614 Some(ResolvedArg::EarlyBound(def_id)) => {615 expected_captures.insert(def_id.to_def_id());616617 // Make sure we allow capturing these lifetimes through `Self` and618 // `T::Assoc` projection syntax, too. These will occur when we only619 // see lifetimes are captured after hir-lowering -- this aligns with620 // the cases that were stabilized with the `impl_trait_projection`621 // feature -- see <https://github.com/rust-lang/rust/pull/115659>.622 if let DefKind::LifetimeParam = tcx.def_kind(def_id)623 && let Some(def_id) = tcx624 .map_opaque_lifetime_to_parent_lifetime(def_id)625 .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))626 {627 shadowed_captures.insert(def_id);628 }629 }630 _ => {631 tcx.dcx()632 .span_delayed_bug(tcx.hir_span(hir_id), "parameter should have been resolved");633 }634 }635 }636637 let variances = tcx.variances_of(opaque_def_id);638 let mut def_id = Some(opaque_def_id.to_def_id());639 while let Some(generics) = def_id {640 let generics = tcx.generics_of(generics);641 def_id = generics.parent;642643 for param in &generics.own_params {644 if expected_captures.contains(¶m.def_id) {645 assert_eq!(646 variances[param.index as usize],647 ty::Invariant,648 "precise captured param should be invariant"649 );650 continue;651 }652 // If a param is shadowed by a early-bound (duplicated) lifetime, then653 // it may or may not be captured as invariant, depending on if it shows654 // up through `Self` or `T::Assoc` syntax.655 if shadowed_captures.contains(¶m.def_id) {656 continue;657 }658659 match param.kind {660 ty::GenericParamDefKind::Lifetime => {661 let use_span = tcx.def_span(param.def_id);662 let opaque_span = tcx.def_span(opaque_def_id);663 // Check if the lifetime param was captured but isn't named in the precise captures list.664 if variances[param.index as usize] == ty::Invariant {665 if let DefKind::OpaqueTy = tcx.def_kind(tcx.parent(param.def_id))666 && let Some(def_id) = tcx667 .map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())668 .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))669 {670 tcx.dcx().emit_err(errors::LifetimeNotCaptured {671 opaque_span,672 use_span,673 param_span: tcx.def_span(def_id),674 });675 } else {676 if tcx.def_kind(tcx.parent(param.def_id)) == DefKind::Trait {677 tcx.dcx().emit_err(errors::LifetimeImplicitlyCaptured {678 opaque_span,679 param_span: tcx.def_span(param.def_id),680 });681 } else {682 // If the `use_span` is actually just the param itself, then we must683 // have not duplicated the lifetime but captured the original.684 // The "effective" `use_span` will be the span of the opaque itself,685 // and the param span will be the def span of the param.686 tcx.dcx().emit_err(errors::LifetimeNotCaptured {687 opaque_span,688 use_span: opaque_span,689 param_span: use_span,690 });691 }692 }693 continue;694 }695 }696 ty::GenericParamDefKind::Type { .. } => {697 if matches!(tcx.def_kind(param.def_id), DefKind::Trait | DefKind::TraitAlias) {698 // FIXME(precise_capturing): Structured suggestion for this would be useful699 tcx.dcx().emit_err(errors::SelfTyNotCaptured {700 trait_span: tcx.def_span(param.def_id),701 opaque_span: tcx.def_span(opaque_def_id),702 });703 } else {704 // FIXME(precise_capturing): Structured suggestion for this would be useful705 tcx.dcx().emit_err(errors::ParamNotCaptured {706 param_span: tcx.def_span(param.def_id),707 opaque_span: tcx.def_span(opaque_def_id),708 kind: "type",709 });710 }711 }712 ty::GenericParamDefKind::Const { .. } => {713 // FIXME(precise_capturing): Structured suggestion for this would be useful714 tcx.dcx().emit_err(errors::ParamNotCaptured {715 param_span: tcx.def_span(param.def_id),716 opaque_span: tcx.def_span(opaque_def_id),717 kind: "const",718 });719 }720 }721 }722 }723}724725fn is_enum_of_nonnullable_ptr<'tcx>(726 tcx: TyCtxt<'tcx>,727 adt_def: AdtDef<'tcx>,728 args: GenericArgsRef<'tcx>,729) -> bool {730 if adt_def.repr().inhibit_enum_layout_opt() {731 return false;732 }733734 let [var_one, var_two] = &adt_def.variants().raw[..] else {735 return false;736 };737 let (([], [field]) | ([field], [])) = (&var_one.fields.raw[..], &var_two.fields.raw[..]) else {738 return false;739 };740 matches!(field.ty(tcx, args).kind(), ty::FnPtr(..) | ty::Ref(..))741}742743fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {744 if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {745 if match tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind() {746 ty::RawPtr(_, _) => false,747 ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),748 _ => true,749 } {750 tcx.dcx().emit_err(errors::LinkageType { span: tcx.def_span(def_id) });751 }752 }753}754755pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {756 let mut res = Ok(());757 let generics = tcx.generics_of(def_id);758759 for param in &generics.own_params {760 match param.kind {761 ty::GenericParamDefKind::Lifetime { .. } => {}762 ty::GenericParamDefKind::Type { has_default, .. } => {763 if has_default {764 tcx.ensure_ok().type_of(param.def_id);765 }766 }767 ty::GenericParamDefKind::Const { has_default, .. } => {768 tcx.ensure_ok().type_of(param.def_id);769 if has_default {770 // need to store default and type of default771 let ct = tcx.const_param_default(param.def_id).skip_binder();772 if let ty::ConstKind::Unevaluated(uv) = ct.kind() {773 tcx.ensure_ok().type_of(uv.def);774 }775 }776 }777 }778 }779780 match tcx.def_kind(def_id) {781 DefKind::Static { .. } => {782 tcx.ensure_ok().generics_of(def_id);783 tcx.ensure_ok().type_of(def_id);784 tcx.ensure_ok().predicates_of(def_id);785786 check_static_inhabited(tcx, def_id);787 check_static_linkage(tcx, def_id);788 let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();789 res = res.and(wfcheck::check_static_item(790 tcx, def_id, ty, /* should_check_for_sync */ true,791 ));792793 // Only `Node::Item` and `Node::ForeignItem` still have HIR based794 // checks. Returning early here does not miss any checks and795 // avoids this query from having a direct dependency edge on the HIR796 return res;797 }798 DefKind::Enum => {799 tcx.ensure_ok().generics_of(def_id);800 tcx.ensure_ok().type_of(def_id);801 tcx.ensure_ok().predicates_of(def_id);802 crate::collect::lower_enum_variant_types(tcx, def_id);803 check_enum(tcx, def_id);804 check_variances_for_type_defn(tcx, def_id);805 }806 DefKind::Fn => {807 tcx.ensure_ok().generics_of(def_id);808 tcx.ensure_ok().type_of(def_id);809 tcx.ensure_ok().predicates_of(def_id);810 tcx.ensure_ok().fn_sig(def_id);811 tcx.ensure_ok().codegen_fn_attrs(def_id);812 if let Some(i) = tcx.intrinsic(def_id) {813 intrinsic::check_intrinsic_type(814 tcx,815 def_id,816 tcx.def_ident_span(def_id).unwrap(),817 i.name,818 )819 }820 }821 DefKind::Impl { of_trait } => {822 tcx.ensure_ok().generics_of(def_id);823 tcx.ensure_ok().type_of(def_id);824 tcx.ensure_ok().predicates_of(def_id);825 tcx.ensure_ok().associated_items(def_id);826 if of_trait {827 let impl_trait_header = tcx.impl_trait_header(def_id);828 res = res.and(tcx.ensure_result().coherent_trait(829 impl_trait_header.trait_ref.instantiate_identity().skip_norm_wip().def_id,830 ));831832 if res.is_ok() {833 // Checking this only makes sense if the all trait impls satisfy basic834 // requirements (see `coherent_trait` query), otherwise835 // we run into infinite recursions a lot.836 check_impl_items_against_trait(tcx, def_id, impl_trait_header);837 }838 }839 }840 DefKind::Trait => {841 tcx.ensure_ok().generics_of(def_id);842 tcx.ensure_ok().trait_def(def_id);843 tcx.ensure_ok().explicit_super_predicates_of(def_id);844 tcx.ensure_ok().predicates_of(def_id);845 tcx.ensure_ok().associated_items(def_id);846 let assoc_items = tcx.associated_items(def_id);847848 for &assoc_item in assoc_items.in_definition_order() {849 match assoc_item.kind {850 ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {851 let trait_args = GenericArgs::identity_for_item(tcx, def_id);852 let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(853 tcx,854 assoc_item,855 assoc_item,856 ty::TraitRef::new_from_args(tcx, def_id.to_def_id(), trait_args),857 );858 }859 _ => {}860 }861 }862 }863 DefKind::TraitAlias => {864 tcx.ensure_ok().generics_of(def_id);865 tcx.ensure_ok().explicit_implied_predicates_of(def_id);866 tcx.ensure_ok().explicit_super_predicates_of(def_id);867 tcx.ensure_ok().predicates_of(def_id);868 }869 def_kind @ (DefKind::Struct | DefKind::Union) => {870 tcx.ensure_ok().generics_of(def_id);871 tcx.ensure_ok().type_of(def_id);872 tcx.ensure_ok().predicates_of(def_id);873874 let adt = tcx.adt_def(def_id).non_enum_variant();875 for f in adt.fields.iter() {876 tcx.ensure_ok().generics_of(f.did);877 tcx.ensure_ok().type_of(f.did);878 tcx.ensure_ok().predicates_of(f.did);879 }880881 if let Some((_, ctor_def_id)) = adt.ctor {882 crate::collect::lower_variant_ctor(tcx, ctor_def_id.expect_local());883 }884 match def_kind {885 DefKind::Struct => check_struct(tcx, def_id),886 DefKind::Union => check_union(tcx, def_id),887 _ => unreachable!(),888 }889 check_variances_for_type_defn(tcx, def_id);890 }891 DefKind::OpaqueTy => {892 check_opaque_precise_captures(tcx, def_id);893894 let origin = tcx.local_opaque_ty_origin(def_id);895 if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }896 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin897 && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)898 && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()899 {900 // Skip opaques from RPIT in traits with no default body.901 } else {902 check_opaque(tcx, def_id);903 }904905 tcx.ensure_ok().predicates_of(def_id);906 tcx.ensure_ok().explicit_item_bounds(def_id);907 tcx.ensure_ok().explicit_item_self_bounds(def_id);908 if tcx.is_conditionally_const(def_id) {909 tcx.ensure_ok().explicit_implied_const_bounds(def_id);910 tcx.ensure_ok().const_conditions(def_id);911 }912913 // Only `Node::Item` and `Node::ForeignItem` still have HIR based914 // checks. Returning early here does not miss any checks and915 // avoids this query from having a direct dependency edge on the HIR916 return res;917 }918 DefKind::Const { .. } => {919 tcx.ensure_ok().generics_of(def_id);920 tcx.ensure_ok().type_of(def_id);921 tcx.ensure_ok().predicates_of(def_id);922923 res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {924 let ty = tcx.type_of(def_id).instantiate_identity();925 let ty_span = tcx.ty_span(def_id);926 let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);927 wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into());928 wfcx.register_bound(929 traits::ObligationCause::new(930 ty_span,931 def_id,932 ObligationCauseCode::SizedConstOrStatic,933 ),934 tcx.param_env(def_id),935 ty,936 tcx.require_lang_item(LangItem::Sized, ty_span),937 );938 check_where_clauses(wfcx, def_id);939940 if tcx.is_type_const(def_id) {941 wfcheck::check_type_const(wfcx, def_id, ty, true)?;942 }943 Ok(())944 }));945946 // Only `Node::Item` and `Node::ForeignItem` still have HIR based947 // checks. Returning early here does not miss any checks and948 // avoids this query from having a direct dependency edge on the HIR949 return res;950 }951 DefKind::TyAlias => {952 tcx.ensure_ok().generics_of(def_id);953 tcx.ensure_ok().type_of(def_id);954 tcx.ensure_ok().predicates_of(def_id);955 check_type_alias_type_params_are_used(tcx, def_id);956 let ty = tcx.type_of(def_id).instantiate_identity();957 let span = tcx.def_span(def_id);958 if tcx.type_alias_is_lazy(def_id) {959 res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {960 let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);961 wfcx.register_wf_obligation(962 span,963 Some(WellFormedLoc::Ty(def_id)),964 item_ty.into(),965 );966 check_where_clauses(wfcx, def_id);967 Ok(())968 }));969 check_variances_for_type_defn(tcx, def_id);970 } else {971 res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {972 // HACK: We sometimes incidentally check that const arguments have the correct973 // type as a side effect of the anon const desugaring. To make this "consistent"974 // for users we explicitly check `ConstArgHasType` clauses so that const args975 // that don't go through an anon const still have their types checked.976 //977 // We use the unnormalized type as this mirrors the behaviour that we previously978 // would have had when all const arguments were anon consts.979 //980 // Changing this to normalized obligations is a breaking change:981 // `type Bar = [(); panic!()];` would become an error982 if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty.skip_norm_wip())983 {984 let filtered_obligations =985 unnormalized_obligations.into_iter().filter(|o| {986 matches!(o.predicate.kind().skip_binder(),987 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _))988 if matches!(ct.kind(), ty::ConstKind::Param(..)))989 });990 wfcx.ocx.register_obligations(filtered_obligations)991 }992 Ok(())993 }));994 }995996 // Only `Node::Item` and `Node::ForeignItem` still have HIR based997 // checks. Returning early here does not miss any checks and998 // avoids this query from having a direct dependency edge on the HIR999 return res;1000 }1001 DefKind::ForeignMod => {1002 let it = tcx.hir_expect_item(def_id);1003 let hir::ItemKind::ForeignMod { abi, items } = it.kind else {1004 return Ok(());1005 };10061007 check_abi(tcx, it.hir_id(), it.span, abi);10081009 for &item in items {1010 let def_id = item.owner_id.def_id;10111012 let generics = tcx.generics_of(def_id);1013 let own_counts = generics.own_counts();1014 if generics.own_params.len() - own_counts.lifetimes != 0 {1015 let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {1016 (_, 0) => ("type", "types", Some("u32")),1017 // We don't specify an example value, because we can't generate1018 // a valid value for any type.1019 (0, _) => ("const", "consts", None),1020 _ => ("type or const", "types or consts", None),1021 };1022 let name = if find_attr!(tcx, def_id, RustcEiiForeignItem) {1023 "externally implementable items"1024 } else {1025 "foreign items"1026 };10271028 let span = tcx.def_span(def_id);1029 struct_span_code_err!(1030 tcx.dcx(),1031 span,1032 E0044,1033 "{name} may not have {kinds} parameters",1034 )1035 .with_span_label(span, format!("can't have {kinds} parameters"))1036 .with_help(1037 // FIXME: once we start storing spans for type arguments, turn this1038 // into a suggestion.1039 format!(1040 "replace the {} parameters with concrete {}{}",1041 kinds,1042 kinds_pl,1043 egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),1044 ),1045 )1046 .emit();1047 }10481049 tcx.ensure_ok().generics_of(def_id);1050 tcx.ensure_ok().type_of(def_id);1051 tcx.ensure_ok().predicates_of(def_id);1052 if tcx.is_conditionally_const(def_id) {1053 tcx.ensure_ok().explicit_implied_const_bounds(def_id);1054 tcx.ensure_ok().const_conditions(def_id);1055 }1056 match tcx.def_kind(def_id) {1057 DefKind::Fn => {1058 tcx.ensure_ok().codegen_fn_attrs(def_id);1059 tcx.ensure_ok().fn_sig(def_id);1060 let item = tcx.hir_foreign_item(item);1061 let hir::ForeignItemKind::Fn(sig, ..) = item.kind else { bug!() };1062 check_c_variadic_abi(tcx, sig.decl, abi, item.span);1063 }1064 DefKind::Static { .. } => {1065 tcx.ensure_ok().codegen_fn_attrs(def_id);1066 }1067 _ => (),1068 }1069 }1070 }1071 DefKind::Closure => {1072 // This is guaranteed to be called by metadata encoding,1073 // we still call it in wfcheck eagerly to ensure errors in codegen1074 // attrs prevent lints from spamming the output.1075 tcx.ensure_ok().codegen_fn_attrs(def_id);1076 // We do not call `type_of` for closures here as that1077 // depends on typecheck and would therefore hide1078 // any further errors in case one typeck fails.10791080 // Only `Node::Item` and `Node::ForeignItem` still have HIR based1081 // checks. Returning early here does not miss any checks and1082 // avoids this query from having a direct dependency edge on the HIR1083 return res;1084 }1085 DefKind::AssocFn => {1086 tcx.ensure_ok().codegen_fn_attrs(def_id);1087 tcx.ensure_ok().type_of(def_id);1088 tcx.ensure_ok().fn_sig(def_id);1089 tcx.ensure_ok().predicates_of(def_id);1090 res = res.and(check_associated_item(tcx, def_id));1091 let assoc_item = tcx.associated_item(def_id);1092 match assoc_item.container {1093 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {}1094 ty::AssocContainer::Trait => {1095 res = res.and(check_trait_item(tcx, def_id));1096 }1097 }10981099 // Only `Node::Item` and `Node::ForeignItem` still have HIR based1100 // checks. Returning early here does not miss any checks and1101 // avoids this query from having a direct dependency edge on the HIR1102 return res;1103 }1104 DefKind::AssocConst { .. } => {1105 tcx.ensure_ok().type_of(def_id);1106 tcx.ensure_ok().predicates_of(def_id);1107 res = res.and(check_associated_item(tcx, def_id));1108 let assoc_item = tcx.associated_item(def_id);1109 match assoc_item.container {1110 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {}1111 ty::AssocContainer::Trait => {1112 res = res.and(check_trait_item(tcx, def_id));1113 }1114 }11151116 // Only `Node::Item` and `Node::ForeignItem` still have HIR based1117 // checks. Returning early here does not miss any checks and1118 // avoids this query from having a direct dependency edge on the HIR1119 return res;1120 }1121 DefKind::AssocTy => {1122 tcx.ensure_ok().predicates_of(def_id);1123 res = res.and(check_associated_item(tcx, def_id));11241125 let assoc_item = tcx.associated_item(def_id);1126 let has_type = match assoc_item.container {1127 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,1128 ty::AssocContainer::Trait => {1129 tcx.ensure_ok().explicit_item_bounds(def_id);1130 tcx.ensure_ok().explicit_item_self_bounds(def_id);1131 if tcx.is_conditionally_const(def_id) {1132 tcx.ensure_ok().explicit_implied_const_bounds(def_id);1133 tcx.ensure_ok().const_conditions(def_id);1134 }1135 res = res.and(check_trait_item(tcx, def_id));1136 assoc_item.defaultness(tcx).has_value()1137 }1138 };1139 if has_type {1140 tcx.ensure_ok().type_of(def_id);1141 }11421143 // Only `Node::Item` and `Node::ForeignItem` still have HIR based1144 // checks. Returning early here does not miss any checks and1145 // avoids this query from having a direct dependency edge on the HIR1146 return res;1147 }11481149 // Only `Node::Item` and `Node::ForeignItem` still have HIR based1150 // checks. Returning early here does not miss any checks and1151 // avoids this query from having a direct dependency edge on the HIR1152 DefKind::AnonConst | DefKind::InlineConst => return res,1153 _ => {}1154 }1155 let node = tcx.hir_node_by_def_id(def_id);1156 res.and(match node {1157 hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),1158 hir::Node::Item(item) => wfcheck::check_item(tcx, item),1159 hir::Node::ForeignItem(item) => wfcheck::check_foreign_item(tcx, item),1160 _ => unreachable!("{node:?}"),1161 })1162}11631164pub(super) fn check_specialization_validity<'tcx>(1165 tcx: TyCtxt<'tcx>,1166 trait_def: &ty::TraitDef,1167 trait_item: ty::AssocItem,1168 impl_id: DefId,1169 impl_item: DefId,1170) {1171 let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) else { return };1172 let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| {1173 if parent.is_from_trait() {1174 None1175 } else {1176 Some((parent, parent.item(tcx, trait_item.def_id)))1177 }1178 });11791180 let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {1181 match parent_item {1182 // Parent impl exists, and contains the parent item we're trying to specialize, but1183 // doesn't mark it `default`.1184 Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {1185 Some(Err(parent_impl.def_id()))1186 }11871188 // Parent impl contains item and makes it specializable.1189 Some(_) => Some(Ok(())),11901191 // Parent impl doesn't mention the item. This means it's inherited from the1192 // grandparent. In that case, if parent is a `default impl`, inherited items use the1193 // "defaultness" from the grandparent, else they are final.1194 None => {1195 if tcx.defaultness(parent_impl.def_id()).is_default() {1196 None1197 } else {1198 Some(Err(parent_impl.def_id()))1199 }1200 }1201 }1202 });12031204 // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the1205 // item. This is allowed, the item isn't actually getting specialized here.1206 let result = opt_result.unwrap_or(Ok(()));12071208 if let Err(parent_impl) = result {1209 if !tcx.is_impl_trait_in_trait(impl_item) {1210 let span = tcx.def_span(impl_item);1211 let ident = tcx.item_ident(impl_item);12121213 let err = match tcx.span_of_impl(parent_impl) {1214 Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },1215 Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },1216 };12171218 tcx.dcx().emit_err(err);1219 } else {1220 tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));1221 }1222 }1223}12241225fn check_overriding_final_trait_item<'tcx>(1226 tcx: TyCtxt<'tcx>,1227 trait_item: ty::AssocItem,1228 impl_item: ty::AssocItem,1229) {1230 if trait_item.defaultness(tcx).is_final() {1231 tcx.dcx().emit_err(errors::OverridingFinalTraitFunction {1232 impl_span: tcx.def_span(impl_item.def_id),1233 trait_span: tcx.def_span(trait_item.def_id),1234 ident: tcx.item_ident(impl_item.def_id),1235 });1236 }1237}12381239fn check_impl_items_against_trait<'tcx>(1240 tcx: TyCtxt<'tcx>,1241 impl_id: LocalDefId,1242 impl_trait_header: ty::ImplTraitHeader<'tcx>,1243) {1244 let trait_ref = impl_trait_header.trait_ref.instantiate_identity().skip_norm_wip();1245 // If the trait reference itself is erroneous (so the compilation is going1246 // to fail), skip checking the items here -- the `impl_item` table in `tcx`1247 // isn't populated for such impls.1248 if trait_ref.references_error() {1249 return;1250 }12511252 let impl_item_refs = tcx.associated_item_def_ids(impl_id);12531254 // Negative impls are not expected to have any items1255 match impl_trait_header.polarity {1256 ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}1257 ty::ImplPolarity::Negative => {1258 if let [first_item_ref, ..] = *impl_item_refs {1259 let first_item_span = tcx.def_span(first_item_ref);1260 struct_span_code_err!(1261 tcx.dcx(),1262 first_item_span,1263 E0749,1264 "negative impls cannot have any items"1265 )1266 .emit();1267 }1268 return;1269 }1270 }12711272 let trait_def = tcx.trait_def(trait_ref.def_id);12731274 let self_is_guaranteed_unsize_self = tcx.impl_self_is_guaranteed_unsized(impl_id);12751276 for &impl_item in impl_item_refs {1277 let ty_impl_item = tcx.associated_item(impl_item);1278 let ty_trait_item = match ty_impl_item.expect_trait_impl() {1279 Ok(trait_item_id) => tcx.associated_item(trait_item_id),1280 Err(ErrorGuaranteed { .. }) => continue,1281 };12821283 let res = tcx.ensure_result().compare_impl_item(impl_item.expect_local());1284 if res.is_ok() {1285 match ty_impl_item.kind {1286 ty::AssocKind::Fn { .. } => {1287 compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(1288 tcx,1289 ty_impl_item,1290 ty_trait_item,1291 tcx.impl_trait_ref(ty_impl_item.container_id(tcx))1292 .instantiate_identity()1293 .skip_norm_wip(),1294 );1295 }1296 ty::AssocKind::Const { .. } => {}1297 ty::AssocKind::Type { .. } => {}1298 }1299 }13001301 if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) {1302 tcx.emit_node_span_lint(1303 rustc_lint_defs::builtin::DEAD_CODE,1304 tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),1305 tcx.def_span(ty_impl_item.def_id),1306 errors::UselessImplItem,1307 )1308 }13091310 check_specialization_validity(1311 tcx,1312 trait_def,1313 ty_trait_item,1314 impl_id.to_def_id(),1315 impl_item,1316 );13171318 check_overriding_final_trait_item(tcx, ty_trait_item, ty_impl_item);1319 }13201321 if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {1322 // Check for missing items from trait1323 let mut missing_items = Vec::new();13241325 let mut must_implement_one_of: Option<&[Ident]> =1326 trait_def.must_implement_one_of.as_deref();13271328 for &trait_item_id in tcx.associated_item_def_ids(trait_ref.def_id) {1329 let leaf_def = ancestors.leaf_def(tcx, trait_item_id);13301331 let is_implemented = leaf_def1332 .as_ref()1333 .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());13341335 if !is_implemented1336 && tcx.defaultness(impl_id).is_final()1337 // unsized types don't need to implement methods that have `Self: Sized` bounds.1338 && !(self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(trait_item_id))1339 {1340 missing_items.push(tcx.associated_item(trait_item_id));1341 }13421343 // true if this item is specifically implemented in this impl1344 let is_implemented_here =1345 leaf_def.as_ref().is_some_and(|node_item| !node_item.defining_node.is_from_trait());13461347 if !is_implemented_here {1348 let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));1349 match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {1350 EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(1351 tcx,1352 full_impl_span,1353 trait_item_id,1354 feature,1355 reason,1356 issue,1357 ),13581359 // Unmarked default bodies are considered stable (at least for now).1360 EvalResult::Allow | EvalResult::Unmarked => {}1361 }1362 }13631364 if let Some(required_items) = &must_implement_one_of {1365 if is_implemented_here {1366 let trait_item = tcx.associated_item(trait_item_id);1367 if required_items.contains(&trait_item.ident(tcx)) {1368 must_implement_one_of = None;1369 }1370 }1371 }13721373 if let Some(leaf_def) = &leaf_def1374 && !leaf_def.is_final()1375 && let def_id = leaf_def.item.def_id1376 && tcx.impl_method_has_trait_impl_trait_tys(def_id)1377 {1378 let def_kind = tcx.def_kind(def_id);1379 let descr = tcx.def_kind_descr(def_kind, def_id);1380 let (msg, feature) = if tcx.asyncness(def_id).is_async() {1381 (1382 format!("async {descr} in trait cannot be specialized"),1383 "async functions in traits",1384 )1385 } else {1386 (1387 format!(1388 "{descr} with return-position `impl Trait` in trait cannot be specialized"1389 ),1390 "return position `impl Trait` in traits",1391 )1392 };1393 tcx.dcx()1394 .struct_span_err(tcx.def_span(def_id), msg)1395 .with_note(format!(1396 "specialization behaves in inconsistent and surprising ways with \1397 {feature}, and for now is disallowed"1398 ))1399 .emit();1400 }1401 }14021403 if !missing_items.is_empty() {1404 let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));1405 missing_items_err(tcx, impl_id, &missing_items, full_impl_span);1406 }14071408 if let Some(missing_items) = must_implement_one_of {1409 let attr_span = find_attr!(tcx, trait_ref.def_id, RustcMustImplementOneOf {attr_span, ..} => *attr_span);14101411 missing_items_must_implement_one_of_err(1412 tcx,1413 tcx.def_span(impl_id),1414 missing_items,1415 attr_span,1416 );1417 }1418 }1419}14201421fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {1422 let t = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();1423 if let ty::Adt(def, args) = t.kind()1424 && def.is_struct()1425 {1426 let fields = &def.non_enum_variant().fields;1427 if fields.is_empty() {1428 struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();1429 return;1430 }14311432 let array_field = &fields[FieldIdx::ZERO];1433 let array_ty = array_field.ty(tcx, args);1434 let ty::Array(element_ty, len_const) = array_ty.kind() else {1435 struct_span_code_err!(1436 tcx.dcx(),1437 sp,1438 E0076,1439 "SIMD vector's only field must be an array"1440 )1441 .with_span_label(tcx.def_span(array_field.did), "not an array")1442 .emit();1443 return;1444 };14451446 if let Some(second_field) = fields.get(FieldIdx::ONE) {1447 struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields")1448 .with_span_label(tcx.def_span(second_field.did), "excess field")1449 .emit();1450 return;1451 }14521453 // FIXME(repr_simd): This check is nice, but perhaps unnecessary due to the fact1454 // we do not expect users to implement their own `repr(simd)` types. If they could,1455 // this check is easily side-steppable by hiding the const behind normalization.1456 // The consequence is that the error is, in general, only observable post-mono.1457 if let Some(len) = len_const.try_to_target_usize(tcx) {1458 if len == 0 {1459 struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();1460 return;1461 } else if len > MAX_SIMD_LANES {1462 struct_span_code_err!(1463 tcx.dcx(),1464 sp,1465 E0075,1466 "SIMD vector cannot have more than {MAX_SIMD_LANES} elements",1467 )1468 .emit();1469 return;1470 }1471 }14721473 // Check that we use types valid for use in the lanes of a SIMD "vector register"1474 // These are scalar types which directly match a "machine" type1475 // Yes: Integers, floats, "thin" pointers1476 // No: char, "wide" pointers, compound types1477 match element_ty.kind() {1478 ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors1479 ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok1480 _ => {1481 struct_span_code_err!(1482 tcx.dcx(),1483 sp,1484 E0077,1485 "SIMD vector element type should be a \1486 primitive scalar (integer/float/pointer) type"1487 )1488 .emit();1489 return;1490 }1491 }1492 }1493}14941495#[tracing::instrument(skip(tcx), level = "debug")]1496fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) {1497 let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();1498 let ty::Adt(def, args) = ty.kind() else { return };1499 if !def.is_struct() {1500 tcx.dcx().delayed_bug("`rustc_scalable_vector` applied to non-struct");1501 return;1502 }15031504 let fields = &def.non_enum_variant().fields;1505 match scalable {1506 ScalableElt::ElementCount(..) if fields.is_empty() => {1507 let mut err =1508 tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");1509 err.help("scalable vector types' only field must be a primitive scalar type");1510 err.emit();1511 return;1512 }1513 ScalableElt::ElementCount(..) if fields.len() >= 2 => {1514 tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit();1515 return;1516 }1517 ScalableElt::Container if fields.is_empty() => {1518 let mut err = tcx1519 .dcx()1520 .struct_span_err(span, "scalable vector tuples must have at least one field");1521 err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");1522 err.emit();1523 return;1524 }1525 ScalableElt::Container if fields.len() > 8 => {1526 let mut err = tcx1527 .dcx()1528 .struct_span_err(span, "scalable vector tuples can have at most eight fields");1529 err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");1530 err.emit();1531 return;1532 }1533 _ => {}1534 }15351536 match scalable {1537 ScalableElt::ElementCount(..) => {1538 let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args);15391540 // Check that `element_ty` only uses types valid in the lanes of a scalable vector1541 // register: scalar types which directly match a "machine" type - integers, floats and1542 // bools1543 match element_ty.kind() {1544 ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool => (),1545 _ => {1546 let mut err = tcx.dcx().struct_span_err(1547 span,1548 "element type of a scalable vector must be a primitive scalar",1549 );1550 err.help("only `u*`, `i*`, `f*` and `bool` types are accepted");1551 err.emit();1552 }1553 }1554 }1555 ScalableElt::Container => {1556 let mut prev_field_ty = None;1557 for field in fields.iter() {1558 let element_ty = field.ty(tcx, args);1559 if let ty::Adt(def, _) = element_ty.kind()1560 && def.repr().scalable()1561 {1562 match def1563 .repr()1564 .scalable1565 .expect("`repr().scalable.is_some()` != `repr().scalable()`")1566 {1567 ScalableElt::ElementCount(_) => { /* expected field */ }1568 ScalableElt::Container => {1569 tcx.dcx().span_err(1570 tcx.def_span(field.did),1571 "scalable vector structs cannot contain other scalable vector structs",1572 );1573 break;1574 }1575 }1576 } else {1577 tcx.dcx().span_err(1578 tcx.def_span(field.did),1579 "scalable vector structs can only have scalable vector fields",1580 );1581 break;1582 }15831584 if let Some(prev_ty) = prev_field_ty.replace(element_ty)1585 && prev_ty != element_ty1586 {1587 tcx.dcx().span_err(1588 tcx.def_span(field.did),1589 "all fields in a scalable vector struct must be the same type",1590 );1591 break;1592 }1593 }1594 }1595 }1596}15971598pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {1599 let repr = def.repr();1600 if repr.packed() {1601 if let Some(reprs) = find_attr!(tcx, def.did(), Repr { reprs, .. } => reprs) {1602 for (r, _) in reprs {1603 if let ReprPacked(pack) = r1604 && let Some(repr_pack) = repr.pack1605 && pack != &repr_pack1606 {1607 struct_span_code_err!(1608 tcx.dcx(),1609 sp,1610 E0634,1611 "type has conflicting packed representation hints"1612 )1613 .emit();1614 }1615 }1616 }1617 if repr.align.is_some() {1618 struct_span_code_err!(1619 tcx.dcx(),1620 sp,1621 E0587,1622 "type has conflicting packed and align representation hints"1623 )1624 .emit();1625 } else if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) {1626 let mut err = struct_span_code_err!(1627 tcx.dcx(),1628 sp,1629 E0588,1630 "packed type cannot transitively contain a `#[repr(align)]` type"1631 );16321633 err.span_note(1634 tcx.def_span(def_spans[0].0),1635 format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)),1636 );16371638 if def_spans.len() > 2 {1639 let mut first = true;1640 for (adt_def, span) in def_spans.iter().skip(1).rev() {1641 let ident = tcx.item_name(*adt_def);1642 err.span_note(1643 *span,1644 if first {1645 format!(1646 "`{}` contains a field of type `{}`",1647 tcx.type_of(def.did()).instantiate_identity().skip_norm_wip(),1648 ident1649 )1650 } else {1651 format!("...which contains a field of type `{ident}`")1652 },1653 );1654 first = false;1655 }1656 }16571658 err.emit();1659 }1660 }1661}16621663pub(super) fn check_packed_inner(1664 tcx: TyCtxt<'_>,1665 def_id: DefId,1666 stack: &mut Vec<DefId>,1667) -> Option<Vec<(DefId, Span)>> {1668 if let ty::Adt(def, args) = tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind() {1669 if def.is_struct() || def.is_union() {1670 if def.repr().align.is_some() {1671 return Some(vec![(def.did(), DUMMY_SP)]);1672 }16731674 stack.push(def_id);1675 for field in &def.non_enum_variant().fields {1676 if let ty::Adt(def, _) = field.ty(tcx, args).kind()1677 && !stack.contains(&def.did())1678 && let Some(mut defs) = check_packed_inner(tcx, def.did(), stack)1679 {1680 defs.push((def.did(), field.ident(tcx).span));1681 return Some(defs);1682 }1683 }1684 stack.pop();1685 }1686 }16871688 None1689}16901691pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {1692 struct ZeroSizedFieldReprTransparentIncompatibility<'tcx> {1693 unsuited: UnsuitedInfo<'tcx>,1694 }16951696 impl<'a, 'tcx> Diagnostic<'a, ()> for ZeroSizedFieldReprTransparentIncompatibility<'tcx> {1697 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {1698 let Self { unsuited } = self;1699 let (title, note) = match unsuited.reason {1700 UnsuitedReason::NonExhaustive => (1701 "external non-exhaustive types",1702 "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.",1703 ),1704 UnsuitedReason::PrivateField => (1705 "external types with private fields",1706 "contains private fields, so it could become non-zero-sized in the future.",1707 ),1708 UnsuitedReason::ReprC => (1709 "`repr(C)` types",1710 "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.",1711 ),1712 };1713 Diag::new(1714 dcx,1715 level,1716 format!("zero-sized fields in `repr(transparent)` cannot contain {title}"),1717 )1718 .with_note(format!(1719 "this field contains `{field_ty}`, which {note}",1720 field_ty = unsuited.ty,1721 ))1722 }1723 }17241725 if !adt.repr().transparent() {1726 return;1727 }17281729 if adt.is_union() && !tcx.features().transparent_unions() {1730 feature_err(1731 &tcx.sess,1732 sym::transparent_unions,1733 tcx.def_span(adt.did()),1734 "transparent unions are unstable",1735 )1736 .emit();1737 }17381739 if adt.variants().len() != 1 {1740 bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());1741 // Don't bother checking the fields.1742 return;1743 }17441745 let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did());1746 // For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST).1747 struct FieldInfo<'tcx> {1748 span: Span,1749 trivial: bool,1750 ty: Ty<'tcx>,1751 }17521753 let field_infos = adt.all_fields().map(|field| {1754 let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));1755 let layout = tcx.layout_of(typing_env.as_query_input(ty));1756 // We are currently checking the type this field came from, so it must be local1757 let span = tcx.hir_span_if_local(field.did).unwrap();1758 let trivial = layout.is_ok_and(|layout| layout.is_1zst());1759 FieldInfo { span, trivial, ty }1760 });17611762 let non_trivial_fields = field_infos1763 .clone()1764 .filter_map(|field| if !field.trivial { Some(field.span) } else { None });1765 let non_trivial_count = non_trivial_fields.clone().count();1766 if non_trivial_count >= 2 {1767 bad_non_zero_sized_fields(1768 tcx,1769 adt,1770 non_trivial_count,1771 non_trivial_fields,1772 tcx.def_span(adt.did()),1773 );1774 return;1775 }17761777 // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private1778 // fields or `repr(C)`. We call those fields "unsuited".1779 struct UnsuitedInfo<'tcx> {1780 /// The source of the problem, a type that is found somewhere within the field type.1781 ty: Ty<'tcx>,1782 reason: UnsuitedReason,1783 }1784 enum UnsuitedReason {1785 NonExhaustive,1786 PrivateField,1787 ReprC,1788 }17891790 fn check_unsuited<'tcx>(1791 tcx: TyCtxt<'tcx>,1792 typing_env: ty::TypingEnv<'tcx>,1793 ty: Ty<'tcx>,1794 ) -> ControlFlow<UnsuitedInfo<'tcx>> {1795 // We can encounter projections during traversal, so ensure the type is normalized.1796 let ty =1797 tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)).unwrap_or(ty);1798 match ty.kind() {1799 ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),1800 ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),1801 ty::Adt(def, args) => {1802 if !def.did().is_local() && !find_attr!(tcx, def.did(), RustcPubTransparent(_)) {1803 let non_exhaustive = def.is_variant_list_non_exhaustive()1804 || def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);1805 let has_priv = def.all_fields().any(|f| !f.vis.is_public());1806 if non_exhaustive || has_priv {1807 return ControlFlow::Break(UnsuitedInfo {1808 ty,1809 reason: if non_exhaustive {1810 UnsuitedReason::NonExhaustive1811 } else {1812 UnsuitedReason::PrivateField1813 },1814 });1815 }1816 }1817 if def.repr().c() {1818 return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });1819 }1820 def.all_fields()1821 .map(|field| field.ty(tcx, args))1822 .try_for_each(|t| check_unsuited(tcx, typing_env, t))1823 }1824 _ => ControlFlow::Continue(()),1825 }1826 }18271828 let mut prev_unsuited_1zst = false;1829 for field in field_infos {1830 if field.trivial1831 && let Some(unsuited) = check_unsuited(tcx, typing_env, field.ty).break_value()1832 {1833 // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.1834 // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.1835 if non_trivial_count > 0 || prev_unsuited_1zst {1836 tcx.emit_node_span_lint(1837 REPR_TRANSPARENT_NON_ZST_FIELDS,1838 tcx.local_def_id_to_hir_id(adt.did().expect_local()),1839 field.span,1840 ZeroSizedFieldReprTransparentIncompatibility { unsuited },1841 );1842 } else {1843 prev_unsuited_1zst = true;1844 }1845 }1846 }1847}18481849#[allow(trivial_numeric_casts)]1850fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {1851 let def = tcx.adt_def(def_id);1852 def.destructor(tcx); // force the destructor to be evaluated18531854 if def.variants().is_empty() {1855 find_attr!(tcx, def_id, Repr { reprs, first_span } => {1856 struct_span_code_err!(1857 tcx.dcx(),1858 reprs.first().map(|repr| repr.1).unwrap_or(*first_span),1859 E0084,1860 "unsupported representation for zero-variant enum"1861 )1862 .with_span_label(tcx.def_span(def_id), "zero-variant enum")1863 .emit();1864 });1865 }18661867 for v in def.variants() {1868 if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {1869 tcx.ensure_ok().typeck(discr_def_id.expect_local());1870 }1871 }18721873 if def.repr().int.is_none() {1874 let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));1875 let get_disr = |var: &ty::VariantDef| match var.discr {1876 ty::VariantDiscr::Explicit(disr) => Some(disr),1877 ty::VariantDiscr::Relative(_) => None,1878 };18791880 let non_unit = def.variants().iter().find(|var| !is_unit(var));1881 let disr_unit =1882 def.variants().iter().filter(|var| is_unit(var)).find_map(|var| get_disr(var));1883 let disr_non_unit =1884 def.variants().iter().filter(|var| !is_unit(var)).find_map(|var| get_disr(var));18851886 if disr_non_unit.is_some() || (disr_unit.is_some() && non_unit.is_some()) {1887 let mut err = struct_span_code_err!(1888 tcx.dcx(),1889 tcx.def_span(def_id),1890 E0732,1891 "`#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants"1892 );1893 if let Some(disr_non_unit) = disr_non_unit {1894 err.span_label(1895 tcx.def_span(disr_non_unit),1896 "explicit discriminant on non-unit variant specified here",1897 );1898 } else {1899 err.span_label(1900 tcx.def_span(disr_unit.unwrap()),1901 "explicit discriminant specified here",1902 );1903 err.span_label(1904 tcx.def_span(non_unit.unwrap().def_id),1905 "non-unit discriminant declared here",1906 );1907 }1908 err.emit();1909 }1910 }19111912 detect_discriminant_duplicate(tcx, def);1913 check_transparent(tcx, def);1914}19151916/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal1917fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {1918 // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.1919 // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`1920 let report = |dis: Discr<'tcx>, idx, err: &mut Diag<'_>| {1921 let var = adt.variant(idx); // HIR for the duplicate discriminant1922 let (span, display_discr) = match var.discr {1923 ty::VariantDiscr::Explicit(discr_def_id) => {1924 // In the case the discriminant is both a duplicate and overflowed, let the user know1925 if let hir::Node::AnonConst(expr) =1926 tcx.hir_node_by_def_id(discr_def_id.expect_local())1927 && let hir::ExprKind::Lit(lit) = &tcx.hir_body(expr.body).value.kind1928 && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node1929 && *lit_value != dis.val1930 {1931 (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))1932 } else {1933 // Otherwise, format the value as-is1934 (tcx.def_span(discr_def_id), format!("`{dis}`"))1935 }1936 }1937 // This should not happen.1938 ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),1939 ty::VariantDiscr::Relative(distance_to_explicit) => {1940 // At this point we know this discriminant is a duplicate, and was not explicitly1941 // assigned by the user. Here we iterate backwards to fetch the HIR for the last1942 // explicitly assigned discriminant, and letting the user know that this was the1943 // increment startpoint, and how many steps from there leading to the duplicate1944 if let Some(explicit_idx) =1945 idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)1946 {1947 let explicit_variant = adt.variant(explicit_idx);1948 let ve_ident = var.name;1949 let ex_ident = explicit_variant.name;1950 let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };19511952 err.span_label(1953 tcx.def_span(explicit_variant.def_id),1954 format!(1955 "discriminant for `{ve_ident}` incremented from this startpoint \1956 (`{ex_ident}` + {distance_to_explicit} {sp} later \1957 => `{ve_ident}` = {dis})"1958 ),1959 );1960 }19611962 (tcx.def_span(var.def_id), format!("`{dis}`"))1963 }1964 };19651966 err.span_label(span, format!("{display_discr} assigned here"));1967 };19681969 let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();19701971 // Here we loop through the discriminants, comparing each discriminant to another.1972 // When a duplicate is detected, we instantiate an error and point to both1973 // initial and duplicate value. The duplicate discriminant is then discarded by swapping1974 // it with the last element and decrementing the `vec.len` (which is why we have to evaluate1975 // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional1976 // style as we are mutating `discrs` on the fly).1977 let mut i = 0;1978 while i < discrs.len() {1979 let var_i_idx = discrs[i].0;1980 let mut error: Option<Diag<'_, _>> = None;19811982 let mut o = i + 1;1983 while o < discrs.len() {1984 let var_o_idx = discrs[o].0;19851986 if discrs[i].1.val == discrs[o].1.val {1987 let err = error.get_or_insert_with(|| {1988 let mut ret = struct_span_code_err!(1989 tcx.dcx(),1990 tcx.def_span(adt.did()),1991 E0081,1992 "discriminant value `{}` assigned more than once",1993 discrs[i].1,1994 );19951996 report(discrs[i].1, var_i_idx, &mut ret);19971998 ret1999 });