Skip to content

Commit bc4a1de

Browse files
jswrennm1el
andcommitted
Initial (incomplete) implementation of transmutability trait.
This initial implementation handles transmutations between types with specified layouts, except when references are involved. Co-authored-by: Igor null <m1el.2027@gmail.com>
1 parent 2a22093 commit bc4a1de

File tree

91 files changed

+5691
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+5691
-2
lines changed

Cargo.lock

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4553,6 +4553,7 @@ dependencies = [
45534553
"rustc_session",
45544554
"rustc_span",
45554555
"rustc_target",
4556+
"rustc_transmute",
45564557
"smallvec",
45574558
"tracing",
45584559
]
@@ -4577,6 +4578,20 @@ dependencies = [
45774578
"tracing",
45784579
]
45794580

4581+
[[package]]
4582+
name = "rustc_transmute"
4583+
version = "0.1.0"
4584+
dependencies = [
4585+
"itertools",
4586+
"rustc_data_structures",
4587+
"rustc_infer",
4588+
"rustc_macros",
4589+
"rustc_middle",
4590+
"rustc_span",
4591+
"rustc_target",
4592+
"tracing",
4593+
]
4594+
45804595
[[package]]
45814596
name = "rustc_ty_utils"
45824597
version = "0.0.0"

compiler/rustc_hir/src/lang_items.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ language_item_table! {
191191
CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
192192
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
193193

194+
// language items relating to transmutability
195+
TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6);
196+
194197
Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
195198
Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
196199
Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1);

compiler/rustc_middle/src/traits/select.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ pub enum SelectionCandidate<'tcx> {
109109
/// `false` if there are no *further* obligations.
110110
has_nested: bool,
111111
},
112+
113+
/// Implementation of transmutability trait.
114+
TransmutabilityCandidate,
115+
112116
ParamCandidate(ty::PolyTraitPredicate<'tcx>),
113117
ImplCandidate(DefId),
114118
AutoImplCandidate(DefId),

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub use subst::*;
4848
pub use vtable::*;
4949

5050
use std::fmt::Debug;
51-
use std::hash::Hash;
51+
use std::hash::{Hash, Hasher};
5252
use std::ops::ControlFlow;
5353
use std::{fmt, str};
5454

@@ -1724,6 +1724,26 @@ impl VariantDef {
17241724
}
17251725
}
17261726

1727+
/// There should be only one VariantDef for each `def_id`, therefore
1728+
/// it is fine to implement `PartialEq` only based on `def_id`.
1729+
impl PartialEq for VariantDef {
1730+
#[inline]
1731+
fn eq(&self, other: &Self) -> bool {
1732+
self.def_id == other.def_id
1733+
}
1734+
}
1735+
1736+
impl Eq for VariantDef {}
1737+
1738+
/// There should be only one VariantDef for each `def_id`, therefore
1739+
/// it is fine to implement `Hash` only based on `def_id`.
1740+
impl Hash for VariantDef {
1741+
#[inline]
1742+
fn hash<H: Hasher>(&self, s: &mut H) {
1743+
self.def_id.hash(s)
1744+
}
1745+
}
1746+
17271747
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
17281748
pub enum VariantDiscr {
17291749
/// Explicit value for this variant, i.e., `X = 123`.
@@ -1744,6 +1764,26 @@ pub struct FieldDef {
17441764
pub vis: Visibility,
17451765
}
17461766

1767+
/// There should be only one FieldDef for each `did`, therefore
1768+
/// it is fine to implement `PartialEq` only based on `did`.
1769+
impl PartialEq for FieldDef {
1770+
#[inline]
1771+
fn eq(&self, other: &Self) -> bool {
1772+
self.did == other.did
1773+
}
1774+
}
1775+
1776+
impl Eq for FieldDef {}
1777+
1778+
/// There should be only one FieldDef for each `did`, therefore
1779+
/// it is fine to implement `Hash` only based on `did`.
1780+
impl Hash for FieldDef {
1781+
#[inline]
1782+
fn hash<H: Hasher>(&self, s: &mut H) {
1783+
self.did.hash(s)
1784+
}
1785+
}
1786+
17471787
bitflags! {
17481788
#[derive(TyEncodable, TyDecodable, Default, HashStable)]
17491789
pub struct ReprFlags: u8 {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,7 @@ symbols! {
14621462
trait_alias,
14631463
trait_upcasting,
14641464
transmute,
1465+
transmute_trait,
14651466
transparent,
14661467
transparent_enums,
14671468
transparent_unions,

compiler/rustc_target/src/abi/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ impl fmt::Debug for Align {
508508

509509
impl Align {
510510
pub const ONE: Align = Align { pow2: 0 };
511+
pub const MAX: Align = Align { pow2: 29 };
511512

512513
#[inline]
513514
pub fn from_bits(bits: u64) -> Result<Align, String> {
@@ -540,7 +541,7 @@ impl Align {
540541
if bytes != 1 {
541542
return Err(not_power_of_2(align));
542543
}
543-
if pow2 > 29 {
544+
if pow2 > Self::MAX.pow2 {
544545
return Err(too_large(align));
545546
}
546547

compiler/rustc_trait_selection/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ rustc_query_system = { path = "../rustc_query_system" }
2323
rustc_session = { path = "../rustc_session" }
2424
rustc_span = { path = "../rustc_span" }
2525
rustc_target = { path = "../rustc_target" }
26+
rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
2627
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
305305
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
306306
} else if lang_items.destruct_trait() == Some(def_id) {
307307
self.assemble_const_destruct_candidates(obligation, &mut candidates);
308+
} else if lang_items.transmute_trait() == Some(def_id) {
309+
// User-defined transmutability impls are permitted.
310+
self.assemble_candidates_from_impls(obligation, &mut candidates);
311+
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
308312
} else {
309313
if lang_items.clone_trait() == Some(def_id) {
310314
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -873,6 +877,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
873877
};
874878
}
875879

880+
#[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
881+
fn assemble_candidates_for_transmutability(
882+
&mut self,
883+
obligation: &TraitObligation<'tcx>,
884+
candidates: &mut SelectionCandidateSet<'tcx>,
885+
) {
886+
if obligation.has_param_types_or_consts() {
887+
candidates.ambiguous = false;
888+
return;
889+
}
890+
891+
if obligation.has_infer_types_or_consts() {
892+
candidates.ambiguous = true;
893+
return;
894+
}
895+
896+
candidates.vec.push(TransmutabilityCandidate);
897+
}
898+
876899
#[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
877900
fn assemble_candidates_for_trait_alias(
878901
&mut self,

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
4848
ImplSource::Builtin(data)
4949
}
5050

51+
TransmutabilityCandidate => {
52+
let data = self.confirm_transmutability_candidate(obligation)?;
53+
ImplSource::Builtin(data)
54+
}
55+
5156
ParamCandidate(param) => {
5257
let obligations =
5358
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
@@ -267,6 +272,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
267272
ImplSourceBuiltinData { nested: obligations }
268273
}
269274

275+
fn confirm_transmutability_candidate(
276+
&mut self,
277+
obligation: &TraitObligation<'tcx>,
278+
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
279+
debug!(?obligation, "confirm_transmutability_candidate");
280+
281+
let predicate = obligation.predicate;
282+
283+
let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
284+
let bool_at = |i| {
285+
predicate
286+
.skip_binder()
287+
.trait_ref
288+
.substs
289+
.const_at(i)
290+
.try_eval_bool(self.tcx(), obligation.param_env)
291+
.unwrap()
292+
};
293+
294+
let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
295+
src: p.trait_ref.substs.type_at(1),
296+
dst: p.trait_ref.substs.type_at(0),
297+
});
298+
299+
let scope = type_at(2).skip_binder();
300+
301+
let assume = rustc_transmute::Assume {
302+
alignment: bool_at(3),
303+
lifetimes: bool_at(4),
304+
validity: bool_at(5),
305+
visibility: bool_at(6),
306+
};
307+
308+
let cause = obligation.cause.clone();
309+
310+
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
311+
312+
let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
313+
314+
use rustc_transmute::Answer;
315+
316+
match maybe_transmutable {
317+
Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
318+
_ => Err(Unimplemented),
319+
}
320+
}
321+
270322
/// This handles the case where an `auto trait Foo` impl is being used.
271323
/// The idea is that the impl applies to `X : Foo` if the following conditions are met:
272324
///

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,6 +1630,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16301630
);
16311631
}
16321632

1633+
// FIXME(@jswrenn): this should probably be more sophisticated
1634+
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
1635+
16331636
// (*)
16341637
(
16351638
BuiltinCandidate { has_nested: false }

0 commit comments

Comments
 (0)