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`
This commit is contained in:
parent
6266358237
commit
d2164d5c9a
5 changed files with 39 additions and 33 deletions
|
@ -2751,8 +2751,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
|
||||
span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
|
||||
};
|
||||
// FIXME(bryangarza): Is this enough, or should we resolve all nested
|
||||
// obligations like we do for `confirm_transmutability_candidate(...)?`
|
||||
|
||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||
obligation.cause,
|
||||
src_and_dst,
|
||||
|
@ -2784,10 +2783,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
rustc_transmute::Reason::DstIsTooBig => {
|
||||
format!("The size of `{src}` is smaller than the size of `{dst}`")
|
||||
}
|
||||
// FIXME(bryangarza): Say exactly what the minimum alignments of src and dst are
|
||||
rustc_transmute::Reason::DstHasStricterAlignment => {
|
||||
rustc_transmute::Reason::DstHasStricterAlignment {
|
||||
src_min_align,
|
||||
dst_min_align,
|
||||
} => {
|
||||
format!(
|
||||
"The minimum alignment of `{src}` should be greater than that of `{dst}`, but it is not"
|
||||
"The minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstIsMoreUnique => {
|
||||
|
|
|
@ -290,25 +290,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
predicate: TraitPredicate<'tcx>,
|
||||
answer: rustc_transmute::Answer<rustc_transmute::layout::rustc::Ref<'tcx>>,
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
answer: rustc_transmute::Condition<rustc_transmute::layout::rustc::Ref<'tcx>>,
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
match answer {
|
||||
Ok(None) => Ok(vec![]),
|
||||
Err(_) => Err(Unimplemented),
|
||||
// FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll`
|
||||
// Not possible until the trait solver supports disjunctions of obligations
|
||||
Ok(Some(rustc_transmute::Condition::IfAll(answers)))
|
||||
| Ok(Some(rustc_transmute::Condition::IfAny(answers))) => {
|
||||
rustc_transmute::Condition::IfAll(answers)
|
||||
| rustc_transmute::Condition::IfAny(answers) => {
|
||||
let mut nested = vec![];
|
||||
for flattened in answers
|
||||
.into_iter()
|
||||
.map(|answer| flatten_answer_tree(tcx, obligation, predicate, answer))
|
||||
{
|
||||
nested.extend(flattened?);
|
||||
nested.extend(flattened);
|
||||
}
|
||||
Ok(nested)
|
||||
nested
|
||||
}
|
||||
Ok(Some(rustc_transmute::Condition::IfTransmutable { src, dst })) => {
|
||||
rustc_transmute::Condition::IfTransmutable { src, dst } => {
|
||||
let trait_def_id = obligation.predicate.def_id();
|
||||
let scope = predicate.trait_ref.substs.type_at(2);
|
||||
let assume_const = predicate.trait_ref.substs.const_at(3);
|
||||
|
@ -339,7 +337,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
if dst.mutability == Mutability::Mut {
|
||||
obligations.push(make_obl(dst.ty, src.ty));
|
||||
}
|
||||
Ok(obligations)
|
||||
obligations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -371,8 +369,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
assume,
|
||||
);
|
||||
|
||||
let fully_flattened =
|
||||
flatten_answer_tree(self.tcx(), obligation, predicate, maybe_transmutable)?;
|
||||
let fully_flattened = match maybe_transmutable {
|
||||
Err(_) => Err(Unimplemented)?,
|
||||
Ok(Some(mt)) => flatten_answer_tree(self.tcx(), obligation, predicate, mt),
|
||||
Ok(None) => vec![],
|
||||
};
|
||||
|
||||
debug!(?fully_flattened);
|
||||
Ok(ImplSourceBuiltinData { nested: fully_flattened })
|
||||
}
|
||||
|
|
|
@ -29,10 +29,10 @@ pub enum Condition<R> {
|
|||
IfTransmutable { src: R, dst: R },
|
||||
|
||||
/// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
|
||||
IfAll(Vec<Answer<R>>),
|
||||
IfAll(Vec<Condition<R>>),
|
||||
|
||||
/// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
|
||||
IfAny(Vec<Answer<R>>),
|
||||
IfAny(Vec<Condition<R>>),
|
||||
}
|
||||
|
||||
/// Answers: Why wasn't the source type transmutable into the destination type?
|
||||
|
@ -49,7 +49,7 @@ pub enum Reason {
|
|||
/// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
|
||||
DstIsTooBig,
|
||||
/// Src should have a stricter alignment than Dst, but it does not.
|
||||
DstHasStricterAlignment,
|
||||
DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
|
||||
/// Can't go from shared pointer to unique pointer
|
||||
DstIsMoreUnique,
|
||||
}
|
||||
|
|
|
@ -303,7 +303,10 @@ where
|
|||
} else if !self.assume.alignment
|
||||
&& src_ref.min_align() < dst_ref.min_align()
|
||||
{
|
||||
Err(Reason::DstHasStricterAlignment)
|
||||
Err(Reason::DstHasStricterAlignment {
|
||||
src_min_align: src_ref.min_align(),
|
||||
dst_min_align: dst_ref.min_align(),
|
||||
})
|
||||
} else {
|
||||
// ...such that `src` is transmutable into `dst`, if
|
||||
// `src_ref` is transmutability into `dst_ref`.
|
||||
|
@ -360,13 +363,13 @@ where
|
|||
Some(Condition::IfAll(lhs))
|
||||
}
|
||||
// If only one side is an IfAll, add the other Condition to it
|
||||
(constraint, Some(Condition::IfAll(mut constraints)))
|
||||
| (Some(Condition::IfAll(mut constraints)), constraint) => {
|
||||
constraints.push(Ok(constraint));
|
||||
Some(Condition::IfAll(constraints))
|
||||
(Some(cond), Some(Condition::IfAll(mut conds)))
|
||||
| (Some(Condition::IfAll(mut conds)), Some(cond)) => {
|
||||
conds.push(cond);
|
||||
Some(Condition::IfAll(conds))
|
||||
}
|
||||
// Otherwise, both lhs and rhs conditions can be combined in a parent IfAll
|
||||
(lhs, rhs) => Some(Condition::IfAll(vec![Ok(lhs), Ok(rhs)])),
|
||||
(Some(lhs), Some(rhs)) => Some(Condition::IfAll(vec![lhs, rhs])),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -394,13 +397,13 @@ where
|
|||
Some(Condition::IfAny(lhs))
|
||||
}
|
||||
// If only one side is an IfAny, add the other Condition to it
|
||||
(constraint, Some(Condition::IfAny(mut constraints)))
|
||||
| (Some(Condition::IfAny(mut constraints)), constraint) => {
|
||||
constraints.push(Ok(constraint));
|
||||
Some(Condition::IfAny(constraints))
|
||||
(Some(cond), Some(Condition::IfAny(mut conds)))
|
||||
| (Some(Condition::IfAny(mut conds)), Some(cond)) => {
|
||||
conds.push(cond);
|
||||
Some(Condition::IfAny(conds))
|
||||
}
|
||||
// Otherwise, both lhs and rhs conditions can be combined in a parent IfAny
|
||||
(lhs, rhs) => Some(Condition::IfAny(vec![Ok(lhs), Ok(rhs)])),
|
||||
(Some(lhs), Some(rhs)) => Some(Condition::IfAny(vec![lhs, rhs])),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: `&[u8; 0]` cannot be safely transmuted into `&[u16; 0]` in the defining scope of `assert::Context`
|
||||
--> $DIR/align-fail.rs:22:55
|
||||
|
|
||||
LL | ...c [u8; 0], &'static [u16; 0]>();
|
||||
| ^^^^^^^^^^^^^^^^^ The minimum alignment of `&[u8; 0]` should be greater than that of `&[u16; 0]`, but it is not
|
||||
LL | ...tatic [u8; 0], &'static [u16; 0]>();
|
||||
| ^^^^^^^^^^^^^^^^^ The minimum alignment of `&[u8; 0]` (1) should be greater than that of `&[u16; 0]` (2)
|
||||
|
|
||||
note: required by a bound in `is_maybe_transmutable`
|
||||
--> $DIR/align-fail.rs:10:14
|
||||
|
|
Loading…
Add table
Reference in a new issue