Skip to content

Commit 03f1e90

Browse files
authored
Unrolled build for rust-lang#121681
Rollup merge of rust-lang#121681 - jswrenn:nix-visibility-analysis, r=compiler-errors Safe Transmute: Revise safety analysis This PR migrates `BikeshedIntrinsicFrom` to a simplified safety analysis (described [here](rust-lang/project-safe-transmute#15)) that does not rely on analyzing the visibility of types and fields. The revised analysis treats primitive types as safe, and user-defined types as potentially carrying safety invariants. If Rust gains explicit (un)safe fields, this PR is structured so that it will be fairly easy to thread support for those annotations into the analysis. Notably, this PR removes the `Context` type parameter from `BikeshedIntrinsicFrom`. Most of the files changed by this PR are just UI tests tweaked to accommodate the removed parameter. r? `@compiler-errors`
2 parents 878c8a2 + 23ab1bd commit 03f1e90

File tree

127 files changed

+1379
-1940
lines changed

Some content is hidden

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

127 files changed

+1379
-1940
lines changed

compiler/rustc_hir/src/lang_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ language_item_table! {
167167

168168
// language items relating to transmutability
169169
TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0);
170-
TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3);
170+
TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(2);
171171

172172
Add, sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
173173
Sub, sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);

compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -874,15 +874,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
874874
pub(super) fn is_transmutable(
875875
&self,
876876
src_and_dst: rustc_transmute::Types<'tcx>,
877-
scope: Ty<'tcx>,
878877
assume: rustc_transmute::Assume,
879878
) -> Result<Certainty, NoSolution> {
880879
use rustc_transmute::Answer;
881880
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
882881
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
883882
ObligationCause::dummy(),
884883
src_and_dst,
885-
scope,
886884
assume,
887885
) {
888886
Answer::Yes => Ok(Certainty::Yes),

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -549,14 +549,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
549549
let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args);
550550

551551
let Some(assume) =
552-
rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(3))
552+
rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(2))
553553
else {
554554
return Err(NoSolution);
555555
};
556556

557557
let certainty = ecx.is_transmutable(
558558
rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
559-
args.type_at(2),
560559
assume,
561560
)?;
562561
ecx.evaluate_added_goals_and_make_canonical_response(certainty)

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

+5-9
Original file line numberDiff line numberDiff line change
@@ -2960,11 +2960,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
29602960
dst: trait_ref.args.type_at(0),
29612961
src: trait_ref.args.type_at(1),
29622962
};
2963-
let scope = trait_ref.args.type_at(2);
29642963
let Some(assume) = rustc_transmute::Assume::from_const(
29652964
self.infcx.tcx,
29662965
obligation.param_env,
2967-
trait_ref.args.const_at(3),
2966+
trait_ref.args.const_at(2),
29682967
) else {
29692968
self.dcx().span_delayed_bug(
29702969
span,
@@ -2976,15 +2975,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
29762975
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
29772976
obligation.cause,
29782977
src_and_dst,
2979-
scope,
29802978
assume,
29812979
) {
29822980
Answer::No(reason) => {
29832981
let dst = trait_ref.args.type_at(0);
29842982
let src = trait_ref.args.type_at(1);
2985-
let err_msg = format!(
2986-
"`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
2987-
);
2983+
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
29882984
let safe_transmute_explanation = match reason {
29892985
rustc_transmute::Reason::SrcIsUnspecified => {
29902986
format!("`{src}` does not have a well-specified layout")
@@ -2998,9 +2994,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
29982994
format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`")
29992995
}
30002996

3001-
rustc_transmute::Reason::DstIsPrivate => format!(
3002-
"`{dst}` is or contains a type or field that is not visible in that scope"
3003-
),
2997+
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
2998+
format!("`{dst}` may carry safety invariants")
2999+
}
30043000
rustc_transmute::Reason::DstIsTooBig => {
30053001
format!("The size of `{src}` is smaller than the size of `{dst}`")
30063002
}

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

+2-5
Original file line numberDiff line numberDiff line change
@@ -310,16 +310,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
310310
.collect(),
311311
Condition::IfTransmutable { src, dst } => {
312312
let trait_def_id = obligation.predicate.def_id();
313-
let scope = predicate.trait_ref.args.type_at(2);
314-
let assume_const = predicate.trait_ref.args.const_at(3);
313+
let assume_const = predicate.trait_ref.args.const_at(2);
315314
let make_obl = |from_ty, to_ty| {
316315
let trait_ref1 = ty::TraitRef::new(
317316
tcx,
318317
trait_def_id,
319318
[
320319
ty::GenericArg::from(to_ty),
321320
ty::GenericArg::from(from_ty),
322-
ty::GenericArg::from(scope),
323321
ty::GenericArg::from(assume_const),
324322
],
325323
);
@@ -355,7 +353,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
355353
let Some(assume) = rustc_transmute::Assume::from_const(
356354
self.infcx.tcx,
357355
obligation.param_env,
358-
predicate.trait_ref.args.const_at(3),
356+
predicate.trait_ref.args.const_at(2),
359357
) else {
360358
return Err(Unimplemented);
361359
};
@@ -367,7 +365,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
367365
let maybe_transmutable = transmute_env.is_transmutable(
368366
obligation.cause.clone(),
369367
rustc_transmute::Types { dst, src },
370-
predicate.trait_ref.args.type_at(2),
371368
assume,
372369
);
373370

compiler/rustc_transmute/src/layout/mod.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,21 @@ impl fmt::Debug for Byte {
2929
}
3030
}
3131

32-
pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {}
32+
pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {
33+
fn has_safety_invariants(&self) -> bool;
34+
}
3335
pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {
3436
fn min_align(&self) -> usize;
3537

3638
fn is_mutable(&self) -> bool;
3739
}
3840

39-
impl Def for ! {}
41+
impl Def for ! {
42+
fn has_safety_invariants(&self) -> bool {
43+
unreachable!()
44+
}
45+
}
46+
4047
impl Ref for ! {
4148
fn min_align(&self) -> usize {
4249
unreachable!()
@@ -83,5 +90,12 @@ pub mod rustc {
8390
Primitive,
8491
}
8592

86-
impl<'tcx> super::Def for Def<'tcx> {}
93+
impl<'tcx> super::Def for Def<'tcx> {
94+
fn has_safety_invariants(&self) -> bool {
95+
// Rust presently has no notion of 'unsafe fields', so for now we
96+
// make the conservative assumption that everything besides
97+
// primitive types carry safety invariants.
98+
self != &Self::Primitive
99+
}
100+
}
87101
}

compiler/rustc_transmute/src/layout/tree.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ where
8181
Self::Seq(vec![Self::uninit(); width_in_bytes])
8282
}
8383

84-
/// Remove all `Def` nodes, and all branches of the layout for which `f` produces false.
84+
/// Remove all `Def` nodes, and all branches of the layout for which `f`
85+
/// produces `true`.
8586
pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
8687
where
8788
F: Fn(D) -> bool,
@@ -106,7 +107,7 @@ where
106107
Self::Byte(b) => Tree::Byte(b),
107108
Self::Ref(r) => Tree::Ref(r),
108109
Self::Def(d) => {
109-
if !f(d) {
110+
if f(d) {
110111
Tree::uninhabited()
111112
} else {
112113
Tree::unit()

compiler/rustc_transmute/src/layout/tree/tests.rs

+47-22
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ use super::Tree;
22

33
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
44
pub enum Def {
5-
Visible,
6-
Invisible,
5+
NoSafetyInvariants,
6+
HasSafetyInvariants,
77
}
88

9-
impl super::Def for Def {}
9+
impl super::Def for Def {
10+
fn has_safety_invariants(&self) -> bool {
11+
self == &Self::HasSafetyInvariants
12+
}
13+
}
1014

1115
mod prune {
1216
use super::*;
@@ -16,17 +20,22 @@ mod prune {
1620

1721
#[test]
1822
fn seq_1() {
19-
let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::from_bits(0x00));
20-
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
23+
let layout: Tree<Def, !> =
24+
Tree::def(Def::NoSafetyInvariants).then(Tree::from_bits(0x00));
25+
assert_eq!(
26+
layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
27+
Tree::from_bits(0x00)
28+
);
2129
}
2230

2331
#[test]
2432
fn seq_2() {
25-
let layout: Tree<Def, !> =
26-
Tree::from_bits(0x00).then(Tree::def(Def::Visible)).then(Tree::from_bits(0x01));
33+
let layout: Tree<Def, !> = Tree::from_bits(0x00)
34+
.then(Tree::def(Def::NoSafetyInvariants))
35+
.then(Tree::from_bits(0x01));
2736

2837
assert_eq!(
29-
layout.prune(&|d| matches!(d, Def::Visible)),
38+
layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
3039
Tree::from_bits(0x00).then(Tree::from_bits(0x01))
3140
);
3241
}
@@ -37,21 +46,32 @@ mod prune {
3746

3847
#[test]
3948
fn invisible_def() {
40-
let layout: Tree<Def, !> = Tree::def(Def::Invisible);
41-
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
49+
let layout: Tree<Def, !> = Tree::def(Def::HasSafetyInvariants);
50+
assert_eq!(
51+
layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
52+
Tree::uninhabited()
53+
);
4254
}
4355

4456
#[test]
4557
fn invisible_def_in_seq_len_2() {
46-
let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Invisible));
47-
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
58+
let layout: Tree<Def, !> =
59+
Tree::def(Def::NoSafetyInvariants).then(Tree::def(Def::HasSafetyInvariants));
60+
assert_eq!(
61+
layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
62+
Tree::uninhabited()
63+
);
4864
}
4965

5066
#[test]
5167
fn invisible_def_in_seq_len_3() {
52-
let layout: Tree<Def, !> =
53-
Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Invisible));
54-
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
68+
let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants)
69+
.then(Tree::from_bits(0x00))
70+
.then(Tree::def(Def::HasSafetyInvariants));
71+
assert_eq!(
72+
layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
73+
Tree::uninhabited()
74+
);
5575
}
5676
}
5777

@@ -60,21 +80,26 @@ mod prune {
6080

6181
#[test]
6282
fn visible_def() {
63-
let layout: Tree<Def, !> = Tree::def(Def::Visible);
64-
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
83+
let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants);
84+
assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::unit());
6585
}
6686

6787
#[test]
6888
fn visible_def_in_seq_len_2() {
69-
let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Visible));
70-
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
89+
let layout: Tree<Def, !> =
90+
Tree::def(Def::NoSafetyInvariants).then(Tree::def(Def::NoSafetyInvariants));
91+
assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::unit());
7192
}
7293

7394
#[test]
7495
fn visible_def_in_seq_len_3() {
75-
let layout: Tree<Def, !> =
76-
Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Visible));
77-
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
96+
let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants)
97+
.then(Tree::from_bits(0x00))
98+
.then(Tree::def(Def::NoSafetyInvariants));
99+
assert_eq!(
100+
layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
101+
Tree::from_bits(0x00)
102+
);
78103
}
79104
}
80105
}

compiler/rustc_transmute/src/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ pub enum Reason {
4949
DstIsUnspecified,
5050
/// The layout of the destination type is bit-incompatible with the source type.
5151
DstIsBitIncompatible,
52-
/// There aren't any public constructors for `Dst`.
53-
DstIsPrivate,
52+
/// The destination type may carry safety invariants.
53+
DstMayHaveSafetyInvariants,
5454
/// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
5555
DstIsTooBig,
5656
/// Src should have a stricter alignment than Dst, but it does not.
@@ -106,13 +106,11 @@ mod rustc {
106106
&mut self,
107107
cause: ObligationCause<'tcx>,
108108
types: Types<'tcx>,
109-
scope: Ty<'tcx>,
110109
assume: crate::Assume,
111110
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
112111
crate::maybe_transmutable::MaybeTransmutableQuery::new(
113112
types.src,
114113
types.dst,
115-
scope,
116114
assume,
117115
self.infcx.tcx,
118116
)

0 commit comments

Comments
 (0)