diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
26 files changed, 976 insertions, 484 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 476814c261e..c66572a9377 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -5,13 +5,14 @@ use rustc_abi::FieldIdx; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; -use rustc_hir::Node; use rustc_hir::def::{CtorKind, DefKind}; +use rustc_hir::{Node, Safety, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, }; +use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; @@ -20,8 +21,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; use rustc_middle::ty::{ - AdtDef, GenericArgKind, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, + AdtDef, GenericArgKind, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -37,7 +37,7 @@ use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_i use super::*; use crate::check::intrinsicck::InlineAsmCtxt; -pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { +pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) { if !tcx.sess.target.is_abi_supported(abi) { struct_span_code_err!( tcx.dcx(), @@ -49,7 +49,7 @@ pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { } } -pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { +pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { if !tcx.sess.target.is_abi_supported(abi) { tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| { lint.primary_message(format!( @@ -70,6 +70,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_transparent(tcx, def); check_packed(tcx, span, def); + check_unsafe_fields(tcx, def_id); } fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { @@ -81,47 +82,54 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_packed(tcx, span, def); } +fn allowed_union_or_unsafe_field<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + span: Span, +) -> bool { + // We don't just accept all !needs_drop fields, due to semver concerns. + let allowed = match ty.kind() { + ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) + ty::Tuple(tys) => { + // allow tuples of allowed types + tys.iter().all(|ty| allowed_union_or_unsafe_field(tcx, ty, typing_env, span)) + } + ty::Array(elem, _len) => { + // Like `Copy`, we do *not* special-case length 0. + allowed_union_or_unsafe_field(tcx, *elem, typing_env, span) + } + _ => { + // Fallback case: allow `ManuallyDrop` and things that are `Copy`, + // also no need to report an error if the type is unresolved. + ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) + || ty.is_copy_modulo_regions(tcx, typing_env) + || ty.references_error() + } + }; + if allowed && ty.needs_drop(tcx, typing_env) { + // This should never happen. But we can get here e.g. in case of name resolution errors. + tcx.dcx() + .span_delayed_bug(span, "we should never accept maybe-dropping union or unsafe fields"); + } + allowed +} + /// Check that the fields of the `union` do not need dropping. fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { let item_type = tcx.type_of(item_def_id).instantiate_identity(); if let ty::Adt(def, args) = item_type.kind() { assert!(def.is_union()); - fn allowed_union_field<'tcx>( - ty: Ty<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - // We don't just accept all !needs_drop fields, due to semver concerns. - match ty.kind() { - ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) - ty::Tuple(tys) => { - // allow tuples of allowed types - tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env)) - } - ty::Array(elem, _len) => { - // Like `Copy`, we do *not* special-case length 0. - allowed_union_field(*elem, tcx, param_env) - } - _ => { - // Fallback case: allow `ManuallyDrop` and things that are `Copy`, - // also no need to report an error if the type is unresolved. - ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) - || ty.is_copy_modulo_regions(tcx, param_env) - || ty.references_error() - } - } - } - - let param_env = tcx.param_env(item_def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); for field in &def.non_enum_variant().fields { - let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args)) + let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) else { tcx.dcx().span_delayed_bug(span, "could not normalize field type"); continue; }; - if !allowed_union_field(field_ty, tcx, param_env) { + if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { // We are currently checking the type this field came from, so it must be local. Some(Node::Field(field)) => (field.span, field.ty.span), @@ -136,10 +144,6 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b note: (), }); return false; - } else if field_ty.needs_drop(tcx, param_env) { - // This should never happen. But we can get here e.g. in case of name resolution errors. - tcx.dcx() - .span_delayed_bug(span, "we should never accept maybe-dropping union fields"); } } } else { @@ -148,6 +152,41 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b true } +/// Check that the unsafe fields do not need dropping. +fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) { + let span = tcx.def_span(item_def_id); + let item_type = tcx.type_of(item_def_id).instantiate_identity(); + let ty::Adt(def, args) = item_type.kind() else { + span_bug!(span, "structs/enums must be ty::Adt, but got {:?}", item_type.kind()); + }; + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); + for field in def.all_fields() { + if field.safety != Safety::Unsafe { + continue; + } + let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) + else { + tcx.dcx().span_delayed_bug(span, "could not normalize field type"); + continue; + }; + + if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) { + let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.expect_local()) else { + unreachable!("field has to correspond to hir field") + }; + let ty_span = field.ty.span; + tcx.dcx().emit_err(errors::InvalidUnsafeField { + field_span: field.span, + sugg: errors::InvalidUnsafeFieldSuggestion { + lo: ty_span.shrink_to_lo(), + hi: ty_span.shrink_to_hi(), + }, + note: (), + }); + } + } +} + /// Check that a `static` is inhabited. fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { // Make sure statics are inhabited. @@ -157,7 +196,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { // reason to allow any statics to be uninhabited. let ty = tcx.type_of(def_id).instantiate_identity(); let span = tcx.def_span(def_id); - let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) { + let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) { Ok(l) => l, // Foreign statics that overflow their allowed size should emit an error Err(LayoutError::SizeOverflow(_)) @@ -190,7 +229,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` /// projections that would result in "inheriting lifetimes". fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id); + let hir::OpaqueTy { origin, .. } = *tcx.hir().expect_opaque_ty(def_id); // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting // `async-std` (and `pub async fn` in general). @@ -200,23 +239,20 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - let span = tcx.def_span(def_id); - if tcx.type_of(def_id).instantiate_identity().references_error() { return; } - if check_opaque_for_cycles(tcx, def_id, span).is_err() { + if check_opaque_for_cycles(tcx, def_id).is_err() { return; } - let _ = check_opaque_meets_bounds(tcx, def_id, span, origin); + let _ = check_opaque_meets_bounds(tcx, def_id, origin); } /// Checks that an opaque type does not contain cycles. pub(super) fn check_opaque_for_cycles<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, - span: Span, ) -> Result<(), ErrorGuaranteed> { let args = GenericArgs::identity_for_item(tcx, def_id); @@ -233,13 +269,16 @@ pub(super) fn check_opaque_for_cycles<'tcx>( .try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No) .is_err() { - let reported = opaque_type_cycle_error(tcx, def_id, span); + let reported = opaque_type_cycle_error(tcx, def_id); return Err(reported); } // And also look for cycle errors in the layout of coroutines. if let Err(&LayoutError::Cycle(guar)) = - tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args))) + tcx.layout_of( + ty::TypingEnv::post_analysis(tcx, def_id.to_def_id()) + .as_query_input(Ty::new_opaque(tcx, def_id.to_def_id(), args)), + ) { return Err(guar); } @@ -267,10 +306,16 @@ pub(super) fn check_opaque_for_cycles<'tcx>( fn check_opaque_meets_bounds<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, - span: Span, - origin: &hir::OpaqueTyOrigin<LocalDefId>, + origin: hir::OpaqueTyOrigin<LocalDefId>, ) -> Result<(), ErrorGuaranteed> { - let defining_use_anchor = match *origin { + let (span, definition_def_id) = + if let Some((span, def_id)) = best_definition_site_of_opaque(tcx, def_id, origin) { + (span, Some(def_id)) + } else { + (tcx.def_span(def_id), None) + }; + + let defining_use_anchor = match origin { hir::OpaqueTyOrigin::FnReturn { parent, .. } | hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, @@ -281,7 +326,7 @@ fn check_opaque_meets_bounds<'tcx>( let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - let args = match *origin { + let args = match origin { hir::OpaqueTyOrigin::FnReturn { parent, .. } | hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item( @@ -306,8 +351,35 @@ fn check_opaque_meets_bounds<'tcx>( _ => re, }); - let misc_cause = traits::ObligationCause::misc(span, def_id); + // HACK: We eagerly instantiate some bounds to report better errors for them... + // This isn't necessary for correctness, since we register these bounds when + // equating the opaque below, but we should clean this up in the new solver. + for (predicate, pred_span) in + tcx.explicit_item_bounds(def_id).iter_instantiated_copied(tcx, args) + { + let predicate = predicate.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }); + ocx.register_obligation(Obligation::new( + tcx, + ObligationCause::new( + span, + def_id, + ObligationCauseCode::OpaqueTypeBound(pred_span, definition_def_id), + ), + param_env, + predicate, + )); + } + + let misc_cause = ObligationCause::misc(span, def_id); + // FIXME: We should just register the item bounds here, rather than equating. + // FIXME(const_trait_impl): When we do that, please make sure to also register + // the `~const` bounds. match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { Ok(()) => {} Err(ty_err) => { @@ -364,6 +436,97 @@ fn check_opaque_meets_bounds<'tcx>( } } +fn best_definition_site_of_opaque<'tcx>( + tcx: TyCtxt<'tcx>, + opaque_def_id: LocalDefId, + origin: hir::OpaqueTyOrigin<LocalDefId>, +) -> Option<(Span, LocalDefId)> { + struct TaitConstraintLocator<'tcx> { + opaque_def_id: LocalDefId, + tcx: TyCtxt<'tcx>, + } + impl<'tcx> TaitConstraintLocator<'tcx> { + fn check(&self, item_def_id: LocalDefId) -> ControlFlow<(Span, LocalDefId)> { + if !self.tcx.has_typeck_results(item_def_id) { + return ControlFlow::Continue(()); + } + + if let Some(hidden_ty) = + self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id) + { + ControlFlow::Break((hidden_ty.span, item_def_id)) + } else { + ControlFlow::Continue(()) + } + } + } + impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { + type NestedFilter = nested_filter::All; + type Result = ControlFlow<(Span, LocalDefId)>; + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result { + if let hir::ExprKind::Closure(closure) = ex.kind { + self.check(closure.def_id)?; + } + intravisit::walk_expr(self, ex) + } + fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result { + self.check(it.owner_id.def_id)?; + intravisit::walk_item(self, it) + } + fn visit_impl_item(&mut self, it: &'tcx hir::ImplItem<'tcx>) -> Self::Result { + self.check(it.owner_id.def_id)?; + intravisit::walk_impl_item(self, it) + } + fn visit_trait_item(&mut self, it: &'tcx hir::TraitItem<'tcx>) -> Self::Result { + self.check(it.owner_id.def_id)?; + intravisit::walk_trait_item(self, it) + } + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Result { + intravisit::walk_foreign_item(self, it) + } + } + + let mut locator = TaitConstraintLocator { tcx, opaque_def_id }; + match origin { + hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } => locator.check(parent).break_value(), + hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty: true } => { + let impl_def_id = tcx.local_parent(parent); + for assoc in tcx.associated_items(impl_def_id).in_definition_order() { + match assoc.kind { + ty::AssocKind::Const | ty::AssocKind::Fn => { + if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local()) + { + return Some(span); + } + } + ty::AssocKind::Type => {} + } + } + + None + } + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => { + let scope = tcx.hir().get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id)); + let found = if scope == hir::CRATE_HIR_ID { + tcx.hir().walk_toplevel_module(&mut locator) + } else { + match tcx.hir_node(scope) { + Node::Item(it) => locator.visit_item(it), + Node::ImplItem(it) => locator.visit_impl_item(it), + Node::TraitItem(it) => locator.visit_trait_item(it), + Node::ForeignItem(it) => locator.visit_foreign_item(it), + other => bug!("{:?} is not a valid scope for an opaque type item", other), + } + }; + found.break_value() + } + } +} + fn sanity_check_found_hidden_type<'tcx>( tcx: TyCtxt<'tcx>, key: ty::OpaqueTypeKey<'tcx>, @@ -628,7 +791,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { def_id, tcx.def_ident_span(def_id).unwrap(), i.name, - Abi::Rust, + ExternAbi::Rust, ) } // Everything else is checked entirely within check_item_body @@ -699,7 +862,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_abi(tcx, it.span, abi); match abi { - Abi::RustIntrinsic => { + ExternAbi::RustIntrinsic => { for item in items { intrinsic::check_intrinsic_type( tcx, @@ -1187,8 +1350,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) // "known" respecting #[non_exhaustive] attributes. let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did)); - let param_env = tcx.param_env(field.did); - let layout = tcx.layout_of(param_env.and(ty)); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did); + let layout = tcx.layout_of(typing_env.as_query_input(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir().span_if_local(field.did).unwrap(); let trivial = layout.is_ok_and(|layout| layout.is_1zst()); @@ -1340,6 +1503,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { detect_discriminant_duplicate(tcx, def); check_transparent(tcx, def); + check_unsafe_fields(tcx, def_id); } /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal @@ -1535,11 +1699,8 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD /// /// If all the return expressions evaluate to `!`, then we explain that the error will go away /// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. -fn opaque_type_cycle_error( - tcx: TyCtxt<'_>, - opaque_def_id: LocalDefId, - span: Span, -) -> ErrorGuaranteed { +fn opaque_type_cycle_error(tcx: TyCtxt<'_>, opaque_def_id: LocalDefId) -> ErrorGuaranteed { + let span = tcx.def_span(opaque_def_id); let mut err = struct_span_code_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type"); let mut label = false; diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 0b7d3f8b085..f86ca95a954 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -26,7 +26,7 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, }; use tracing::{debug, instrument}; @@ -205,7 +205,6 @@ fn compare_method_predicate_entailment<'tcx>( trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate), ); - // FIXME(effects): This should be replaced with a more dedicated method. let is_conditionally_const = tcx.is_conditionally_const(impl_def_id); if is_conditionally_const { // Augment the hybrid param-env with the const conditions @@ -224,7 +223,7 @@ fn compare_method_predicate_entailment<'tcx>( } let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds)); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); @@ -509,7 +508,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( .into_iter() .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args)) .map(|(clause, _)| clause); - let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds)); let param_env = traits::normalize_param_env_or_error( tcx, param_env, @@ -1190,13 +1189,13 @@ fn compare_self_type<'tcx>( let self_string = |method: ty::AssocItem| { let untransformed_self_ty = match method.container { - ty::ImplContainer => impl_trait_ref.self_ty(), - ty::TraitContainer => tcx.types.self_param, + ty::AssocItemContainer::Impl => impl_trait_ref.self_ty(), + ty::AssocItemContainer::Trait => tcx.types.self_param, }; let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0); - let param_env = ty::ParamEnv::reveal_all(); - - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let (infcx, param_env) = tcx + .infer_ctxt() + .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, method.def_id)); let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { @@ -1794,7 +1793,7 @@ fn compare_const_predicate_entailment<'tcx>( .map(|(predicate, _)| predicate), ); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds)); let param_env = traits::normalize_param_env_or_error( tcx, param_env, @@ -1947,7 +1946,7 @@ fn compare_type_predicate_entailment<'tcx>( ); } - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds)); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); @@ -2084,7 +2083,7 @@ pub(super) fn check_type_bounds<'tcx>( // Only in a const implementation do we need to check that the `~const` item bounds hold. if tcx.is_conditionally_const(impl_ty_def_id) { obligations.extend( - tcx.implied_const_bounds(trait_ty.def_id) + tcx.explicit_implied_const_bounds(trait_ty.def_id) .iter_instantiated_copied(tcx, rebased_args) .map(|(c, span)| { traits::Obligation::new( @@ -2225,10 +2224,8 @@ fn param_env_with_gat_bounds<'tcx>( for impl_ty in impl_tys_to_install { let trait_ty = match impl_ty.container { - ty::AssocItemContainer::TraitContainer => impl_ty, - ty::AssocItemContainer::ImplContainer => { - tcx.associated_item(impl_ty.trait_item_def_id.unwrap()) - } + ty::AssocItemContainer::Trait => impl_ty, + ty::AssocItemContainer::Impl => tcx.associated_item(impl_ty.trait_item_def_id.unwrap()), }; let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = @@ -2247,7 +2244,7 @@ fn param_env_with_gat_bounds<'tcx>( .into() } GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let kind = ty::BoundRegionKind::Named(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { @@ -2309,7 +2306,7 @@ fn param_env_with_gat_bounds<'tcx>( }; } - ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) + ty::ParamEnv::new(tcx.mk_clauses(&predicates)) } /// Manually check here that `async fn foo()` wasn't matched against `fn foo()`, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 646c104f1f5..67cbcc1566a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -1,11 +1,12 @@ +use itertools::Itertools as _; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE}; use rustc_middle::span_bug; -use rustc_middle::traits::{ObligationCause, Reveal}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, @@ -75,6 +76,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let mut trait_bounds = vec![]; // Bounds that we find on the RPITITs in the impl signature. let mut impl_bounds = vec![]; + // Pairs of trait and impl opaques. + let mut pairs = vec![]; for trait_projection in collector.types.into_iter().rev() { let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args); @@ -121,6 +124,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( tcx.explicit_item_bounds(impl_opaque.def_id) .iter_instantiated_copied(tcx, impl_opaque.args), )); + + pairs.push((trait_projection, impl_opaque)); } let hybrid_preds = tcx @@ -129,7 +134,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( .into_iter() .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args)) .map(|(clause, _)| clause); - let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds)); let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); let ref infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); @@ -212,6 +217,39 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; } } + + // Make sure that the RPITIT doesn't capture fewer regions than + // the trait definition. We hard-error if it captures *more*, since that + // is literally unrepresentable in the type system; however, we may be + // promising stronger outlives guarantees if we capture *fewer* regions. + for (trait_projection, impl_opaque) in pairs { + let impl_variances = tcx.variances_of(impl_opaque.def_id); + let impl_captures: FxIndexSet<_> = impl_opaque + .args + .iter() + .zip_eq(impl_variances) + .filter(|(_, v)| **v == ty::Invariant) + .map(|(arg, _)| arg) + .collect(); + + let trait_variances = tcx.variances_of(trait_projection.def_id); + let mut trait_captures = FxIndexSet::default(); + for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) { + if *variance != ty::Invariant { + continue; + } + arg.visit_with(&mut CollectParams { params: &mut trait_captures }); + } + + if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) { + report_mismatched_rpitit_captures( + tcx, + impl_opaque.def_id.expect_local(), + trait_captures, + is_internal, + ); + } + } } struct ImplTraitInTraitCollector<'tcx> { @@ -342,3 +380,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> { self.tcx.anonymize_bound_vars(t) } } + +struct CollectParams<'a, 'tcx> { + params: &'a mut FxIndexSet<ty::GenericArg<'tcx>>, +} +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectParams<'_, 'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) { + if let ty::Param(_) = ty.kind() { + self.params.insert(ty.into()); + } else { + ty.super_visit_with(self); + } + } + fn visit_region(&mut self, r: ty::Region<'tcx>) { + match r.kind() { + ty::ReEarlyParam(_) | ty::ReLateParam(_) => { + self.params.insert(r.into()); + } + _ => {} + } + } + fn visit_const(&mut self, ct: ty::Const<'tcx>) { + if let ty::ConstKind::Param(_) = ct.kind() { + self.params.insert(ct.into()); + } else { + ct.super_visit_with(self); + } + } +} + +fn report_mismatched_rpitit_captures<'tcx>( + tcx: TyCtxt<'tcx>, + impl_opaque_def_id: LocalDefId, + mut trait_captured_args: FxIndexSet<ty::GenericArg<'tcx>>, + is_internal: bool, +) { + let Some(use_bound_span) = + tcx.hir_node_by_def_id(impl_opaque_def_id).expect_opaque_ty().bounds.iter().find_map( + |bound| match *bound { + rustc_hir::GenericBound::Use(_, span) => Some(span), + hir::GenericBound::Trait(_) | hir::GenericBound::Outlives(_) => None, + }, + ) + else { + // I have no idea when you would ever undercapture without a `use<..>`. + tcx.dcx().delayed_bug("expected use<..> to undercapture in an impl opaque"); + return; + }; + + trait_captured_args + .sort_by_cached_key(|arg| !matches!(arg.unpack(), ty::GenericArgKind::Lifetime(_))); + let suggestion = format!("use<{}>", trait_captured_args.iter().join(", ")); + + tcx.emit_node_span_lint( + if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE }, + tcx.local_def_id_to_hir_id(impl_opaque_def_id), + use_bound_span, + crate::errors::ReturnPositionImplTraitInTraitRefinedLifetimes { + suggestion_span: use_bound_span, + suggestion, + }, + ); +} diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 0beb1f98d56..f3dd13c84b9 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -1,5 +1,6 @@ use std::ops::Not; +use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; @@ -9,7 +10,6 @@ use rustc_session::config::EntryFnType; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_span::symbol::sym; -use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -158,7 +158,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { expected_return_type, false, hir::Safety::Safe, - Abi::Rust, + ExternAbi::Rust, )); if check_function_signature( @@ -254,7 +254,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { tcx.types.isize, false, hir::Safety::Safe, - Abi::Rust, + ExternAbi::Rust, )); let _ = check_function_signature( diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs deleted file mode 100644 index 64307407b73..00000000000 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ /dev/null @@ -1,88 +0,0 @@ -use rustc_hir as hir; -use rustc_lint_defs::builtin::STATIC_MUT_REFS; -use rustc_middle::ty::{Mutability, TyCtxt}; -use rustc_span::Span; - -use crate::errors; - -/// Check for shared or mutable references of `static mut` inside expression -pub(crate) fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { - let span = expr.span; - let hir_id = expr.hir_id; - if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind - && matches!(borrow_kind, hir::BorrowKind::Ref) - && path_if_static_mut(expr) - { - handle_static_mut_ref( - tcx, - span, - span.with_hi(expr.span.lo()), - span.shrink_to_hi(), - span.edition().at_least_rust_2024(), - m, - hir_id, - ); - } -} - -/// Check for shared or mutable references of `static mut` inside statement -pub(crate) fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { - if let hir::StmtKind::Let(loc) = stmt.kind - && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind - && let hir::ByRef::Yes(rmutbl) = ba.0 - && let Some(init) = loc.init - && path_if_static_mut(init) - { - handle_static_mut_ref( - tcx, - init.span, - init.span.shrink_to_lo(), - init.span.shrink_to_hi(), - loc.span.edition().at_least_rust_2024(), - rmutbl, - stmt.hir_id, - ); - } -} - -fn path_if_static_mut(expr: &hir::Expr<'_>) -> bool { - if let hir::ExprKind::Path(qpath) = expr.kind - && let hir::QPath::Resolved(_, path) = qpath - && let hir::def::Res::Def(def_kind, _) = path.res - && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = - def_kind - { - return true; - } - false -} - -fn handle_static_mut_ref( - tcx: TyCtxt<'_>, - span: Span, - lo: Span, - hi: Span, - e2024: bool, - mutable: Mutability, - hir_id: hir::HirId, -) { - if e2024 { - let (sugg, shared) = if mutable == Mutability::Mut { - (errors::MutRefSugg::Mut { lo, hi }, "mutable") - } else { - (errors::MutRefSugg::Shared { lo, hi }, "shared") - }; - tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared }); - } else { - let (sugg, shared) = if mutable == Mutability::Mut { - (errors::MutRefSugg::Mut { lo, hi }, "mutable") - } else { - (errors::MutRefSugg::Shared { lo, hi }, "shared") - }; - tcx.emit_node_span_lint(STATIC_MUT_REFS, hir_id, span, errors::RefOfMutStatic { - span, - sugg, - shared, - }); - } -} diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index c75bdcec388..3e33120901f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -1,16 +1,15 @@ -//! Type-checking for the rust-intrinsic and platform-intrinsic -//! intrinsics that the compiler exposes. +//! Type-checking for the rust-intrinsic intrinsics that the compiler exposes. +use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, struct_span_code_err}; -use rustc_hir as hir; +use rustc_hir::{self as hir, Safety}; use rustc_middle::bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; -use rustc_target::spec::abi::Abi; use crate::check::check_function_signature; use crate::errors::{ @@ -76,10 +75,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - let has_safe_attr = if tcx.has_attr(intrinsic_id, sym::rustc_intrinsic) { tcx.fn_sig(intrinsic_id).skip_binder().safety() } else { - match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) { - true => hir::Safety::Safe, - false => hir::Safety::Unsafe, - } + // Old-style intrinsics are never safe + Safety::Unsafe }; let is_in_list = match tcx.item_name(intrinsic_id.into()) { // When adding a new intrinsic to this list, @@ -112,9 +109,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::three_way_compare | sym::discriminant_value | sym::type_id - | sym::likely - | sym::unlikely | sym::select_unpredictable + | sym::cold_path | sym::ptr_guaranteed_cmp | sym::minnumf16 | sym::minnumf32 @@ -163,7 +159,7 @@ pub fn check_intrinsic_type( intrinsic_id: LocalDefId, span: Span, intrinsic_name: Symbol, - abi: Abi, + abi: ExternAbi, ) { let generics = tcx.generics_of(intrinsic_id); let param = |n| { @@ -178,19 +174,19 @@ pub fn check_intrinsic_type( let name_str = intrinsic_name.as_str(); let bound_vars = tcx.mk_bound_variable_kinds(&[ - ty::BoundVariableKind::Region(ty::BrAnon), - ty::BoundVariableKind::Region(ty::BrAnon), - ty::BoundVariableKind::Region(ty::BrEnv), + ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), + ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), + ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv), ]); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { let region = ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::ZERO, - kind: ty::BrAnon, + kind: ty::BoundRegionKind::Anon, }); let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(2), - kind: ty::BrEnv, + kind: ty::BoundRegionKind::ClosureEnv, }); let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]); (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) @@ -492,9 +488,8 @@ pub fn check_intrinsic_type( sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit), - sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), - sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)), + sym::cold_path => (0, 0, vec![], tcx.types.unit), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { @@ -509,7 +504,8 @@ pub fn check_intrinsic_type( ); let discriminant_def_id = assoc_items[0]; - let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }; + let br = + ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }; ( 1, 0, @@ -533,14 +529,14 @@ pub fn check_intrinsic_type( tcx.types.unit, false, hir::Safety::Safe, - Abi::Rust, + ExternAbi::Rust, )); let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8, mut_u8], tcx.types.unit, false, hir::Safety::Safe, - Abi::Rust, + ExternAbi::Rust, )); ( 0, @@ -573,10 +569,14 @@ pub fn check_intrinsic_type( } sym::raw_eq => { - let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }; + let br = + ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }; let param_ty_lhs = Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); - let br = ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon }; + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(1), + kind: ty::BoundRegionKind::Anon, + }; let param_ty_rhs = Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); (1, 0, vec![param_ty_lhs, param_ty_rhs], tcx.types.bool) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index e95669c9d40..dfddf93a5c2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -15,7 +15,7 @@ use rustc_target::asm::{ pub struct InlineAsmCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>, } @@ -23,24 +23,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { InlineAsmCtxt { tcx, - param_env: ty::ParamEnv::empty(), + typing_env: ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: ty::ParamEnv::empty(), + }, get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")), } } + // FIXME(#132279): This likely causes us to incorrectly handle opaque types in their + // defining scope. pub fn new_in_fn( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a, ) -> Self { - InlineAsmCtxt { tcx, param_env, get_operand_ty: Box::new(get_operand_ty) } + InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) } } // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { // Type still may have region variables, but `Sized` does not depend // on those, so just erase them before querying. - if ty.is_sized(self.tcx, self.param_env) { + if ty.is_sized(self.tcx, self.typing_env) { return true; } if let ty::Foreign(..) = ty.kind() { @@ -171,7 +176,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { + if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) { let msg = "arguments for inline assembly must be copyable"; self.tcx .dcx() diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index e9eea36a0e6..375cbfd1c4f 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -74,7 +74,7 @@ pub mod wfcheck; use std::num::NonZero; pub use check::{check_abi, check_abi_fn_ptr}; -use rustc_abi::VariantIdx; +use rustc_abi::{ExternAbi, VariantIdx}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -91,7 +91,6 @@ use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; -use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; @@ -142,8 +141,8 @@ fn get_owner_return_paths( /// Forbid defining intrinsics in Rust code, /// as they must always be defined by the compiler. // FIXME: Move this to a more appropriate place. -pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { - if let Abi::RustIntrinsic = abi { +pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: ExternAbi) { + if let ExternAbi::RustIntrinsic = abi { tcx.dcx().span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 679f6ccb816..b9cb48cafdc 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -17,6 +17,7 @@ use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::middle::region::*; use rustc_middle::ty::TyCtxt; +use rustc_session::lint; use rustc_span::source_map; use tracing::debug; @@ -167,8 +168,23 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } } if let Some(tail_expr) = blk.expr { - if blk.span.edition().at_least_rust_2024() { - visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); + let local_id = tail_expr.hir_id.local_id; + let edition = blk.span.edition(); + if edition.at_least_rust_2024() { + visitor.terminating_scopes.insert(local_id); + } else if !visitor + .tcx + .lints_that_dont_need_to_run(()) + .contains(&lint::LintId::of(lint::builtin::TAIL_EXPR_DROP_ORDER)) + { + // If this temporary scope will be changing once the codebase adopts Rust 2024, + // and we are linting about possible semantic changes that would result, + // then record this node-id in the field `backwards_incompatible_scope` + // for future reference. + visitor + .scope_tree + .backwards_incompatible_scope + .insert(local_id, Scope { id: local_id, data: ScopeData::Node }); } visitor.visit_expr(tail_expr); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d01c3784ade..9a70555fede 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,6 +2,7 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; +use rustc_abi::ExternAbi; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; @@ -23,7 +24,6 @@ use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::symbol::{Ident, sym}; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::misc::{ @@ -604,7 +604,7 @@ fn augment_param_env<'tcx>( ); // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this // i.e. traits::normalize_param_env_or_error - ty::ParamEnv::new(bounds, param_env.reveal()) + ty::ParamEnv::new(bounds) } /// We use the following trait as an example throughout this function. @@ -1048,8 +1048,10 @@ fn check_associated_item( .coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?; let self_ty = match item.container { - ty::TraitContainer => tcx.types.self_param, - ty::ImplContainer => tcx.type_of(item.container_id(tcx)).instantiate_identity(), + ty::AssocItemContainer::Trait => tcx.types.self_param, + ty::AssocItemContainer::Impl => { + tcx.type_of(item.container_id(tcx)).instantiate_identity() + } }; match item.kind { @@ -1072,7 +1074,7 @@ fn check_associated_item( check_method_receiver(wfcx, hir_sig, item, self_ty) } ty::AssocKind::Type => { - if let ty::AssocItemContainer::TraitContainer = item.container { + if let ty::AssocItemContainer::Trait = item.container { check_associated_type_bounds(wfcx, item, span) } if item.defaultness(tcx).has_value() { @@ -1124,7 +1126,7 @@ fn check_type_defn<'tcx>( let ty = tcx.type_of(variant.tail().did).instantiate_identity(); let ty = tcx.erase_regions(ty); assert!(!ty.has_infer()); - ty.needs_drop(tcx, tcx.param_env(item.owner_id)) + ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env)) } }; // All fields (except for possibly the last) should be sized. @@ -1279,7 +1281,8 @@ fn check_item_type( UnsizedHandling::Forbid => true, UnsizedHandling::Allow => false, UnsizedHandling::AllowIfForeignTail => { - let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.param_env); + let tail = + tcx.struct_tail_for_codegen(item_ty, wfcx.infcx.typing_env(wfcx.param_env)); !matches!(tail.kind(), ty::Foreign(_)) } }; @@ -1425,16 +1428,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let predicates = tcx.predicates_of(def_id.to_def_id()); let generics = tcx.generics_of(def_id); - let is_our_default = |def: &ty::GenericParamDef| match def.kind { - GenericParamDefKind::Type { has_default, .. } - | GenericParamDefKind::Const { has_default, .. } => { - has_default && def.index >= generics.parent_count as u32 - } - GenericParamDefKind::Lifetime => { - span_bug!(tcx.def_span(def.def_id), "lifetime params can have no default") - } - }; - // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. // For example, this forbids the declaration: // @@ -1442,40 +1435,21 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for param in &generics.own_params { - match param.kind { - GenericParamDefKind::Type { .. } => { - if is_our_default(param) { - let ty = tcx.type_of(param.def_id).instantiate_identity(); - // Ignore dependent defaults -- that is, where the default of one type - // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't - // be sure if it will error or not as user might always specify the other. - if !ty.has_param() { - wfcx.register_wf_obligation( - tcx.def_span(param.def_id), - Some(WellFormedLoc::Ty(param.def_id.expect_local())), - ty.into(), - ); - } - } - } - GenericParamDefKind::Const { .. } => { - if is_our_default(param) { - // FIXME(const_generics_defaults): This - // is incorrect when dealing with unused args, for example - // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>` - // we should eagerly error. - let default_ct = tcx.const_param_default(param.def_id).instantiate_identity(); - if !default_ct.has_param() { - wfcx.register_wf_obligation( - tcx.def_span(param.def_id), - None, - default_ct.into(), - ); - } - } + if let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) { + // Ignore dependent defaults -- that is, where the default of one type + // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't + // be sure if it will error or not as user might always specify the other. + // FIXME(generic_const_exprs): This is incorrect when dealing with unused const params. + // E.g: `struct Foo<const N: usize, const M: usize = { 1 - 2 }>;`. Here, we should + // eagerly error but we don't as we have `ConstKind::Unevaluated(.., [N, M])`. + if !default.has_param() { + wfcx.register_wf_obligation( + tcx.def_span(param.def_id), + matches!(param.kind, GenericParamDefKind::Type { .. }) + .then(|| WellFormedLoc::Ty(param.def_id.expect_local())), + default, + ); } - // Doesn't have defaults. - GenericParamDefKind::Lifetime => {} } } @@ -1488,39 +1462,16 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // // First we build the defaulted generic parameters. let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| { - match param.kind { - GenericParamDefKind::Lifetime => { - // All regions are identity. - tcx.mk_param_from_def(param) - } - - GenericParamDefKind::Type { .. } => { - // If the param has a default, ... - if is_our_default(param) { - let default_ty = tcx.type_of(param.def_id).instantiate_identity(); - // ... and it's not a dependent default, ... - if !default_ty.has_param() { - // ... then instantiate it with the default. - return default_ty.into(); - } - } - - tcx.mk_param_from_def(param) - } - GenericParamDefKind::Const { .. } => { - // If the param has a default, ... - if is_our_default(param) { - let default_ct = tcx.const_param_default(param.def_id).instantiate_identity(); - // ... and it's not a dependent default, ... - if !default_ct.has_param() { - // ... then instantiate it with the default. - return default_ct.into(); - } - } - - tcx.mk_param_from_def(param) - } + if param.index >= generics.parent_count as u32 + // If the param has a default, ... + && let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) + // ... and it's not a dependent default, ... + && !default.has_param() + { + // ... then instantiate it with the default. + return default; } + tcx.mk_param_from_def(param) }); // Now we build the instantiated predicates. @@ -1644,7 +1595,7 @@ fn check_fn_or_method<'tcx>( check_where_clauses(wfcx, span, def_id); - if sig.abi == Abi::RustCall { + if sig.abi == ExternAbi::RustCall { let span = tcx.def_span(def_id); let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None; let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 }); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 5ff52376837..3b49bc41ffe 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>( ) -> Result<(), ErrorGuaranteed> { let lang_items = tcx.lang_items(); let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; - let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); - res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); - res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| { + checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?; + checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?; + checker.check(lang_items.const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) - })); - res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { + })?; + checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy) - })); - - res = res.and( - checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized), - ); - res.and( - checker - .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn), - ) + })?; + checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?; + checker + .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; + checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?; + Ok(()) } struct Checker<'tcx> { @@ -259,7 +256,9 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let ty_a = field.ty(tcx, args_a); let ty_b = field.ty(tcx, args_b); - if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { + if let Ok(layout) = + tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a)) + { if layout.is_1zst() { // ignore 1-ZST fields return false; @@ -661,3 +660,63 @@ fn infringing_fields_error<'tcx>( err.emit() } + +fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { + let tcx = checker.tcx; + let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id); + let impl_span = tcx.def_span(checker.impl_def_id); + let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); + + // If an ADT is repr(transparent)... + if let ty::Adt(def, args) = *self_ty.kind() + && def.repr().transparent() + { + // FIXME(compiler-errors): This should and could be deduplicated into a query. + // Find the nontrivial field. + let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did()); + let nontrivial_field = def.all_fields().find(|field_def| { + let field_ty = tcx.type_of(field_def.did).instantiate_identity(); + !tcx.layout_of(adt_typing_env.as_query_input(field_ty)) + .is_ok_and(|layout| layout.layout.is_1zst()) + }); + + if let Some(nontrivial_field) = nontrivial_field { + // Check that the nontrivial field implements `PointerLike`. + let nontrivial_field = nontrivial_field.ty(tcx, args); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound( + ObligationCause::misc(impl_span, checker.impl_def_id), + param_env, + nontrivial_field, + tcx.lang_items().pointer_like().unwrap(), + ); + // FIXME(dyn-star): We should regionck this implementation. + if ocx.select_all_or_error().is_empty() { + return Ok(()); + } + } + } + + let is_permitted_primitive = match *self_ty.kind() { + ty::Adt(def, _) => def.is_box(), + ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true, + _ => false, + }; + + if is_permitted_primitive + && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty)) + && layout.layout.is_pointer_like(&tcx.data_layout) + { + return Ok(()); + } + + Err(tcx + .dcx() + .struct_span_err( + impl_span, + "implementation must be applied to type that has the same ABI as a pointer, \ + or is `repr(transparent)` and whose field is `PointerLike`", + ) + .emit()) +} diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 8a1a887766c..eca85c22a40 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -172,7 +172,7 @@ pub(crate) fn orphan_check_impl( // impl<T> AutoTrait for T {} // impl<T: ?Sized> AutoTrait for T {} ty::Param(..) => ( - if self_ty.is_sized(tcx, tcx.param_env(impl_def_id)) { + if self_ty.is_sized(tcx, ty::TypingEnv::non_body_analysis(tcx, impl_def_id)) { LocalImpl::Allow } else { LocalImpl::Disallow { problematic_kind: "generic type" } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3f6198dbd31..93be3e06e5d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -18,6 +18,7 @@ use std::cell::Cell; use std::iter; use std::ops::Bound; +use rustc_abi::ExternAbi; use rustc_ast::Recovered; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; @@ -38,7 +39,6 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMo use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::spec::abi; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; @@ -46,7 +46,7 @@ use tracing::{debug, instrument}; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; -use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; pub(crate) mod dump; mod generics_of; @@ -78,7 +78,7 @@ pub fn provide(providers: &mut Providers) { predicates_of::explicit_supertraits_containing_assoc_item, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, const_conditions: predicates_of::const_conditions, - implied_const_bounds: predicates_of::implied_const_bounds, + explicit_implied_const_bounds: predicates_of::explicit_implied_const_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, adt_def, @@ -88,6 +88,7 @@ pub fn provide(providers: &mut Providers) { coroutine_for_closure, opaque_ty_origin, rendered_precise_capturing_args, + const_param_default, ..*providers }; } @@ -339,6 +340,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { self.tcx.ensure().explicit_item_super_predicates(def_id); self.tcx.ensure().item_bounds(def_id); self.tcx.ensure().item_super_predicates(def_id); + if self.tcx.is_conditionally_const(def_id) { + self.tcx.ensure().explicit_implied_const_bounds(def_id); + self.tcx.ensure().const_conditions(def_id); + } intravisit::walk_opaque_ty(self, opaque); } @@ -634,7 +639,7 @@ fn get_new_lifetime_name<'tcx>( .collect_referenced_late_bound_regions(poly_trait_ref) .into_iter() .filter_map(|lt| { - if let ty::BoundRegionKind::BrNamed(_, name) = lt { + if let ty::BoundRegionKind::Named(_, name) = lt { Some(name.as_str().to_string()) } else { None @@ -681,6 +686,10 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure().generics_of(item.owner_id); tcx.ensure().type_of(item.owner_id); tcx.ensure().predicates_of(item.owner_id); + if tcx.is_conditionally_const(def_id) { + tcx.ensure().explicit_implied_const_bounds(def_id); + tcx.ensure().const_conditions(def_id); + } match item.kind { hir::ForeignItemKind::Fn(..) => { tcx.ensure().codegen_fn_attrs(item.owner_id); @@ -1031,6 +1040,7 @@ fn lower_variant( did: f.def_id.to_def_id(), name: f.ident.name, vis: tcx.visibility(f.def_id), + safety: f.safety, }) .collect(); let recovered = match def { @@ -1361,7 +1371,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn (Bound::Unbounded, Bound::Unbounded) => hir::Safety::Safe, _ => hir::Safety::Unsafe, }; - ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, abi::Abi::Rust)) + ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, ExternAbi::Rust)) } Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { @@ -1686,10 +1696,10 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'tcx>, - abi: abi::Abi, + abi: ExternAbi, safety: hir::Safety, ) -> ty::PolyFnSig<'tcx> { - let safety = if abi == abi::Abi::RustIntrinsic { + let safety = if abi == ExternAbi::RustIntrinsic { intrinsic_operation_unsafety(tcx, def_id) } else { safety @@ -1700,7 +1710,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( // Feature gate SIMD types in FFI, since I am not sure that the // ABIs are handled at all correctly. -huonw - if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi() { + if abi != ExternAbi::RustIntrinsic && !tcx.features().simd_ffi() { let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| { if ty.is_simd() { let snip = tcx @@ -1790,3 +1800,23 @@ fn rendered_precise_capturing_args<'tcx>( _ => None, }) } + +fn const_param_default<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + let default_ct = match tcx.hir_node_by_def_id(def_id) { + hir::Node::GenericParam(hir::GenericParam { + kind: hir::GenericParamKind::Const { default: Some(ct), .. }, + .. + }) => ct, + _ => span_bug!( + tcx.def_span(def_id), + "`const_param_default` expected a generic parameter with a constant" + ), + }; + let icx = ItemCtxt::new(tcx, def_id); + // FIXME(const_generics): investigate which places do and don't need const ty feeding + let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::No); + ty::EarlyBinder::bind(ct) +} diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index da779a16569..0b81f469371 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -43,7 +43,7 @@ fn associated_type_bounds<'tcx>( match filter { PredicateFilter::All | PredicateFilter::SelfOnly - | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); } @@ -122,7 +122,7 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( PredicateFilter::SelfOnly => { return None; } - PredicateFilter::SelfThatDefines(_) + PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfConstIfConst | PredicateFilter::SelfAndAssociatedTypeBounds | PredicateFilter::ConstIfConst => { @@ -329,7 +329,7 @@ fn opaque_type_bounds<'tcx>( match filter { PredicateFilter::All | PredicateFilter::SelfOnly - | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { // Associated types are implicitly sized unless a `?Sized` bound is found icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index efe84e0006f..b5dee5bd021 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -223,11 +223,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen trace!(?predicates); } hir::GenericParamKind::Const { .. } => { + let param_def_id = param.def_id.to_def_id(); let ct_ty = tcx - .type_of(param.def_id.to_def_id()) + .type_of(param_def_id) .no_bound_vars() .expect("const parameters cannot be generic"); - let ct = icx.lowerer().lower_const_param(param.hir_id); + let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id); predicates .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span)); } @@ -557,7 +558,11 @@ pub(super) fn explicit_supertraits_containing_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, (trait_def_id, assoc_name): (DefId, Ident), ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { - implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name)) + implied_predicates_with_filter( + tcx, + trait_def_id, + PredicateFilter::SelfTraitThatDefines(assoc_name), + ) } pub(super) fn explicit_implied_predicates_of<'tcx>( @@ -586,7 +591,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( let Some(trait_def_id) = trait_def_id.as_local() else { // if `assoc_name` is None, then the query should've been redirected to an // external provider - assert_matches!(filter, PredicateFilter::SelfThatDefines(_)); + assert_matches!(filter, PredicateFilter::SelfTraitThatDefines(_)); return tcx.explicit_super_predicates_of(trait_def_id); }; @@ -606,12 +611,8 @@ pub(super) fn implied_predicates_with_filter<'tcx>( let mut bounds = Bounds::default(); icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter); - let where_bounds_that_match = icx.probe_ty_param_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - filter, - ); + let where_bounds_that_match = + icx.probe_ty_param_bounds_in_generics(generics, item.owner_id.def_id, filter); // Combine the two lists to form the complete set of superbounds: let implied_bounds = @@ -652,7 +653,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( } // Make sure when elaborating supertraits, probing for associated types, etc., -// we really truly are elaborating clauses that have `Self` as their self type. +// we really truly are elaborating clauses that have `ty` as their self type. // This is very important since downstream code relies on this being correct. pub(super) fn assert_only_contains_predicates_from<'tcx>( filter: PredicateFilter, @@ -664,7 +665,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( } match filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + PredicateFilter::SelfOnly => { for (clause, _) in bounds { match clause.kind().skip_binder() { ty::ClauseKind::Trait(trait_predicate) => { @@ -704,6 +705,33 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( } } } + PredicateFilter::SelfTraitThatDefines(_) => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) => { + assert_eq!( + trait_predicate.self_ty(), + ty, + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" + ); + } + + ty::ClauseKind::Projection(_) + | ty::ClauseKind::TypeOutlives(_) + | ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => { + bug!( + "unexpected non-`Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } PredicateFilter::ConstIfConst => { for (clause, _) in bounds { match clause.kind().skip_binder() { @@ -767,21 +795,16 @@ pub(super) fn type_param_predicates<'tcx>( None => {} } - use rustc_hir::*; - use rustc_middle::ty::Ty; - // In the HIR, bounds can derive from two places. Either // written inline like `<T: Foo>` or in a where-clause like // `where T: Foo`. let param_id = tcx.local_def_id_to_hir_id(def_id); let param_owner = tcx.hir().ty_param_owner(def_id); - let generics = tcx.generics_of(param_owner); - let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let ty = Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner { + // FIXME: Shouldn't this be unreachable? None } else { tcx.generics_of(item_def_id).parent.map(|def_id| def_id.expect_local()) @@ -801,8 +824,9 @@ pub(super) fn type_param_predicates<'tcx>( let Some(hir_generics) = hir_node.generics() else { return result; }; + if let Node::Item(item) = hir_node - && let ItemKind::Trait(..) = item.kind + && let hir::ItemKind::Trait(..) = item.kind // Implied `Self: Trait` and supertrait bounds. && param_id == item_hir_id { @@ -811,23 +835,34 @@ pub(super) fn type_param_predicates<'tcx>( } let icx = ItemCtxt::new(tcx, item_def_id); - let extra_predicates = extend.into_iter().chain( - icx.probe_ty_param_bounds_in_generics( - hir_generics, - def_id, - ty, - PredicateFilter::SelfThatDefines(assoc_name), - ) - .into_iter() - .filter(|(predicate, _)| match predicate.kind().skip_binder() { - ty::ClauseKind::Trait(data) => data.self_ty().is_param(index), - _ => false, - }), + let extra_predicates = extend.into_iter().chain(icx.probe_ty_param_bounds_in_generics( + hir_generics, + def_id, + PredicateFilter::SelfTraitThatDefines(assoc_name), + )); + + let bounds = + &*tcx.arena.alloc_from_iter(result.skip_binder().iter().copied().chain(extra_predicates)); + + // Double check that the bounds *only* contain `SelfTy: Trait` preds. + let self_ty = match tcx.def_kind(def_id) { + DefKind::TyParam => Ty::new_param( + tcx, + tcx.generics_of(item_def_id) + .param_def_id_to_index(tcx, def_id.to_def_id()) + .expect("expected generic param to be owned by item"), + tcx.item_name(def_id.to_def_id()), + ), + DefKind::Trait | DefKind::TraitAlias => tcx.types.self_param, + _ => unreachable!(), + }; + assert_only_contains_predicates_from( + PredicateFilter::SelfTraitThatDefines(assoc_name), + bounds, + self_ty, ); - ty::EarlyBinder::bind( - tcx.arena.alloc_from_iter(result.skip_binder().iter().copied().chain(extra_predicates)), - ) + ty::EarlyBinder::bind(bounds) } impl<'tcx> ItemCtxt<'tcx> { @@ -841,7 +876,6 @@ impl<'tcx> ItemCtxt<'tcx> { &self, hir_generics: &'tcx hir::Generics<'tcx>, param_def_id: LocalDefId, - ty: Ty<'tcx>, filter: PredicateFilter, ) -> Vec<(ty::Clause<'tcx>, Span)> { let mut bounds = Bounds::default(); @@ -851,13 +885,21 @@ impl<'tcx> ItemCtxt<'tcx> { continue; }; - let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) { - ty - } else if matches!(filter, PredicateFilter::All) { - self.lowerer().lower_ty_maybe_return_type_notation(predicate.bounded_ty) - } else { - continue; - }; + match filter { + _ if predicate.is_param_bound(param_def_id.to_def_id()) => { + // Ok + } + PredicateFilter::All => { + // Ok + } + PredicateFilter::SelfOnly + | PredicateFilter::SelfTraitThatDefines(_) + | PredicateFilter::SelfConstIfConst + | PredicateFilter::SelfAndAssociatedTypeBounds => continue, + PredicateFilter::ConstIfConst => unreachable!(), + } + + let bound_ty = self.lowerer().lower_ty_maybe_return_type_notation(predicate.bounded_ty); let bound_vars = self.tcx.late_bound_vars(predicate.hir_id); self.lowerer().lower_bounds( @@ -917,6 +959,12 @@ pub(super) fn const_conditions<'tcx>( hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false), _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, + Node::OpaqueTy(opaque) => match opaque.origin { + hir::OpaqueTyOrigin::FnReturn { parent, .. } => return tcx.const_conditions(parent), + hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => { + unreachable!() + } + }, // N.B. Tuple ctors are unconditionally constant. Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(), _ => bug!("const_conditions called on wrong item: {def_id:?}"), @@ -976,7 +1024,7 @@ pub(super) fn const_conditions<'tcx>( } } -pub(super) fn implied_const_bounds<'tcx>( +pub(super) fn explicit_implied_const_bounds<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { @@ -992,10 +1040,11 @@ pub(super) fn implied_const_bounds<'tcx>( PredicateFilter::SelfConstIfConst, ) } - Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => { + Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) + | Node::OpaqueTy(_) => { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) } - _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"), + _ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"), }; bounds.map_bound(|bounds| { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 9483439ae4e..b4b3ef31f97 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -177,6 +177,7 @@ enum Scope<'a> { LateBoundary { s: ScopeRef<'a>, what: &'static str, + deny_late_regions: bool, }, Root { @@ -234,9 +235,11 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("s", &"..") .finish(), Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), - Scope::LateBoundary { s: _, what } => { - f.debug_struct("LateBoundary").field("what", what).finish() - } + Scope::LateBoundary { s: _, what, deny_late_regions } => f + .debug_struct("LateBoundary") + .field("what", what) + .field("deny_late_regions", deny_late_regions) + .finish(), Scope::Root { opt_parent_item } => { f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish() } @@ -322,7 +325,7 @@ fn late_arg_as_bound_arg<'tcx>( let name = tcx.item_name(def_id); match param.kind { GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) + ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id, name)) } GenericParamKind::Type { .. } => { ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) @@ -337,7 +340,7 @@ fn late_arg_as_bound_arg<'tcx>( fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind { match param.kind { ty::GenericParamDefKind::Lifetime => { - ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(param.def_id, param.name)) + ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(param.def_id, param.name)) } ty::GenericParamDefKind::Type { .. } => { ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) @@ -571,17 +574,23 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // We list scopes outwards, this causes us to see lifetime parameters in reverse // declaration order. In order to make it consistent with what `generics_of` might // give, we will reverse the IndexMap after early captures. + let mut late_depth = 0; let mut scope = self.scope; let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)]; loop { match *scope { - Scope::Binder { ref bound_vars, s, .. } => { + Scope::Binder { ref bound_vars, scope_type, s, .. } => { for (&original_lifetime, &def) in bound_vars.iter().rev() { if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { + let def = def.shifted(late_depth); let ident = lifetime_ident(original_lifetime); self.remap_opaque_captures(&opaque_capture_scopes, def, ident); } } + match scope_type { + BinderScopeType::Normal => late_depth += 1, + BinderScopeType::Concatenating => {} + } scope = s; } @@ -602,6 +611,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { Scope::Opaque { captures, def_id, s } => { opaque_capture_scopes.push((def_id, captures)); + late_depth = 0; scope = s; } @@ -623,7 +633,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + this.with(scope, |this| { + let scope = Scope::LateBoundary { + s: this.scope, + what: "nested `impl Trait`", + // We can capture late-bound regions; we just don't duplicate + // lifetime or const params, so we can't allow those. + deny_late_regions: false, + }; + this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + }) }); let captures = captures.into_inner().into_iter().collect(); @@ -980,9 +999,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { - self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| { - intravisit::walk_anon_const(this, c); - }); + self.with( + Scope::LateBoundary { s: self.scope, what: "constant", deny_late_regions: true }, + |this| { + intravisit::walk_anon_const(this, c); + }, + ); } fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) { @@ -1274,8 +1296,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } - Scope::LateBoundary { s, what } => { - crossed_late_boundary = Some(what); + Scope::LateBoundary { s, what, deny_late_regions } => { + if deny_late_regions { + crossed_late_boundary = Some(what); + } scope = s; } } @@ -1491,7 +1515,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } - Scope::LateBoundary { s, what } => { + Scope::LateBoundary { s, what, deny_late_regions: _ } => { crossed_late_boundary = Some(what); scope = s; } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 84161ec7648..816761fd00f 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -175,19 +175,13 @@ fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span // arm would handle this. // // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU - Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { + Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(ty, segment)), .. }) => { // Find the Item containing the associated type so we can create an ItemCtxt. // Using the ItemCtxt lower the HIR for the unresolved assoc type into a // ty which is a fully resolved projection. // For the code example above, this would mean lowering `Self::Assoc<3>` // to a ty::Alias(ty::Projection, `<Self as Foo>::Assoc<3>`). - let item_def_id = tcx - .hir() - .parent_owner_iter(arg_hir_id) - .find(|(_, node)| matches!(node, OwnerNode::Item(_))) - .unwrap() - .0 - .def_id; + let item_def_id = tcx.hir().get_parent_item(ty.hir_id).def_id; let ty = ItemCtxt::new(tcx, item_def_id).lower_ty(hir_ty); // Iterate through the generics of the projection to find the one that corresponds to diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a92a5e4278c..f5ca3c49475 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -735,6 +735,17 @@ pub(crate) struct InvalidUnionField { } #[derive(Diagnostic)] +#[diag(hir_analysis_invalid_unsafe_field, code = E0740)] +pub(crate) struct InvalidUnsafeField { + #[primary_span] + pub field_span: Span, + #[subdiagnostic] + pub sugg: InvalidUnsafeFieldSuggestion, + #[note] + pub note: (), +} + +#[derive(Diagnostic)] #[diag(hir_analysis_return_type_notation_on_non_rpitit)] pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> { #[primary_span] @@ -755,6 +766,18 @@ pub(crate) struct InvalidUnionFieldSuggestion { pub hi: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + hir_analysis_invalid_unsafe_field_sugg, + applicability = "machine-applicable" +)] +pub(crate) struct InvalidUnsafeFieldSuggestion { + #[suggestion_part(code = "std::mem::ManuallyDrop<")] + pub lo: Span, + #[suggestion_part(code = ">")] + pub hi: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_return_type_notation_equality_bound)] pub(crate) struct ReturnTypeNotationEqualityBound { @@ -1153,6 +1176,16 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { pub return_ty: Ty<'tcx>, } +#[derive(LintDiagnostic)] +#[diag(hir_analysis_rpitit_refined_lifetimes)] +#[note] +#[note(hir_analysis_feedback_note)] +pub(crate) struct ReturnPositionImplTraitInTraitRefinedLifetimes { + #[suggestion(applicability = "maybe-incorrect", code = "{suggestion}")] + pub suggestion_span: Span, + pub suggestion: String, +} + #[derive(Diagnostic)] #[diag(hir_analysis_inherent_ty_outside, code = E0390)] #[help] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index a5709089db6..6ebe1cedcaf 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -19,7 +19,9 @@ use tracing::{debug, instrument}; use super::errors::GenericsArgsErrExtend; use crate::bounds::Bounds; use crate::errors; -use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{ + AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason, +}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. @@ -152,9 +154,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { 'tcx: 'hir, { for hir_bound in hir_bounds { - // In order to avoid cycles, when we're lowering `SelfThatDefines`, + // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`, // we skip over any traits that don't define the given associated type. - if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter { + if let PredicateFilter::SelfTraitThatDefines(assoc_name) = predicate_filter { if let Some(trait_ref) = hir_bound.trait_ref() && let Some(trait_did) = trait_ref.trait_def_id() && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name) @@ -168,12 +170,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; - let polarity = match polarity { - rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, - rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, - rustc_ast::BoundPolarity::Maybe(_) => continue, - }; - let _ = self.lower_poly_trait_ref( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -352,9 +348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), - hir::Term::Const(ct) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into() - } + hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(), }; // Find any late-bound regions declared in `ty` that are not @@ -395,7 +389,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match predicate_filter { PredicateFilter::All | PredicateFilter::SelfOnly - | PredicateFilter::SelfThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { bounds.push_projection_bound( tcx, @@ -406,6 +399,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { constraint.span, ); } + // SelfTraitThatDefines is only interested in trait predicates. + PredicateFilter::SelfTraitThatDefines(_) => {} // `ConstIfConst` is only interested in `~const` bounds. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} } @@ -432,7 +427,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } PredicateFilter::SelfOnly - | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfConstIfConst => {} } } @@ -649,7 +644,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::GenericParamDefKind::Lifetime => { ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), + kind: ty::BoundRegionKind::Named(param.def_id, param.name), }) .into() } @@ -835,8 +830,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't } ty::ReBound(db, br) if db >= self.depth => { self.vars.insert(match br.kind { - ty::BrNamed(def_id, name) => (def_id, name), - ty::BrAnon | ty::BrEnv => { + ty::BoundRegionKind::Named(def_id, name) => (def_id, name), + ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => { let guar = self .cx .dcx() diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 672dc8ddeda..39471931461 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -1,9 +1,9 @@ +use rustc_abi::ExternAbi; use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err}; use rustc_hir::{self as hir, HirId}; use rustc_middle::bug; use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{self, ParamEnv, TyCtxt}; -use rustc_target::spec::abi; +use rustc_middle::ty::{self, TyCtxt}; use crate::errors; @@ -14,13 +14,13 @@ pub(crate) fn validate_cmse_abi<'tcx>( tcx: TyCtxt<'tcx>, dcx: DiagCtxtHandle<'_>, hir_id: HirId, - abi: abi::Abi, + abi: ExternAbi, fn_sig: ty::PolyFnSig<'tcx>, ) { let abi_name = abi.name(); match abi { - abi::Abi::CCmseNonSecureCall => { + ExternAbi::CCmseNonSecureCall => { let hir_node = tcx.hir_node(hir_id); let hir::Node::Ty(hir::Ty { span: bare_fn_span, @@ -78,7 +78,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( } }; } - abi::Abi::CCmseNonSecureEntry => { + ExternAbi::CCmseNonSecureEntry => { let hir_node = tcx.hir_node(hir_id); let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else { // might happen when this ABI is used incorrectly. That will be handled elsewhere @@ -130,7 +130,7 @@ fn is_valid_cmse_inputs<'tcx>( let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); for (index, ty) in fn_sig.inputs().iter().enumerate() { - let layout = tcx.layout_of(ParamEnv::reveal_all().and(*ty))?; + let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?; let align = layout.layout.align().abi.bytes(); let size = layout.layout.size().bytes(); @@ -158,8 +158,10 @@ fn is_valid_cmse_output<'tcx>( // this type is only used for layout computation, which does not rely on regions let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + let typing_env = ty::TypingEnv::fully_monomorphized(); + let mut ret_ty = fn_sig.output(); - let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?; + let layout = tcx.layout_of(typing_env.as_query_input(ret_ty))?; let size = layout.layout.size().bytes(); if size <= 4 { @@ -182,7 +184,7 @@ fn is_valid_cmse_output<'tcx>( for variant_def in adt_def.variants() { for field_def in variant_def.fields.iter() { let ty = field_def.ty(tcx, args); - let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty))?; + let layout = tcx.layout_of(typing_env.as_query_input(ty))?; if !layout.layout.is_1zst() { ret_ty = ty; @@ -195,17 +197,17 @@ fn is_valid_cmse_output<'tcx>( Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64) } -fn should_emit_generic_error<'tcx>(abi: abi::Abi, layout_err: &'tcx LayoutError<'tcx>) -> bool { +fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<'tcx>) -> bool { use LayoutError::*; match layout_err { Unknown(ty) => { match abi { - abi::Abi::CCmseNonSecureCall => { + ExternAbi::CCmseNonSecureCall => { // prevent double reporting of this error !ty.is_impl_trait() } - abi::Abi::CCmseNonSecureEntry => true, + ExternAbi::CCmseNonSecureEntry => true, _ => bug!("invalid ABI: {abi}"), } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 46a5cbb0af4..5e27ace4cbe 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -51,7 +51,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &trait_bound.trait_ref, trait_bound.span, hir::BoundConstness::Never, - ty::PredicatePolarity::Positive, + hir::BoundPolarity::Positive, dummy_self, &mut bounds, PredicateFilter::SelfOnly, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index dd0f250a8e2..4e5a8271e9e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1106,7 +1106,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect::<String>() ), [(only, _)] => only.to_string(), - [] => "this type".to_string(), + [] => bug!("expected one segment to deny"), }; let arg_spans: Vec<Span> = segments @@ -1136,7 +1136,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { "s", ), [only] => (only.to_string(), ""), - [] => unreachable!("expected at least one generic to prohibit"), + [] => bug!("expected at least one generic to prohibit"), }; let last_span = *arg_spans.last().unwrap(); let span: MultiSpan = arg_spans.into(); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 6e8a9ded4f3..ae1279d428c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -115,17 +115,22 @@ fn generic_arg_mismatch_err( } } (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => { - // FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too, - // this should match against that instead of ::Anon - if let hir::ConstArgKind::Anon(anon) = cnst.kind + if let hir::ConstArgKind::Path(qpath) = cnst.kind + && let rustc_hir::QPath::Resolved(_, path) = qpath + && let Res::Def(DefKind::Fn { .. }, id) = path.res + { + err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); + err.help("function item types cannot be named directly"); + } else if let hir::ConstArgKind::Anon(anon) = cnst.kind && let body = tcx.hir().body(anon.body) && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind + && let Res::Def(DefKind::Fn { .. }, id) = path.res { - if let Res::Def(DefKind::Fn { .. }, id) = path.res { - err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); - err.help("function item types cannot be named directly"); - } + // FIXME(min_generic_const_args): this branch is dead once new const path lowering + // (for single-segment paths) is no longer gated + err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); + err.help("function item types cannot be named directly"); } } _ => {} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d70e4d8345a..01276abec22 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -30,7 +30,7 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, }; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -47,7 +47,6 @@ use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::spec::abi; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -76,7 +75,7 @@ pub enum PredicateFilter { /// Only traits that reference `Self: ..` and define an associated type /// with the given ident are implied by the trait. This mode exists to /// side-step query cycles when lowering associated types. - SelfThatDefines(Ident), + SelfTraitThatDefines(Ident), /// Only traits that reference `Self: ..` and their associated type bounds. /// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr` @@ -218,6 +217,23 @@ impl AssocItemQSelf { } } +/// In some cases, [`hir::ConstArg`]s that are being used in the type system +/// through const generics need to have their type "fed" to them +/// using the query system. +/// +/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the +/// desired behavior. +#[derive(Debug, Clone, Copy)] +pub enum FeedConstTy { + /// Feed the type. + /// + /// The `DefId` belongs to the const param that we are supplying + /// this (anon) const arg to. + Param(DefId), + /// Don't feed the type. + No, +} + /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// @@ -315,7 +331,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), - kind: ty::BrNamed(def_id.to_def_id(), name), + kind: ty::BoundRegionKind::Named(def_id.to_def_id(), name), }; ty::Region::new_bound(tcx, debruijn, br) } @@ -333,7 +349,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_late_param( tcx, scope.to_def_id(), - ty::BrNamed(id.to_def_id(), name), + ty::BoundRegionKind::Named(id.to_def_id(), name), ) // (*) -- not late-bound, won't change @@ -501,8 +517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id)) - .into() + self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into() } (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.lowerer.ct_infer(Some(param), inf.span).into() @@ -563,7 +578,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Err(guar) = ty.error_reported() { return ty::Const::new_error(tcx, guar).into(); } - // FIXME(effects) see if we should special case effect params here if !infer_args && has_default { tcx.const_param_default(param.def_id) .instantiate(tcx, preceding_args) @@ -668,7 +682,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_ref: &hir::TraitRef<'tcx>, span: Span, constness: hir::BoundConstness, - polarity: ty::PredicatePolarity, + polarity: hir::BoundPolarity, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, predicate_filter: PredicateFilter, @@ -690,15 +704,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(self_ty), ); - if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness - && !self.tcx().is_const_trait(trait_def_id) - { - self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { - span, - modifier: constness.as_str(), - }); - } - let tcx = self.tcx(); let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); debug!(?bound_vars); @@ -708,10 +713,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bound_vars, ); + let polarity = match polarity { + rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, + rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, + rustc_ast::BoundPolarity::Maybe(_) => { + // Validate associated type at least. We may want to reject these + // outright in the future... + for constraint in trait_segment.args().constraints { + let _ = self.lower_assoc_item_constraint( + trait_ref.hir_ref_id, + poly_trait_ref, + constraint, + &mut Default::default(), + &mut Default::default(), + constraint.span, + predicate_filter, + ); + } + return arg_count; + } + }; + + if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness + && !self.tcx().is_const_trait(trait_def_id) + { + self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { + span, + modifier: constness.as_str(), + }); + } + match predicate_filter { + // This is only concerned with trait predicates. + PredicateFilter::SelfTraitThatDefines(..) => { + bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); + } PredicateFilter::All | PredicateFilter::SelfOnly - | PredicateFilter::SelfThatDefines(..) | PredicateFilter::SelfAndAssociatedTypeBounds => { debug!(?poly_trait_ref); bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); @@ -763,11 +801,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // since we should have emitted an error for them earlier, and they // would not be well-formed! if polarity != ty::PredicatePolarity::Positive { - assert!( - self.dcx().has_errors().is_some(), + self.dcx().span_delayed_bug( + constraint.span, "negative trait bounds should not have assoc item constraints", ); - continue; + break; } // Specify type to assert that error was already reported in `Err` case. @@ -957,8 +995,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No) - .into() + self.lower_const_arg(ct, FeedConstTy::No).into() } }; // FIXME(#97583): This isn't syntactically well-formed! @@ -2003,23 +2040,138 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] /// and late-bound ones to [`ty::ConstKind::Bound`]. - pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> { + pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); - match tcx.named_bound_var(hir_id) { - Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + + match tcx.named_bound_var(path_hir_id) { + Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. - let item_def_id = tcx.local_parent(def_id); + let item_def_id = tcx.parent(param_def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let name = tcx.item_name(def_id.to_def_id()); + let index = generics.param_def_id_to_index[¶m_def_id]; + let name = tcx.item_name(param_def_id); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) } Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), - arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), + arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), + } + } + + /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const). + #[instrument(skip(self), level = "debug")] + pub fn lower_const_arg( + &self, + const_arg: &hir::ConstArg<'tcx>, + feed: FeedConstTy, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + if let FeedConstTy::Param(param_def_id) = feed + && let hir::ConstArgKind::Anon(anon) = &const_arg.kind + { + tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id)); + } + + let hir_id = const_arg.hir_id; + match const_arg.kind { + hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { + debug!(?maybe_qself, ?path); + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + self.lower_const_path_resolved(opt_self_ty, path, hir_id) + } + hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message( + tcx, + qpath.span(), + format!("Const::lower_const_arg: invalid qpath {qpath:?}"), + ), + hir::ConstArgKind::Anon(anon) => Const::from_anon_const(tcx, anon.def_id), + } + } + + fn lower_const_path_resolved( + &self, + opt_self_ty: Option<Ty<'tcx>>, + path: &hir::Path<'tcx>, + hir_id: HirId, + ) -> Const<'tcx> { + let tcx = self.tcx(); + let span = path.span; + match path.res { + Res::Def(DefKind::ConstParam, def_id) => { + assert_eq!(opt_self_ty, None); + let _ = self.prohibit_generic_args( + path.segments.iter(), + GenericsArgsErrExtend::Param(def_id), + ); + self.lower_const_param(def_id, hir_id) + } + Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => { + assert_eq!(opt_self_ty, None); + let _ = self.prohibit_generic_args( + path.segments.split_last().unwrap().1.iter(), + GenericsArgsErrExtend::None, + ); + let args = self.lower_generic_args_of_path_segment( + span, + did, + path.segments.last().unwrap(), + ); + ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) + } + Res::Def(DefKind::Static { .. }, _) => { + span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") + } + // FIXME(const_generics): create real const to allow fn items as const paths + Res::Def(DefKind::Fn | DefKind::AssocFn, _) => ty::Const::new_error_with_message( + tcx, + span, + "fn items cannot be used as const args", + ), + + // Exhaustive match to be clear about what exactly we're considering to be + // an invalid Res for a const path. + Res::Def( + DefKind::Mod + | DefKind::Enum + | DefKind::Variant + | DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) + | DefKind::Struct + | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) + | DefKind::OpaqueTy + | DefKind::TyAlias + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::Union + | DefKind::Trait + | DefKind::ForeignTy + | DefKind::AssocConst + | DefKind::TyParam + | DefKind::Macro(_) + | DefKind::LifetimeParam + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::Field + | DefKind::Impl { .. } + | DefKind::Closure + | DefKind::ExternCrate + | DefKind::GlobalAsm + | DefKind::SyntheticCoroutineBody, + _, + ) + | Res::PrimTy(_) + | Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } + | Res::SelfCtor(_) + | Res::Local(_) + | Res::ToolMod + | Res::NonMacroAttr(_) + | Res::Err => Const::new_error_with_message(tcx, span, "invalid Res for const path"), } } @@ -2031,14 +2183,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Lower a type from the HIR to our internal notion of a type given some extra data for diagnostics. - /// - /// Extra diagnostic data: - /// - /// 1. `borrowed`: Whether trait object types are borrowed like in `&dyn Trait`. - /// Used to avoid emitting redundant errors. - /// 2. `in_path`: Whether the type appears inside of a path. - /// Used to provide correct diagnostics for bare trait object types. + /// Lower a type from the HIR to our internal notion of a type. #[instrument(level = "debug", skip(self), ret)] pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2167,7 +2312,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let length = match length { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { - ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No) + self.lower_const_arg(constant, FeedConstTy::No) } }; @@ -2225,7 +2370,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .type_of(def_id) .no_bound_vars() .expect("const parameter types cannot be generic"); - let ct = self.lower_const_param(expr.hir_id); + let ct = self.lower_const_param(def_id, expr.hir_id); (ct, ty) } @@ -2329,7 +2474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, hir_id: HirId, safety: hir::Safety, - abi: abi::Abi, + abi: rustc_abi::ExternAbi, decl: &hir::FnDecl<'tcx>, generics: Option<&hir::Generics<'_>>, hir_ty: Option<&hir::Ty<'_>>, @@ -2427,15 +2572,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) { for br in referenced_regions.difference(&constrained_regions) { let br_name = match *br { - ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon | ty::BrEnv => { - "an anonymous lifetime".to_string() - } - ty::BrNamed(_, name) => format!("lifetime `{name}`"), + ty::BoundRegionKind::Named(_, kw::UnderscoreLifetime) + | ty::BoundRegionKind::Anon + | ty::BoundRegionKind::ClosureEnv => "an anonymous lifetime".to_string(), + ty::BoundRegionKind::Named(_, name) => format!("lifetime `{name}`"), }; let mut err = generate_err(&br_name); - if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon = *br { + if let ty::BoundRegionKind::Named(_, kw::UnderscoreLifetime) + | ty::BoundRegionKind::Anon = *br + { // The only way for an anonymous lifetime to wind up // in the return type but **also** be unconstrained is // if it only appears in "associated types" in the diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index b0c9aed5d85..246643d8074 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -70,6 +70,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ @@ -210,13 +211,7 @@ fn get_impl_args( impl1_def_id.to_def_id(), impl1_args, impl2_node, - |_, span| { - traits::ObligationCause::new( - impl1_span, - impl1_def_id, - traits::ObligationCauseCode::WhereClause(impl2_node.def_id(), span), - ) - }, + &ObligationCause::misc(impl1_span, impl1_def_id), ); let errors = ocx.select_all_or_error(); @@ -459,7 +454,7 @@ fn trait_predicates_eq<'tcx>( predicate1: ty::Predicate<'tcx>, predicate2: ty::Predicate<'tcx>, ) -> bool { - // FIXME(effects) + // FIXME(const_trait_impl) predicate1 == predicate2 } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 339eddeeade..0a26b6776bb 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -91,28 +91,35 @@ mod impl_wf_check; mod outlives; mod variance; +use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::Span; use rustc_span::symbol::sym; -use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; +use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { +fn require_c_abi_if_c_variadic( + tcx: TyCtxt<'_>, + decl: &hir::FnDecl<'_>, + abi: ExternAbi, + span: Span, +) { const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`"; const CONVENTIONS_STABLE: &str = "`C` or `cdecl`"; const UNSTABLE_EXPLAIN: &str = "using calling conventions other than `C` or `cdecl` for varargs functions is unstable"; - if !decl.c_variadic || matches!(abi, Abi::C { .. } | Abi::Cdecl { .. }) { + if !decl.c_variadic || matches!(abi, ExternAbi::C { .. } | ExternAbi::Cdecl { .. }) { return; } @@ -183,8 +190,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) { DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all(); - tcx.ensure().eval_to_const_value_raw(param_env.and(cid)); + let typing_env = ty::TypingEnv::fully_monomorphized(); + tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid)); } _ => (), } @@ -221,3 +228,14 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id); collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty) } + +/// This is for rustdoc. +// FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed +pub fn lower_const_arg_for_rustdoc<'tcx>( + tcx: TyCtxt<'tcx>, + hir_ct: &hir::ConstArg<'tcx>, + feed: FeedConstTy, +) -> Const<'tcx> { + let env_def_id = tcx.hir().get_parent_item(hir_ct.hir_id); + collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) +} |
