Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit be92fb7

Browse files
committedJul 29, 2024
Auto merge of #128351 - ChayimFriedman2:lint-transmute-unsafe-cell, r=<try>
[crater] Lint against &T to &mut T and &T to &UnsafeCell<T> transmutes Needs a (check-only) crater run as per https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Lint.20against.20.60.26.60-.3E.60.26UnsafeCell.60.20transmutes/near/454868964. r? ghost
2 parents 612a33f + 59c22c3 commit be92fb7

35 files changed

+1105
-75
lines changed
 

‎compiler/rustc_lint/messages.ftl‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ lint_builtin_missing_doc = missing documentation for {$article} {$desc}
119119
120120
lint_builtin_mutable_transmutes =
121121
transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
122+
.note = transmute from `{$from}` to `{$to}`
122123
123124
lint_builtin_no_mangle_fn = declaration of a `no_mangle` function
124125
lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled
@@ -169,6 +170,10 @@ lint_builtin_unreachable_pub = unreachable `pub` {$what}
169170
170171
lint_builtin_unsafe_block = usage of an `unsafe` block
171172
173+
lint_builtin_unsafe_cell_transmutes =
174+
transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
175+
.note = transmute from `{$from}` to `{$to}`
176+
172177
lint_builtin_unsafe_extern_block = usage of an `unsafe extern` block
173178
174179
lint_builtin_unsafe_impl = implementation of an `unsafe` trait
@@ -862,6 +867,11 @@ lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
862867
.label = usage of unsafe attribute
863868
lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
864869
870+
lint_unsafe_cell_reference_casting =
871+
casting `&T` to `&UnsafeCell<T>` is undefined behavior, even if the reference is unused, consider using an `UnsafeCell` on the original data
872+
.label = casting happend here
873+
.note = cast from `{$from}` to `{$to}`
874+
865875
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
866876
867877
lint_untranslatable_diag = diagnostics should be created using translatable messages

‎compiler/rustc_lint/src/builtin.rs‎

Lines changed: 5 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,11 @@ use crate::lints::{
6161
BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
6262
BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
6363
BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
64-
BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes,
65-
BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed,
66-
BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller,
67-
BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub,
68-
BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
69-
BuiltinWhileTrue, InvalidAsmLabel,
64+
BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinNoMangleGeneric,
65+
BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds,
66+
BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
67+
BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures,
68+
BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
7069
};
7170
use crate::nonstandard_style::{method_context, MethodLateContext};
7271
use crate::{
@@ -1100,72 +1099,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
11001099
}
11011100
}
11021101

1103-
declare_lint! {
1104-
/// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
1105-
/// T` because it is [undefined behavior].
1106-
///
1107-
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1108-
///
1109-
/// ### Example
1110-
///
1111-
/// ```rust,compile_fail
1112-
/// unsafe {
1113-
/// let y = std::mem::transmute::<&i32, &mut i32>(&5);
1114-
/// }
1115-
/// ```
1116-
///
1117-
/// {{produces}}
1118-
///
1119-
/// ### Explanation
1120-
///
1121-
/// Certain assumptions are made about aliasing of data, and this transmute
1122-
/// violates those assumptions. Consider using [`UnsafeCell`] instead.
1123-
///
1124-
/// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
1125-
MUTABLE_TRANSMUTES,
1126-
Deny,
1127-
"transmuting &T to &mut T is undefined behavior, even if the reference is unused"
1128-
}
1129-
1130-
declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
1131-
1132-
impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
1133-
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
1134-
if let Some((&ty::Ref(_, _, from_mutbl), &ty::Ref(_, _, to_mutbl))) =
1135-
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
1136-
{
1137-
if from_mutbl < to_mutbl {
1138-
cx.emit_span_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes);
1139-
}
1140-
}
1141-
1142-
fn get_transmute_from_to<'tcx>(
1143-
cx: &LateContext<'tcx>,
1144-
expr: &hir::Expr<'_>,
1145-
) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
1146-
let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
1147-
cx.qpath_res(qpath, expr.hir_id)
1148-
} else {
1149-
return None;
1150-
};
1151-
if let Res::Def(DefKind::Fn, did) = def {
1152-
if !def_id_is_transmute(cx, did) {
1153-
return None;
1154-
}
1155-
let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
1156-
let from = sig.inputs().skip_binder()[0];
1157-
let to = sig.output().skip_binder();
1158-
return Some((from, to));
1159-
}
1160-
None
1161-
}
1162-
1163-
fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
1164-
cx.tcx.is_intrinsic(def_id, sym::transmute)
1165-
}
1166-
}
1167-
}
1168-
11691102
declare_lint! {
11701103
/// The `unstable_features` lint detects uses of `#![feature]`.
11711104
///
@@ -1612,7 +1545,6 @@ declare_lint_pass!(
16121545
UNUSED_DOC_COMMENTS,
16131546
NO_MANGLE_CONST_ITEMS,
16141547
NO_MANGLE_GENERIC_ITEMS,
1615-
MUTABLE_TRANSMUTES,
16161548
UNSTABLE_FEATURES,
16171549
UNREACHABLE_PUB,
16181550
TYPE_ALIAS_BOUNDS,

‎compiler/rustc_lint/src/lib.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ mod macro_expr_fragment_specifier_2024_migration;
6565
mod map_unit_fn;
6666
mod methods;
6767
mod multiple_supertrait_upcastable;
68+
mod mutable_transmutes;
6869
mod non_ascii_idents;
6970
mod non_fmt_panic;
7071
mod non_local_def;
@@ -99,6 +100,7 @@ use macro_expr_fragment_specifier_2024_migration::*;
99100
use map_unit_fn::*;
100101
use methods::*;
101102
use multiple_supertrait_upcastable::*;
103+
use mutable_transmutes::*;
102104
use non_ascii_idents::*;
103105
use non_fmt_panic::NonPanicFmt;
104106
use non_local_def::*;
@@ -209,6 +211,7 @@ late_lint_methods!(
209211
// Depends on referenced function signatures in expressions
210212
PtrNullChecks: PtrNullChecks,
211213
MutableTransmutes: MutableTransmutes,
214+
UnsafeCellReferenceCasting: UnsafeCellReferenceCasting,
212215
TypeAliasBounds: TypeAliasBounds,
213216
TrivialConstraints: TrivialConstraints,
214217
TypeLimits: TypeLimits::new(),

‎compiler/rustc_lint/src/lints.rs‎

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,34 @@ pub struct BuiltinConstNoMangle {
224224
pub suggestion: Span,
225225
}
226226

227+
// mutable_transmutes.rs
227228
#[derive(LintDiagnostic)]
228229
#[diag(lint_builtin_mutable_transmutes)]
229-
pub struct BuiltinMutablesTransmutes;
230+
#[note]
231+
pub struct BuiltinMutablesTransmutes {
232+
pub from: String,
233+
pub to: String,
234+
}
235+
236+
// mutable_transmutes.rs
237+
#[derive(LintDiagnostic)]
238+
#[diag(lint_builtin_unsafe_cell_transmutes)]
239+
#[note]
240+
pub struct BuiltinUnsafeCellTransmutes {
241+
pub from: String,
242+
pub to: String,
243+
}
244+
245+
// mutable_transmutes.rs
246+
#[derive(LintDiagnostic)]
247+
#[diag(lint_unsafe_cell_reference_casting)]
248+
#[note]
249+
pub struct UnsafeCellReferenceCastingDiag {
250+
#[label]
251+
pub orig_cast: Option<Span>,
252+
pub from: String,
253+
pub to: String,
254+
}
230255

231256
#[derive(LintDiagnostic)]
232257
#[diag(lint_builtin_unstable_features)]

‎compiler/rustc_lint/src/mutable_transmutes.rs‎

Lines changed: 715 additions & 0 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Should not rely on the aliasing model for its failure.
22
//@compile-flags: -Zmiri-disable-stacked-borrows
3+
#![allow(unsafe_cell_reference_casting)]
34

45
use std::sync::atomic::{AtomicI32, Ordering};
56

‎src/tools/miri/tests/fail/concurrency/read_only_atomic_load_acquire.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Should not rely on the aliasing model for its failure.
22
//@compile-flags: -Zmiri-disable-stacked-borrows
3+
#![allow(unsafe_cell_reference_casting)]
34

45
use std::sync::atomic::{AtomicI32, Ordering};
56

‎src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//@compile-flags: -Zmiri-disable-stacked-borrows
33
// Needs atomic accesses larger than the pointer size
44
//@ignore-64bit
5+
#![allow(unsafe_cell_reference_casting)]
56

67
use std::sync::atomic::{AtomicI64, Ordering};
78

‎src/tools/miri/tests/pass/atomic-readonly-load.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Stacked Borrows doesn't like this.
22
//@compile-flags: -Zmiri-tree-borrows
3+
#![allow(unsafe_cell_reference_casting)]
34

45
use std::sync::atomic::*;
56

‎src/tools/miri/tests/pass/tree_borrows/transmute-unsafecell.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//@compile-flags: -Zmiri-tree-borrows
2+
#![allow(unsafe_cell_transmutes)]
23

34
//! Testing `mem::transmute` between types with and without interior mutability.
45
//! All transmutations should work, as long as we don't do any actual accesses

‎tests/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ warning: transmuting &T to &mut T is undefined behavior, even if the reference i
44
LL | let y = std::mem::transmute::<&i32, &mut i32>(&5);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7+
= note: transmute from `&i32` to `&mut i32`
78
= note: requested on the command line with `--force-warn mutable-transmutes`
89

910
warning: 1 warning emitted

‎tests/ui/lint/force-warn/allowed-deny-by-default-lint.stderr‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ warning: transmuting &T to &mut T is undefined behavior, even if the reference i
44
LL | let y = std::mem::transmute::<&i32, &mut i32>(&5);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7+
= note: transmute from `&i32` to `&mut i32`
78
= note: requested on the command line with `--force-warn mutable-transmutes`
89

910
warning: 1 warning emitted

‎tests/ui/lint/force-warn/deny-by-default-lint.stderr‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ warning: transmuting &T to &mut T is undefined behavior, even if the reference i
44
LL | let y = std::mem::transmute::<&i32, &mut i32>(&5);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7+
= note: transmute from `&i32` to `&mut i32`
78
= note: requested on the command line with `--force-warn mutable-transmutes`
89

910
warning: 1 warning emitted
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//@ check-pass
2+
3+
use std::mem::transmute;
4+
5+
fn main() {
6+
let _a: &mut u8 = unsafe { transmute(&mut 0u8) };
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ check-pass
2+
3+
use std::cell::UnsafeCell;
4+
use std::mem::transmute;
5+
6+
fn main() {
7+
let _a: &mut UnsafeCell<u8> = unsafe { transmute(&mut 0u8) };
8+
let _a: &UnsafeCell<u8> = unsafe { transmute(&mut 0u8) };
9+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ check-pass
2+
3+
use std::cell::UnsafeCell;
4+
use std::mem::transmute;
5+
6+
#[repr(C)]
7+
struct A {
8+
a: u32,
9+
b: UnsafeCell<u32>,
10+
}
11+
12+
#[repr(C)]
13+
struct B {
14+
a: u32,
15+
b: UnsafeCell<u32>,
16+
}
17+
18+
#[repr(transparent)]
19+
struct AWrapper(A);
20+
21+
fn main() {
22+
let _a: &UnsafeCell<u8> = unsafe { transmute(&UnsafeCell::new(0u8)) };
23+
let _a: &B = unsafe { transmute(&A { a: 0, b: UnsafeCell::new(0) }) };
24+
let _a: &AWrapper = unsafe { transmute(&A { a: 0, b: UnsafeCell::new(0) }) };
25+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use std::mem::transmute;
2+
3+
fn main() {
4+
let _a: [&mut u8; 2] = unsafe { transmute([&1u8; 2]) };
5+
//~^ ERROR transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
2+
--> $DIR/array.rs:4:37
3+
|
4+
LL | let _a: [&mut u8; 2] = unsafe { transmute([&1u8; 2]) };
5+
| ^^^^^^^^^
6+
|
7+
= note: transmute from `[&u8; 2][0]` to `[&mut u8; 2][0]`
8+
= note: `#[deny(mutable_transmutes)]` on by default
9+
10+
error: aborting due to 1 previous error
11+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use std::cell::UnsafeCell;
2+
use std::mem::transmute;
3+
4+
#[repr(transparent)]
5+
struct A {
6+
a: B,
7+
}
8+
#[repr(transparent)]
9+
struct B {
10+
b: C,
11+
}
12+
#[repr(transparent)]
13+
struct C {
14+
c: &'static D,
15+
}
16+
#[repr(transparent)]
17+
struct D {
18+
d: UnsafeCell<u8>,
19+
}
20+
21+
#[repr(transparent)]
22+
struct E {
23+
e: F,
24+
}
25+
#[repr(transparent)]
26+
struct F {
27+
f: &'static G,
28+
}
29+
#[repr(transparent)]
30+
struct G {
31+
g: H,
32+
}
33+
#[repr(transparent)]
34+
struct H {
35+
h: u8,
36+
}
37+
38+
fn main() {
39+
let _: A = unsafe { transmute(&1u8) };
40+
//~^ ERROR transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
41+
let _: A = unsafe { transmute(E { e: F { f: &G { g: H { h: 0 } } } }) };
42+
//~^ ERROR transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
43+
let _: &'static UnsafeCell<u8> = unsafe { transmute(E { e: F { f: &G { g: H { h: 0 } } } }) };
44+
//~^ ERROR transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
45+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
2+
--> $DIR/diag_includes_field_names.rs:39:25
3+
|
4+
LL | let _: A = unsafe { transmute(&1u8) };
5+
| ^^^^^^^^^
6+
|
7+
= note: transmute from `*&u8` to `(*A.a.b.c).d`
8+
= note: `#[deny(unsafe_cell_transmutes)]` on by default
9+
10+
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
11+
--> $DIR/diag_includes_field_names.rs:41:25
12+
|
13+
LL | let _: A = unsafe { transmute(E { e: F { f: &G { g: H { h: 0 } } } }) };
14+
| ^^^^^^^^^
15+
|
16+
= note: transmute from `(*E.e.f).g.h` to `(*A.a.b.c).d`
17+
18+
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
19+
--> $DIR/diag_includes_field_names.rs:43:47
20+
|
21+
LL | let _: &'static UnsafeCell<u8> = unsafe { transmute(E { e: F { f: &G { g: H { h: 0 } } } }) };
22+
| ^^^^^^^^^
23+
|
24+
= note: transmute from `(*E.e.f).g.h` to `*&UnsafeCell<u8>`
25+
26+
error: aborting due to 3 previous errors
27+
File renamed without changes.

‎tests/ui/transmute/transmute-imut-to-mut.stderr‎ renamed to ‎tests/ui/lint/mutable_transmutes/imm_to_mut.stderr‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
2-
--> $DIR/transmute-imut-to-mut.rs:6:32
2+
--> $DIR/imm_to_mut.rs:6:32
33
|
44
LL | let _a: &mut u8 = unsafe { transmute(&1u8) };
55
| ^^^^^^^^^
66
|
7+
= note: transmute from `&u8` to `&mut u8`
78
= note: `#[deny(mutable_transmutes)]` on by default
89

910
error: aborting due to 1 previous error
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use std::cell::UnsafeCell;
2+
use std::mem::transmute;
3+
4+
fn main() {
5+
let _a: &UnsafeCell<u8> = unsafe { transmute(&1u8) };
6+
//~^ ERROR transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
2+
--> $DIR/imm_to_unsafecelll.rs:5:40
3+
|
4+
LL | let _a: &UnsafeCell<u8> = unsafe { transmute(&1u8) };
5+
| ^^^^^^^^^
6+
|
7+
= note: transmute from `*&u8` to `*&UnsafeCell<u8>`
8+
= note: `#[deny(unsafe_cell_transmutes)]` on by default
9+
10+
error: aborting due to 1 previous error
11+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std::cell::UnsafeCell;
2+
use std::mem::transmute;
3+
4+
#[repr(C)]
5+
struct Foo<T> {
6+
a: u32,
7+
b: Bar<T>,
8+
}
9+
#[repr(C)]
10+
struct Bar<T>(Baz<T>);
11+
#[repr(C)]
12+
struct Baz<T>(T);
13+
14+
#[repr(C)]
15+
struct Other(&'static u8, &'static u8);
16+
17+
fn main() {
18+
let _: Foo<&'static mut u8> = unsafe { transmute(Other(&1u8, &1u8)) };
19+
//~^ ERROR transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
20+
let _: Foo<&'static UnsafeCell<u8>> = unsafe { transmute(Other(&1u8, &1u8)) };
21+
//~^ ERROR transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
22+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
2+
--> $DIR/nested_field.rs:18:44
3+
|
4+
LL | let _: Foo<&'static mut u8> = unsafe { transmute(Other(&1u8, &1u8)) };
5+
| ^^^^^^^^^
6+
|
7+
= note: transmute from `Other.1` to `Foo<&mut u8>.b.0.0`
8+
= note: `#[deny(mutable_transmutes)]` on by default
9+
10+
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
11+
--> $DIR/nested_field.rs:20:52
12+
|
13+
LL | let _: Foo<&'static UnsafeCell<u8>> = unsafe { transmute(Other(&1u8, &1u8)) };
14+
| ^^^^^^^^^
15+
|
16+
= note: transmute from `*Other.1` to `*Foo<&UnsafeCell<u8>>.b.0.0`
17+
= note: `#[deny(unsafe_cell_transmutes)]` on by default
18+
19+
error: aborting due to 2 previous errors
20+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ check-pass
2+
//@ compile-flags: -Zrandomize-layout -Zlayout-seed=2464363
3+
4+
use std::cell::UnsafeCell;
5+
6+
#[derive(Default)]
7+
struct A {
8+
a: u32,
9+
b: u32,
10+
c: u32,
11+
d: u32,
12+
e: UnsafeCell<u32>,
13+
f: UnsafeCell<u32>,
14+
g: UnsafeCell<u32>,
15+
h: UnsafeCell<u32>,
16+
}
17+
18+
#[repr(transparent)]
19+
struct B(A);
20+
21+
fn main() {
22+
let _b: &B = unsafe { std::mem::transmute(&A::default()) };
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// This test checks that transmuting part of `&T` to part of `&mut T` errors.
2+
// I don't think this is necessary or common, but this is what the current code does.
3+
4+
use std::cell::UnsafeCell;
5+
use std::mem::transmute;
6+
7+
#[repr(C, packed)]
8+
struct Foo<T>(u8, T);
9+
10+
#[repr(C, packed)]
11+
struct Bar(&'static u8, u8);
12+
13+
fn main() {
14+
let _: Foo<&'static mut u8> = unsafe { transmute(Bar(&1u8, 0)) };
15+
//~^ ERROR transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
16+
let _: Foo<&'static UnsafeCell<u8>> = unsafe { transmute(Bar(&1u8, 0)) };
17+
//~^ ERROR transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
2+
--> $DIR/partially_overlapping.rs:14:44
3+
|
4+
LL | let _: Foo<&'static mut u8> = unsafe { transmute(Bar(&1u8, 0)) };
5+
| ^^^^^^^^^
6+
|
7+
= note: transmute from `Bar.0` to `Foo<&mut u8>.1`
8+
= note: `#[deny(mutable_transmutes)]` on by default
9+
10+
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
11+
--> $DIR/partially_overlapping.rs:16:52
12+
|
13+
LL | let _: Foo<&'static UnsafeCell<u8>> = unsafe { transmute(Bar(&1u8, 0)) };
14+
| ^^^^^^^^^
15+
|
16+
= note: transmute from `*Bar.0` to `*Foo<&UnsafeCell<u8>>.1`
17+
= note: `#[deny(unsafe_cell_transmutes)]` on by default
18+
19+
error: aborting due to 2 previous errors
20+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use std::cell::UnsafeCell;
2+
use std::mem::transmute;
3+
4+
#[repr(C)]
5+
struct Foo(&'static u8, &'static u8);
6+
#[repr(C)]
7+
struct Bar(&'static UnsafeCell<u8>, &'static mut u8);
8+
9+
fn main() {
10+
let _a: Bar = unsafe { transmute(Foo(&0, &0)) };
11+
//~^ ERROR transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
2+
--> $DIR/report_only_first_error.rs:10:28
3+
|
4+
LL | let _a: Bar = unsafe { transmute(Foo(&0, &0)) };
5+
| ^^^^^^^^^
6+
|
7+
= note: transmute from `*Foo.0` to `*Bar.0`
8+
= note: `#[deny(unsafe_cell_transmutes)]` on by default
9+
10+
error: aborting due to 1 previous error
11+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use std::cell::UnsafeCell;
2+
3+
#[repr(C)]
4+
struct A {
5+
a: u64,
6+
b: u32,
7+
c: u32,
8+
}
9+
10+
#[repr(C)]
11+
struct B {
12+
a: u64,
13+
b: UnsafeCell<u32>,
14+
c: u32,
15+
}
16+
17+
fn main() {
18+
let a = A { a: 0, b: 0, c: 0 };
19+
let _b = unsafe { &*(&a as *const A as *const B) };
20+
//~^ ERROR casting `&T` to `&UnsafeCell<T>` is undefined behavior, even if the reference is unused, consider using an `UnsafeCell` on the original data
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: casting `&T` to `&UnsafeCell<T>` is undefined behavior, even if the reference is unused, consider using an `UnsafeCell` on the original data
2+
--> $DIR/unsafe_cell_reference_casting.rs:19:23
3+
|
4+
LL | let _b = unsafe { &*(&a as *const A as *const B) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: cast from `A.b` to `B.b`
8+
= note: `#[deny(unsafe_cell_reference_casting)]` on by default
9+
10+
error: aborting due to 1 previous error
11+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use std::cell::UnsafeCell;
2+
3+
#[repr(C)]
4+
struct A<T: ?Sized> {
5+
a: u32,
6+
b: T,
7+
}
8+
9+
#[repr(C)]
10+
struct B {
11+
a: UnsafeCell<u32>,
12+
b: [u32],
13+
}
14+
15+
fn main() {
16+
let a = &A { a: 0, b: [0_u32, 0] } as &A<[u32]>;
17+
let _b = unsafe { &*(a as *const A<[u32]> as *const B) };
18+
//~^ ERROR casting `&T` to `&UnsafeCell<T>` is undefined behavior, even if the reference is unused, consider using an `UnsafeCell` on the original data
19+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: casting `&T` to `&UnsafeCell<T>` is undefined behavior, even if the reference is unused, consider using an `UnsafeCell` on the original data
2+
--> $DIR/unsized.rs:17:23
3+
|
4+
LL | let _b = unsafe { &*(a as *const A<[u32]> as *const B) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: cast from `A<[u32]>.a` to `B.a`
8+
= note: `#[deny(unsafe_cell_reference_casting)]` on by default
9+
10+
error: aborting due to 1 previous error
11+

0 commit comments

Comments
 (0)
Please sign in to comment.