Skip to content

Commit 09818c9

Browse files
authored
Unrolled build for #142040
Rollup merge of #142040 - jswrenn:transmute-ty-region-generic, r=compiler-errors transmutability: shift abstraction boundary Previously, `rustc_transmute`'s layout representations were genericized over `R`, a reference. Now, it's instead genericized over representations of type and region. This allows us to move reference transmutability logic from `rustc_trait_selection` to `rustc_transmutability` (and thus unit test it independently of the compiler), and — in a follow-up PR — will make it possible to support analyzing function pointer transmutability with minimal surgery. r? `@compiler-errors`
2 parents 1434630 + e9eae28 commit 09818c9

File tree

14 files changed

+385
-357
lines changed

14 files changed

+385
-357
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,32 +2558,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
25582558
rustc_transmute::Reason::SrcIsNotYetSupported => {
25592559
format!("analyzing the transmutability of `{src}` is not yet supported")
25602560
}
2561-
25622561
rustc_transmute::Reason::DstIsNotYetSupported => {
25632562
format!("analyzing the transmutability of `{dst}` is not yet supported")
25642563
}
2565-
25662564
rustc_transmute::Reason::DstIsBitIncompatible => {
25672565
format!(
25682566
"at least one value of `{src}` isn't a bit-valid value of `{dst}`"
25692567
)
25702568
}
2571-
25722569
rustc_transmute::Reason::DstUninhabited => {
25732570
format!("`{dst}` is uninhabited")
25742571
}
2575-
25762572
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
25772573
format!("`{dst}` may carry safety invariants")
25782574
}
25792575
rustc_transmute::Reason::DstIsTooBig => {
25802576
format!("the size of `{src}` is smaller than the size of `{dst}`")
25812577
}
2582-
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
2583-
let src_size = src.size;
2584-
let dst_size = dst.size;
2578+
rustc_transmute::Reason::DstRefIsTooBig {
2579+
src,
2580+
src_size,
2581+
dst,
2582+
dst_size,
2583+
} => {
25852584
format!(
2586-
"the referent size of `{src}` ({src_size} bytes) \
2585+
"the size of `{src}` ({src_size} bytes) \
25872586
is smaller than that of `{dst}` ({dst_size} bytes)"
25882587
)
25892588
}

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

Lines changed: 46 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99
1010
use std::ops::ControlFlow;
1111

12-
use rustc_ast::Mutability;
1312
use rustc_data_structures::stack::ensure_sufficient_stack;
1413
use rustc_hir::lang_items::LangItem;
1514
use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
1615
use rustc_infer::traits::ObligationCauseCode;
1716
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
18-
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast, elaborate};
17+
use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, Upcast, elaborate};
1918
use rustc_middle::{bug, span_bug};
2019
use rustc_span::def_id::DefId;
2120
use thin_vec::thin_vec;
@@ -286,99 +285,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
286285
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
287286
use rustc_transmute::{Answer, Assume, Condition};
288287

289-
/// Generate sub-obligations for reference-to-reference transmutations.
290-
fn reference_obligations<'tcx>(
291-
tcx: TyCtxt<'tcx>,
292-
obligation: &PolyTraitObligation<'tcx>,
293-
(src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
294-
(dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
295-
assume: Assume,
296-
) -> PredicateObligations<'tcx> {
297-
let make_transmute_obl = |src, dst| {
298-
let transmute_trait = obligation.predicate.def_id();
299-
let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2);
300-
let trait_ref = ty::TraitRef::new(
301-
tcx,
302-
transmute_trait,
303-
[
304-
ty::GenericArg::from(dst),
305-
ty::GenericArg::from(src),
306-
ty::GenericArg::from(assume),
307-
],
308-
);
309-
Obligation::with_depth(
310-
tcx,
311-
obligation.cause.clone(),
312-
obligation.recursion_depth + 1,
313-
obligation.param_env,
314-
trait_ref,
315-
)
316-
};
317-
318-
let make_freeze_obl = |ty| {
319-
let trait_ref = ty::TraitRef::new(
320-
tcx,
321-
tcx.require_lang_item(LangItem::Freeze, obligation.cause.span),
322-
[ty::GenericArg::from(ty)],
323-
);
324-
Obligation::with_depth(
325-
tcx,
326-
obligation.cause.clone(),
327-
obligation.recursion_depth + 1,
328-
obligation.param_env,
329-
trait_ref,
330-
)
331-
};
332-
333-
let make_outlives_obl = |target, region| {
334-
let outlives = ty::OutlivesPredicate(target, region);
335-
Obligation::with_depth(
336-
tcx,
337-
obligation.cause.clone(),
338-
obligation.recursion_depth + 1,
339-
obligation.param_env,
340-
outlives,
341-
)
342-
};
343-
344-
// Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`,
345-
// it is always the case that `Src` must be transmutable into `Dst`,
346-
// and that that `'src` must outlive `'dst`.
347-
let mut obls = PredicateObligations::with_capacity(1);
348-
obls.push(make_transmute_obl(src_ty, dst_ty));
349-
if !assume.lifetimes {
350-
obls.push(make_outlives_obl(src_lifetime, dst_lifetime));
351-
}
352-
353-
// Given a transmutation from `&Src`, both `Src` and `Dst` must be
354-
// `Freeze`, otherwise, using the transmuted value could lead to
355-
// data races.
356-
if src_mut == Mutability::Not {
357-
obls.extend([make_freeze_obl(src_ty), make_freeze_obl(dst_ty)])
358-
}
359-
360-
// Given a transmutation into `&'dst mut Dst`, it also must be the
361-
// case that `Dst` is transmutable into `Src`. For example,
362-
// transmuting bool -> u8 is OK as long as you can't update that u8
363-
// to be > 1, because you could later transmute the u8 back to a
364-
// bool and get undefined behavior. It also must be the case that
365-
// `'dst` lives exactly as long as `'src`.
366-
if dst_mut == Mutability::Mut {
367-
obls.push(make_transmute_obl(dst_ty, src_ty));
368-
if !assume.lifetimes {
369-
obls.push(make_outlives_obl(dst_lifetime, src_lifetime));
370-
}
371-
}
372-
373-
obls
374-
}
375-
376288
/// Flatten the `Condition` tree into a conjunction of obligations.
377289
#[instrument(level = "debug", skip(tcx, obligation))]
378290
fn flatten_answer_tree<'tcx>(
379291
tcx: TyCtxt<'tcx>,
380292
obligation: &PolyTraitObligation<'tcx>,
381-
cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>,
293+
cond: Condition<Region<'tcx>, Ty<'tcx>>,
382294
assume: Assume,
383295
) -> PredicateObligations<'tcx> {
384296
match cond {
@@ -388,13 +300,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
388300
.into_iter()
389301
.flat_map(|cond| flatten_answer_tree(tcx, obligation, cond, assume))
390302
.collect(),
391-
Condition::IfTransmutable { src, dst } => reference_obligations(
392-
tcx,
393-
obligation,
394-
(src.lifetime, src.ty, src.mutability),
395-
(dst.lifetime, dst.ty, dst.mutability),
396-
assume,
397-
),
303+
Condition::Immutable { ty } => {
304+
let trait_ref = ty::TraitRef::new(
305+
tcx,
306+
tcx.require_lang_item(LangItem::Freeze, obligation.cause.span),
307+
[ty::GenericArg::from(ty)],
308+
);
309+
thin_vec![Obligation::with_depth(
310+
tcx,
311+
obligation.cause.clone(),
312+
obligation.recursion_depth + 1,
313+
obligation.param_env,
314+
trait_ref,
315+
)]
316+
}
317+
Condition::Outlives { long, short } => {
318+
let outlives = ty::OutlivesPredicate(long, short);
319+
thin_vec![Obligation::with_depth(
320+
tcx,
321+
obligation.cause.clone(),
322+
obligation.recursion_depth + 1,
323+
obligation.param_env,
324+
outlives,
325+
)]
326+
}
327+
Condition::Transmutable { src, dst } => {
328+
let transmute_trait = obligation.predicate.def_id();
329+
let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2);
330+
let trait_ref = ty::TraitRef::new(
331+
tcx,
332+
transmute_trait,
333+
[
334+
ty::GenericArg::from(dst),
335+
ty::GenericArg::from(src),
336+
ty::GenericArg::from(assume),
337+
],
338+
);
339+
thin_vec![Obligation::with_depth(
340+
tcx,
341+
obligation.cause.clone(),
342+
obligation.recursion_depth + 1,
343+
obligation.param_env,
344+
trait_ref,
345+
)]
346+
}
398347
}
399348
}
400349

compiler/rustc_transmute/src/layout/dfa.rs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,35 @@ use std::fmt;
22
use std::iter::Peekable;
33
use std::sync::atomic::{AtomicU32, Ordering};
44

5-
use super::{Byte, Ref, Tree, Uninhabited};
5+
use super::{Byte, Reference, Region, Tree, Type, Uninhabited};
66
use crate::{Map, Set};
77

88
#[derive(PartialEq)]
99
#[cfg_attr(test, derive(Clone))]
10-
pub(crate) struct Dfa<R>
10+
pub(crate) struct Dfa<R, T>
1111
where
12-
R: Ref,
12+
R: Region,
13+
T: Type,
1314
{
14-
pub(crate) transitions: Map<State, Transitions<R>>,
15+
pub(crate) transitions: Map<State, Transitions<R, T>>,
1516
pub(crate) start: State,
1617
pub(crate) accept: State,
1718
}
1819

1920
#[derive(PartialEq, Clone, Debug)]
20-
pub(crate) struct Transitions<R>
21+
pub(crate) struct Transitions<R, T>
2122
where
22-
R: Ref,
23+
R: Region,
24+
T: Type,
2325
{
2426
byte_transitions: EdgeSet<State>,
25-
ref_transitions: Map<R, State>,
27+
ref_transitions: Map<Reference<R, T>, State>,
2628
}
2729

28-
impl<R> Default for Transitions<R>
30+
impl<R, T> Default for Transitions<R, T>
2931
where
30-
R: Ref,
32+
R: Region,
33+
T: Type,
3134
{
3235
fn default() -> Self {
3336
Self { byte_transitions: EdgeSet::empty(), ref_transitions: Map::default() }
@@ -51,9 +54,10 @@ impl fmt::Debug for State {
5154
}
5255
}
5356

54-
impl<R> Dfa<R>
57+
impl<R, T> Dfa<R, T>
5558
where
56-
R: Ref,
59+
R: Region,
60+
T: Type,
5761
{
5862
#[cfg(test)]
5963
pub(crate) fn bool() -> Self {
@@ -64,7 +68,7 @@ where
6468
}
6569

6670
pub(crate) fn unit() -> Self {
67-
let transitions: Map<State, Transitions<R>> = Map::default();
71+
let transitions: Map<State, Transitions<R, T>> = Map::default();
6872
let start = State::new();
6973
let accept = start;
7074

@@ -78,21 +82,21 @@ where
7882
})
7983
}
8084

81-
pub(crate) fn from_ref(r: R) -> Self {
85+
pub(crate) fn from_ref(r: Reference<R, T>) -> Self {
8286
Self::from_transitions(|accept| Transitions {
8387
byte_transitions: EdgeSet::empty(),
8488
ref_transitions: [(r, accept)].into_iter().collect(),
8589
})
8690
}
8791

88-
fn from_transitions(f: impl FnOnce(State) -> Transitions<R>) -> Self {
92+
fn from_transitions(f: impl FnOnce(State) -> Transitions<R, T>) -> Self {
8993
let start = State::new();
9094
let accept = State::new();
9195

9296
Self { transitions: [(start, f(accept))].into_iter().collect(), start, accept }
9397
}
9498

95-
pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
99+
pub(crate) fn from_tree(tree: Tree<!, R, T>) -> Result<Self, Uninhabited> {
96100
Ok(match tree {
97101
Tree::Byte(b) => Self::from_byte(b),
98102
Tree::Ref(r) => Self::from_ref(r),
@@ -125,7 +129,7 @@ where
125129
let start = self.start;
126130
let accept = other.accept;
127131

128-
let mut transitions: Map<State, Transitions<R>> = self.transitions;
132+
let mut transitions: Map<State, Transitions<R, T>> = self.transitions;
129133

130134
for (source, transition) in other.transitions {
131135
let fix_state = |state| if state == other.start { self.accept } else { state };
@@ -169,7 +173,7 @@ where
169173
};
170174

171175
let start = mapped((Some(a.start), Some(b.start)));
172-
let mut transitions: Map<State, Transitions<R>> = Map::default();
176+
let mut transitions: Map<State, Transitions<R, T>> = Map::default();
173177
let empty_transitions = Transitions::default();
174178

175179
struct WorkQueue {
@@ -257,7 +261,7 @@ where
257261
.flat_map(|transitions| transitions.byte_transitions.iter())
258262
}
259263

260-
pub(crate) fn refs_from(&self, start: State) -> impl Iterator<Item = (R, State)> {
264+
pub(crate) fn refs_from(&self, start: State) -> impl Iterator<Item = (Reference<R, T>, State)> {
261265
self.transitions
262266
.get(&start)
263267
.into_iter()
@@ -297,9 +301,10 @@ where
297301
}
298302

299303
/// Serialize the DFA using the Graphviz DOT format.
300-
impl<R> fmt::Debug for Dfa<R>
304+
impl<R, T> fmt::Debug for Dfa<R, T>
301305
where
302-
R: Ref,
306+
R: Region,
307+
T: Type,
303308
{
304309
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305310
writeln!(f, "digraph {{")?;

0 commit comments

Comments
 (0)