Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some rustc_transmute cleanups #137776

Merged
merged 6 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4500,8 +4500,6 @@ dependencies = [
"rustc_abi",
"rustc_data_structures",
"rustc_hir",
"rustc_infer",
"rustc_macros",
"rustc_middle",
"rustc_span",
"tracing",
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_next_trait_solver/src/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {

fn is_transmutable(
&self,
param_env: <Self::Interner as Interner>::ParamEnv,
dst: <Self::Interner as Interner>::Ty,
src: <Self::Interner as Interner>::Ty,
assume: <Self::Interner as Interner>::Const,
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,12 +1037,11 @@ where

pub(super) fn is_transmutable(
&mut self,
param_env: I::ParamEnv,
dst: I::Ty,
src: I::Ty,
assume: I::Const,
) -> Result<Certainty, NoSolution> {
self.delegate.is_transmutable(param_env, dst, src, assume)
self.delegate.is_transmutable(dst, src, assume)
}
}

Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,6 @@ where
)?;

let certainty = ecx.is_transmutable(
goal.param_env,
goal.predicate.trait_ref.args.type_at(0),
goal.predicate.trait_ref.args.type_at(1),
assume,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2530,9 +2530,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return GetSafeTransmuteErrorAndReason::Silent;
};

let Some(assume) =
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
else {
let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
self.dcx().span_delayed_bug(
span,
"Unable to construct rustc_transmute::Assume where it was previously possible",
Expand All @@ -2544,11 +2542,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let src = trait_pred.trait_ref.args.type_at(1);
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");

match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
obligation.cause,
src_and_dst,
assume,
) {
match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx)
.is_transmutable(src_and_dst, assume)
{
Answer::No(reason) => {
let safe_transmute_explanation = match reason {
rustc_transmute::Reason::SrcIsNotYetSupported => {
Expand Down
12 changes: 4 additions & 8 deletions compiler/rustc_trait_selection/src/solve/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use rustc_infer::infer::canonical::{
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
};
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::solve::Goal;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
Expand Down Expand Up @@ -222,7 +221,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
// register candidates. We probably need to register >1 since we may have an OR of ANDs.
fn is_transmutable(
&self,
param_env: ty::ParamEnv<'tcx>,
dst: Ty<'tcx>,
src: Ty<'tcx>,
assume: ty::Const<'tcx>,
Expand All @@ -231,16 +229,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
// which will ICE for region vars.
let (dst, src) = self.tcx.erase_regions((dst, src));

let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else {
let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else {
return Err(NoSolution);
};

// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable(
ObligationCause::dummy(),
rustc_transmute::Types { src, dst },
assume,
) {
match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx)
.is_transmutable(rustc_transmute::Types { src, dst }, assume)
{
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
}
Expand Down
13 changes: 4 additions & 9 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,22 +414,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if self.tcx().features().generic_const_exprs() {
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
}
let Some(assume) =
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
else {
let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
return Err(Unimplemented);
};

let dst = predicate.trait_ref.args.type_at(0);
let src = predicate.trait_ref.args.type_at(1);

debug!(?src, ?dst);
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
let maybe_transmutable = transmute_env.is_transmutable(
obligation.cause.clone(),
rustc_transmute::Types { dst, src },
assume,
);
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx);
let maybe_transmutable =
transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume);

let fully_flattened = match maybe_transmutable {
Answer::No(_) => Err(Unimplemented)?,
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_transmute/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ edition = "2024"
rustc_abi = { path = "../rustc_abi", optional = true }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir", optional = true }
rustc_infer = { path = "../rustc_infer", optional = true }
rustc_macros = { path = "../rustc_macros", optional = true }
rustc_middle = { path = "../rustc_middle", optional = true }
rustc_span = { path = "../rustc_span", optional = true }
tracing = "0.1"
Expand All @@ -19,8 +17,6 @@ tracing = "0.1"
rustc = [
"dep:rustc_abi",
"dep:rustc_hir",
"dep:rustc_infer",
"dep:rustc_macros",
"dep:rustc_middle",
"dep:rustc_span",
]
Expand Down
11 changes: 1 addition & 10 deletions compiler/rustc_transmute/src/layout/dfa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<R> Transitions<R>
where
R: Ref,
{
#[allow(dead_code)]
#[cfg(test)]
fn insert(&mut self, transition: Transition<R>, state: State) {
match transition {
Transition::Byte(b) => {
Expand Down Expand Up @@ -86,15 +86,6 @@ impl<R> Dfa<R>
where
R: Ref,
{
#[allow(dead_code)]
pub(crate) fn unit() -> Self {
let transitions: Map<State, Transitions<R>> = Map::default();
let start = State::new();
let accepting = start;

Self { transitions, start, accepting }
}

#[cfg(test)]
pub(crate) fn bool() -> Self {
let mut transitions: Map<State, Transitions<R>> = Map::default();
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_transmute/src/layout/nfa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,6 @@ where
}
Self { transitions, start, accepting }
}

#[allow(dead_code)]
pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
self.transitions.get(&start)
}
}

impl State {
Expand Down
14 changes: 6 additions & 8 deletions compiler/rustc_transmute/src/layout/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub(crate) mod rustc {

ty::Tuple(members) => Self::from_tuple((ty, layout), members, cx),

ty::Array(inner_ty, len) => {
ty::Array(inner_ty, _len) => {
let FieldsShape::Array { stride, count } = &layout.fields else {
return Err(Err::NotYetSupported);
};
Expand Down Expand Up @@ -282,7 +282,6 @@ pub(crate) mod rustc {
FieldsShape::Primitive => {
assert_eq!(members.len(), 1);
let inner_ty = members[0];
let inner_layout = layout_of(cx, inner_ty)?;
Self::from_ty(inner_ty, cx)
}
FieldsShape::Arbitrary { offsets, .. } => {
Expand Down Expand Up @@ -345,7 +344,7 @@ pub(crate) mod rustc {
// the enum delegates its layout to the variant at `index`.
layout_of_variant(*index, None)
}
Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
Variants::Multiple { tag: _, tag_encoding, tag_field, .. } => {
// `Variants::Multiple` denotes an enum with multiple
// variants. The layout of such an enum is the disjunction
// of the layouts of its tagged variants.
Expand All @@ -356,7 +355,7 @@ pub(crate) mod rustc {

let variants = def.discriminants(cx.tcx()).try_fold(
Self::uninhabited(),
|variants, (idx, ref discriminant)| {
|variants, (idx, _discriminant)| {
let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?;
Result::<Self, Err>::Ok(variants.or(variant))
},
Expand Down Expand Up @@ -414,7 +413,7 @@ pub(crate) mod rustc {

// Append the fields, in memory order, to the layout.
let inverse_memory_index = memory_index.invert_bijective_mapping();
for (memory_idx, &field_idx) in inverse_memory_index.iter_enumerated() {
for &field_idx in inverse_memory_index.iter() {
// Add interfield padding.
let padding_needed = offsets[field_idx] - size;
let padding = Self::padding(padding_needed.bytes_usize());
Expand Down Expand Up @@ -468,15 +467,14 @@ pub(crate) mod rustc {

// This constructor does not support non-`FieldsShape::Union`
// layouts. Fields of this shape are all placed at offset 0.
let FieldsShape::Union(fields) = layout.fields() else {
let FieldsShape::Union(_fields) = layout.fields() else {
return Err(Err::NotYetSupported);
};

let fields = &def.non_enum_variant().fields;
let fields = fields.iter_enumerated().try_fold(
Self::uninhabited(),
|fields, (idx, field_def)| {
let field_def = Def::Field(field_def);
|fields, (idx, _field_def)| {
let field_ty = ty_field(cx, (ty, layout), idx);
let field_layout = layout_of(cx, field_ty)?;
let field = Self::from_ty(field_ty, cx)?;
Expand Down
32 changes: 9 additions & 23 deletions compiler/rustc_transmute/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// tidy-alphabetical-start
#![allow(unused_variables)]
#![feature(alloc_layout_extra)]
#![feature(never_type)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end
Expand Down Expand Up @@ -81,55 +79,43 @@ pub enum Reason<T> {
#[cfg(feature = "rustc")]
mod rustc {
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::InferCtxt;
use rustc_macros::TypeVisitable;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{Const, ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::{Const, Ty, TyCtxt};

use super::*;

/// The source and destination types of a transmutation.
#[derive(TypeVisitable, Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct Types<'tcx> {
/// The source type.
pub src: Ty<'tcx>,
/// The destination type.
pub dst: Ty<'tcx>,
}

pub struct TransmuteTypeEnv<'cx, 'tcx> {
infcx: &'cx InferCtxt<'tcx>,
pub struct TransmuteTypeEnv<'tcx> {
tcx: TyCtxt<'tcx>,
}

impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
Self { infcx }
impl<'tcx> TransmuteTypeEnv<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
Self { tcx }
}

#[allow(unused)]
pub fn is_transmutable(
&mut self,
cause: ObligationCause<'tcx>,
types: Types<'tcx>,
assume: crate::Assume,
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
crate::maybe_transmutable::MaybeTransmutableQuery::new(
types.src,
types.dst,
assume,
self.infcx.tcx,
types.src, types.dst, assume, self.tcx,
)
.answer()
}
}

impl Assume {
/// Constructs an `Assume` from a given const-`Assume`.
pub fn from_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
ct: Const<'tcx>,
) -> Option<Self> {
pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
use rustc_middle::ty::ScalarInt;
use rustc_span::sym;

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_transmute/src/maybe_transmutable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ where
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
let Self { src, dst, assume, context } = self;

// Unconditionally all `Def` nodes from `src`, without pruning away the
// Unconditionally remove all `Def` nodes from `src`, without pruning away the
// branches they appear in. This is valid to do for value-to-value
// transmutations, but not for `&mut T` to `&mut U`; we will need to be
// more sophisticated to handle transmutations between mutable
// references.
let src = src.prune(&|def| false);
let src = src.prune(&|_def| false);

if src.is_inhabited() && !dst.is_inhabited() {
return Answer::No(Reason::DstUninhabited);
Expand All @@ -96,7 +96,7 @@ where
let dst = if assume.safety {
// ...if safety is assumed, don't check if they carry safety
// invariants; retain all paths.
dst.prune(&|def| false)
dst.prune(&|_def| false)
} else {
// ...otherwise, prune away all paths with safety invariants from
// the `Dst` layout.
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_transmute/src/maybe_transmutable/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ mod bool {

#[test]
fn should_permit_validity_expansion_and_reject_contraction() {
let un = layout::Tree::<Def, !>::uninhabited();
let b0 = layout::Tree::<Def, !>::from_bits(0);
let b1 = layout::Tree::<Def, !>::from_bits(1);
let b2 = layout::Tree::<Def, !>::from_bits(2);
Expand Down
Loading