Skip to content

Commit d2164d5

Browse files
committed
Safe Transmute: Update definition of Condition type
- Change `Condition` to not contain `Answer`s but instead just contain other `Condition`s directly. - Also improve error reporting for `DstHasStricterAlignment`
1 parent 6266358 commit d2164d5

File tree

5 files changed

+39
-33
lines changed

5 files changed

+39
-33
lines changed

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -2751,8 +2751,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
27512751
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
27522752
span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
27532753
};
2754-
// FIXME(bryangarza): Is this enough, or should we resolve all nested
2755-
// obligations like we do for `confirm_transmutability_candidate(...)?`
2754+
27562755
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
27572756
obligation.cause,
27582757
src_and_dst,
@@ -2784,10 +2783,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
27842783
rustc_transmute::Reason::DstIsTooBig => {
27852784
format!("The size of `{src}` is smaller than the size of `{dst}`")
27862785
}
2787-
// FIXME(bryangarza): Say exactly what the minimum alignments of src and dst are
2788-
rustc_transmute::Reason::DstHasStricterAlignment => {
2786+
rustc_transmute::Reason::DstHasStricterAlignment {
2787+
src_min_align,
2788+
dst_min_align,
2789+
} => {
27892790
format!(
2790-
"The minimum alignment of `{src}` should be greater than that of `{dst}`, but it is not"
2791+
"The minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
27912792
)
27922793
}
27932794
rustc_transmute::Reason::DstIsMoreUnique => {

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

+14-12
Original file line numberDiff line numberDiff line change
@@ -290,25 +290,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
290290
tcx: TyCtxt<'tcx>,
291291
obligation: &TraitObligation<'tcx>,
292292
predicate: TraitPredicate<'tcx>,
293-
answer: rustc_transmute::Answer<rustc_transmute::layout::rustc::Ref<'tcx>>,
294-
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
293+
answer: rustc_transmute::Condition<rustc_transmute::layout::rustc::Ref<'tcx>>,
294+
) -> Vec<PredicateObligation<'tcx>> {
295295
match answer {
296-
Ok(None) => Ok(vec![]),
297-
Err(_) => Err(Unimplemented),
298296
// FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll`
299297
// Not possible until the trait solver supports disjunctions of obligations
300-
Ok(Some(rustc_transmute::Condition::IfAll(answers)))
301-
| Ok(Some(rustc_transmute::Condition::IfAny(answers))) => {
298+
rustc_transmute::Condition::IfAll(answers)
299+
| rustc_transmute::Condition::IfAny(answers) => {
302300
let mut nested = vec![];
303301
for flattened in answers
304302
.into_iter()
305303
.map(|answer| flatten_answer_tree(tcx, obligation, predicate, answer))
306304
{
307-
nested.extend(flattened?);
305+
nested.extend(flattened);
308306
}
309-
Ok(nested)
307+
nested
310308
}
311-
Ok(Some(rustc_transmute::Condition::IfTransmutable { src, dst })) => {
309+
rustc_transmute::Condition::IfTransmutable { src, dst } => {
312310
let trait_def_id = obligation.predicate.def_id();
313311
let scope = predicate.trait_ref.substs.type_at(2);
314312
let assume_const = predicate.trait_ref.substs.const_at(3);
@@ -339,7 +337,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
339337
if dst.mutability == Mutability::Mut {
340338
obligations.push(make_obl(dst.ty, src.ty));
341339
}
342-
Ok(obligations)
340+
obligations
343341
}
344342
}
345343
}
@@ -371,8 +369,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
371369
assume,
372370
);
373371

374-
let fully_flattened =
375-
flatten_answer_tree(self.tcx(), obligation, predicate, maybe_transmutable)?;
372+
let fully_flattened = match maybe_transmutable {
373+
Err(_) => Err(Unimplemented)?,
374+
Ok(Some(mt)) => flatten_answer_tree(self.tcx(), obligation, predicate, mt),
375+
Ok(None) => vec![],
376+
};
377+
376378
debug!(?fully_flattened);
377379
Ok(ImplSourceBuiltinData { nested: fully_flattened })
378380
}

compiler/rustc_transmute/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ pub enum Condition<R> {
2929
IfTransmutable { src: R, dst: R },
3030

3131
/// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
32-
IfAll(Vec<Answer<R>>),
32+
IfAll(Vec<Condition<R>>),
3333

3434
/// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
35-
IfAny(Vec<Answer<R>>),
35+
IfAny(Vec<Condition<R>>),
3636
}
3737

3838
/// Answers: Why wasn't the source type transmutable into the destination type?
@@ -49,7 +49,7 @@ pub enum Reason {
4949
/// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
5050
DstIsTooBig,
5151
/// Src should have a stricter alignment than Dst, but it does not.
52-
DstHasStricterAlignment,
52+
DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
5353
/// Can't go from shared pointer to unique pointer
5454
DstIsMoreUnique,
5555
}

compiler/rustc_transmute/src/maybe_transmutable/mod.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,10 @@ where
303303
} else if !self.assume.alignment
304304
&& src_ref.min_align() < dst_ref.min_align()
305305
{
306-
Err(Reason::DstHasStricterAlignment)
306+
Err(Reason::DstHasStricterAlignment {
307+
src_min_align: src_ref.min_align(),
308+
dst_min_align: dst_ref.min_align(),
309+
})
307310
} else {
308311
// ...such that `src` is transmutable into `dst`, if
309312
// `src_ref` is transmutability into `dst_ref`.
@@ -360,13 +363,13 @@ where
360363
Some(Condition::IfAll(lhs))
361364
}
362365
// If only one side is an IfAll, add the other Condition to it
363-
(constraint, Some(Condition::IfAll(mut constraints)))
364-
| (Some(Condition::IfAll(mut constraints)), constraint) => {
365-
constraints.push(Ok(constraint));
366-
Some(Condition::IfAll(constraints))
366+
(Some(cond), Some(Condition::IfAll(mut conds)))
367+
| (Some(Condition::IfAll(mut conds)), Some(cond)) => {
368+
conds.push(cond);
369+
Some(Condition::IfAll(conds))
367370
}
368371
// Otherwise, both lhs and rhs conditions can be combined in a parent IfAll
369-
(lhs, rhs) => Some(Condition::IfAll(vec![Ok(lhs), Ok(rhs)])),
372+
(Some(lhs), Some(rhs)) => Some(Condition::IfAll(vec![lhs, rhs])),
370373
})
371374
}
372375

@@ -394,13 +397,13 @@ where
394397
Some(Condition::IfAny(lhs))
395398
}
396399
// If only one side is an IfAny, add the other Condition to it
397-
(constraint, Some(Condition::IfAny(mut constraints)))
398-
| (Some(Condition::IfAny(mut constraints)), constraint) => {
399-
constraints.push(Ok(constraint));
400-
Some(Condition::IfAny(constraints))
400+
(Some(cond), Some(Condition::IfAny(mut conds)))
401+
| (Some(Condition::IfAny(mut conds)), Some(cond)) => {
402+
conds.push(cond);
403+
Some(Condition::IfAny(conds))
401404
}
402405
// Otherwise, both lhs and rhs conditions can be combined in a parent IfAny
403-
(lhs, rhs) => Some(Condition::IfAny(vec![Ok(lhs), Ok(rhs)])),
406+
(Some(lhs), Some(rhs)) => Some(Condition::IfAny(vec![lhs, rhs])),
404407
})
405408
}
406409

tests/ui/transmutability/alignment/align-fail.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: `&[u8; 0]` cannot be safely transmuted into `&[u16; 0]` in the defining scope of `assert::Context`
22
--> $DIR/align-fail.rs:22:55
33
|
4-
LL | ...c [u8; 0], &'static [u16; 0]>();
5-
| ^^^^^^^^^^^^^^^^^ The minimum alignment of `&[u8; 0]` should be greater than that of `&[u16; 0]`, but it is not
4+
LL | ...tatic [u8; 0], &'static [u16; 0]>();
5+
| ^^^^^^^^^^^^^^^^^ The minimum alignment of `&[u8; 0]` (1) should be greater than that of `&[u16; 0]` (2)
66
|
77
note: required by a bound in `is_maybe_transmutable`
88
--> $DIR/align-fail.rs:10:14

0 commit comments

Comments
 (0)