Skip to content

Commit fc23a81

Browse files
committed
Auto merge of #68491 - pnkfelix:hide-niches-under-unsafe-cell, r=oli
Hide niches under UnsafeCell Hide any niche of T from type-construction context of `UnsafeCell<T>`. Fix #68303 Fix #68206
2 parents 3f32e30 + 1b12232 commit fc23a81

File tree

17 files changed

+521
-24
lines changed

17 files changed

+521
-24
lines changed

Diff for: src/ci/docker/dist-various-2/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
4848
COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
4949
# We pass the commit id of the port of LLVM's libunwind to the build script.
5050
# Any update to the commit id here, should cause the container image to be re-built from this point on.
51-
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "53b586346f2c7870e20b170decdc30729d97c42b"
51+
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "5125c169b30837208a842f85f7ae44a83533bd0e"
5252

5353
COPY dist-various-2/build-wasi-toolchain.sh /tmp/
5454
RUN /tmp/build-wasi-toolchain.sh

Diff for: src/libcore/cell.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
14751475
#[lang = "unsafe_cell"]
14761476
#[stable(feature = "rust1", since = "1.0.0")]
14771477
#[repr(transparent)]
1478+
#[cfg_attr(not(bootstrap), repr(no_niche))] // rust-lang/rust#68303.
14781479
pub struct UnsafeCell<T: ?Sized> {
14791480
value: T,
14801481
}

Diff for: src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
#![feature(const_type_id)]
140140
#![feature(const_caller_location)]
141141
#![feature(assoc_int_consts)]
142+
#![cfg_attr(not(bootstrap), feature(no_niche))] // rust-lang/rust#68303
142143

143144
#[prelude_import]
144145
#[allow(unused)]

Diff for: src/librustc/ty/layout.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -356,12 +356,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
356356
debug!("univariant offset: {:?} field: {:#?}", offset, field);
357357
offsets[i as usize] = offset;
358358

359-
if let Some(mut niche) = field.largest_niche.clone() {
360-
let available = niche.available(dl);
361-
if available > largest_niche_available {
362-
largest_niche_available = available;
363-
niche.offset += offset;
364-
largest_niche = Some(niche);
359+
if !repr.hide_niche() {
360+
if let Some(mut niche) = field.largest_niche.clone() {
361+
let available = niche.available(dl);
362+
if available > largest_niche_available {
363+
largest_niche_available = available;
364+
niche.offset += offset;
365+
largest_niche = Some(niche);
366+
}
365367
}
366368
}
367369

@@ -838,7 +840,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
838840
}
839841

840842
// Update `largest_niche` if we have introduced a larger niche.
841-
let niche = Niche::from_scalar(dl, Size::ZERO, scalar.clone());
843+
let niche = if def.repr.hide_niche() {
844+
None
845+
} else {
846+
Niche::from_scalar(dl, Size::ZERO, scalar.clone())
847+
};
842848
if let Some(niche) = niche {
843849
match &st.largest_niche {
844850
Some(largest_niche) => {
@@ -863,6 +869,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
863869
return Ok(tcx.intern_layout(st));
864870
}
865871

872+
// At this point, we have handled all unions and
873+
// structs. (We have also handled univariant enums
874+
// that allow representation optimization.)
875+
assert!(def.is_enum());
876+
866877
// The current code for niche-filling relies on variant indices
867878
// instead of actual discriminants, so dataful enums with
868879
// explicit discriminants (RFC #2363) would misbehave.

Diff for: src/librustc/ty/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,8 @@ bitflags! {
20412041
const IS_TRANSPARENT = 1 << 2;
20422042
// Internal only for now. If true, don't reorder fields.
20432043
const IS_LINEAR = 1 << 3;
2044-
2044+
// If true, don't expose any niche to type's context.
2045+
const HIDE_NICHE = 1 << 4;
20452046
// Any of these flags being set prevent field reordering optimisation.
20462047
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits |
20472048
ReprFlags::IS_SIMD.bits |
@@ -2078,6 +2079,7 @@ impl ReprOptions {
20782079
ReprFlags::empty()
20792080
}
20802081
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
2082+
attr::ReprNoNiche => ReprFlags::HIDE_NICHE,
20812083
attr::ReprSimd => ReprFlags::IS_SIMD,
20822084
attr::ReprInt(i) => {
20832085
size = Some(i);
@@ -2118,6 +2120,10 @@ impl ReprOptions {
21182120
pub fn linear(&self) -> bool {
21192121
self.flags.contains(ReprFlags::IS_LINEAR)
21202122
}
2123+
#[inline]
2124+
pub fn hide_niche(&self) -> bool {
2125+
self.flags.contains(ReprFlags::HIDE_NICHE)
2126+
}
21212127

21222128
pub fn discr_type(&self) -> attr::IntType {
21232129
self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize))

Diff for: src/librustc_attr/builtin.rs

+2
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ pub enum ReprAttr {
840840
ReprSimd,
841841
ReprTransparent,
842842
ReprAlign(u32),
843+
ReprNoNiche,
843844
}
844845

845846
#[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone, HashStable_Generic)]
@@ -895,6 +896,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
895896
sym::packed => Some(ReprPacked(1)),
896897
sym::simd => Some(ReprSimd),
897898
sym::transparent => Some(ReprTransparent),
899+
sym::no_niche => Some(ReprNoNiche),
898900
name => int_type_of_word(name).map(ReprInt),
899901
};
900902

Diff for: src/librustc_builtin_macros/deriving/generic/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,8 @@ fn find_repr_type_name(sess: &ParseSess, type_attrs: &[ast::Attribute]) -> &'sta
825825
attr::ReprPacked(_)
826826
| attr::ReprSimd
827827
| attr::ReprAlign(_)
828-
| attr::ReprTransparent => continue,
828+
| attr::ReprTransparent
829+
| attr::ReprNoNiche => continue,
829830

830831
attr::ReprC => "i32",
831832

Diff for: src/librustc_feature/active.rs

+4
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ declare_features! (
204204
/// Added for testing E0705; perma-unstable.
205205
(active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
206206

207+
/// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`,
208+
/// it is not on path for eventual stabilization).
209+
(active, no_niche, "1.42.0", None, None),
210+
207211
// no-tracking-issue-end
208212

209213
// -------------------------------------------------------------------------

Diff for: src/librustc_passes/check_attr.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
1616
use rustc_hir::DUMMY_HIR_ID;
1717
use rustc_hir::{self, HirId, Item, ItemKind, TraitItem};
1818
use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES};
19+
use rustc_session::parse::feature_err;
1920
use rustc_span::symbol::sym;
2021
use rustc_span::Span;
21-
use syntax::ast::Attribute;
22+
use syntax::ast::{Attribute, NestedMetaItem};
2223
use syntax::attr;
2324

2425
fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
@@ -278,6 +279,21 @@ impl CheckAttrVisitor<'tcx> {
278279
_ => ("a", "struct, enum, or union"),
279280
}
280281
}
282+
sym::no_niche => {
283+
if !self.tcx.features().enabled(sym::no_niche) {
284+
feature_err(
285+
&self.tcx.sess.parse_sess,
286+
sym::no_niche,
287+
hint.span(),
288+
"the attribute `repr(no_niche)` is currently unstable",
289+
)
290+
.emit();
291+
}
292+
match target {
293+
Target::Struct | Target::Enum => continue,
294+
_ => ("a", "struct or enum"),
295+
}
296+
}
281297
sym::i8
282298
| sym::u8
283299
| sym::i16
@@ -305,8 +321,10 @@ impl CheckAttrVisitor<'tcx> {
305321
// This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
306322
let hint_spans = hints.iter().map(|hint| hint.span());
307323

308-
// Error on repr(transparent, <anything else>).
309-
if is_transparent && hints.len() > 1 {
324+
// Error on repr(transparent, <anything else apart from no_niche>).
325+
let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche;
326+
let non_no_niche_count = hints.iter().filter(non_no_niche).count();
327+
if is_transparent && non_no_niche_count > 1 {
310328
let hint_spans: Vec<_> = hint_spans.clone().collect();
311329
struct_span_err!(
312330
self.tcx.sess,

Diff for: src/librustc_span/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ symbols! {
491491
non_exhaustive,
492492
non_modrs_mods,
493493
no_sanitize,
494+
no_niche,
494495
no_stack_check,
495496
no_start,
496497
no_std,
@@ -587,6 +588,7 @@ symbols! {
587588
repr128,
588589
repr_align,
589590
repr_align_enum,
591+
repr_no_niche,
590592
repr_packed,
591593
repr_simd,
592594
repr_transparent,

Diff for: src/libstd/sys/sgx/rwlock.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ pub struct RWLock {
1010
writer: SpinMutex<WaitVariable<bool>>,
1111
}
1212

13-
// Below is to check at compile time, that RWLock has size of 128 bytes.
13+
// Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below)
1414
#[allow(dead_code)]
1515
unsafe fn rw_lock_size_assert(r: RWLock) {
16-
mem::transmute::<RWLock, [u8; 128]>(r);
16+
mem::transmute::<RWLock, [u8; 144]>(r);
1717
}
1818

1919
impl RWLock {
@@ -210,15 +210,17 @@ mod tests {
210210
// be changed too.
211211
#[test]
212212
fn test_c_rwlock_initializer() {
213+
#[rustfmt::skip]
213214
const RWLOCK_INIT: &[u8] = &[
214-
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
215-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0,
216-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
217-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
218-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
219-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0,
220-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
221-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
215+
/* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
216+
/* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
217+
/* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
218+
/* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
219+
/* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
220+
/* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
221+
/* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
222+
/* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
223+
/* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
222224
];
223225

224226
#[inline(never)]
@@ -239,7 +241,7 @@ mod tests {
239241
zero_stack();
240242
let mut init = MaybeUninit::<RWLock>::zeroed();
241243
rwlock_new(&mut init);
242-
assert_eq!(mem::transmute::<_, [u8; 128]>(init.assume_init()).as_slice(), RWLOCK_INIT)
244+
assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT)
243245
};
244246
}
245247
}

Diff for: src/test/ui/layout/unsafe-cell-hides-niche.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// For rust-lang/rust#68303: the contents of `UnsafeCell<T>` cannot
2+
// participate in the niche-optimization for enum discriminants. This
3+
// test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same
4+
// size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes).
5+
6+
// run-pass
7+
8+
#![feature(no_niche)]
9+
10+
use std::cell::UnsafeCell;
11+
use std::mem::size_of;
12+
use std::num::NonZeroU32 as N32;
13+
14+
struct Wrapper<T>(T);
15+
16+
#[repr(transparent)]
17+
struct Transparent<T>(T);
18+
19+
#[repr(no_niche)]
20+
struct NoNiche<T>(T);
21+
22+
fn main() {
23+
assert_eq!(size_of::<Option<Wrapper<u32>>>(), 8);
24+
assert_eq!(size_of::<Option<Wrapper<N32>>>(), 4);
25+
assert_eq!(size_of::<Option<Transparent<u32>>>(), 8);
26+
assert_eq!(size_of::<Option<Transparent<N32>>>(), 4);
27+
assert_eq!(size_of::<Option<NoNiche<u32>>>(), 8);
28+
assert_eq!(size_of::<Option<NoNiche<N32>>>(), 8);
29+
30+
assert_eq!(size_of::<Option<UnsafeCell<u32>>>(), 8);
31+
assert_eq!(size_of::<Option<UnsafeCell<N32>>>(), 8);
32+
}

Diff for: src/test/ui/repr/feature-gate-no-niche.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use std::num::NonZeroU8 as N8;
2+
use std::num::NonZeroU16 as N16;
3+
4+
#[repr(no_niche)]
5+
pub struct Cloaked(N16);
6+
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
7+
8+
#[repr(transparent, no_niche)]
9+
pub struct Shadowy(N16);
10+
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
11+
12+
#[repr(no_niche)]
13+
pub enum Cloaked1 { _A(N16), }
14+
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
15+
16+
#[repr(no_niche)]
17+
pub enum Cloaked2 { _A(N16), _B(u8, N8) }
18+
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
19+
20+
fn main() { }

Diff for: src/test/ui/repr/feature-gate-no-niche.stderr

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0658]: the attribute `repr(no_niche)` is currently unstable
2+
--> $DIR/feature-gate-no-niche.rs:4:8
3+
|
4+
LL | #[repr(no_niche)]
5+
| ^^^^^^^^
6+
|
7+
= help: add `#![feature(no_niche)]` to the crate attributes to enable
8+
9+
error[E0658]: the attribute `repr(no_niche)` is currently unstable
10+
--> $DIR/feature-gate-no-niche.rs:8:21
11+
|
12+
LL | #[repr(transparent, no_niche)]
13+
| ^^^^^^^^
14+
|
15+
= help: add `#![feature(no_niche)]` to the crate attributes to enable
16+
17+
error[E0658]: the attribute `repr(no_niche)` is currently unstable
18+
--> $DIR/feature-gate-no-niche.rs:12:8
19+
|
20+
LL | #[repr(no_niche)]
21+
| ^^^^^^^^
22+
|
23+
= help: add `#![feature(no_niche)]` to the crate attributes to enable
24+
25+
error[E0658]: the attribute `repr(no_niche)` is currently unstable
26+
--> $DIR/feature-gate-no-niche.rs:16:8
27+
|
28+
LL | #[repr(no_niche)]
29+
| ^^^^^^^^
30+
|
31+
= help: add `#![feature(no_niche)]` to the crate attributes to enable
32+
33+
error: aborting due to 4 previous errors
34+
35+
For more information about this error, try `rustc --explain E0658`.
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(no_niche)]
2+
3+
use std::num::NonZeroU8 as N8;
4+
use std::num::NonZeroU16 as N16;
5+
6+
#[repr(no_niche)]
7+
pub union Cloaked1 { _A: N16 }
8+
//~^^ ERROR attribute should be applied to struct or enum [E0517]
9+
10+
#[repr(no_niche)]
11+
pub union Cloaked2 { _A: N16, _B: (u8, N8) }
12+
//~^^ ERROR attribute should be applied to struct or enum [E0517]
13+
14+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0517]: attribute should be applied to struct or enum
2+
--> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8
3+
|
4+
LL | #[repr(no_niche)]
5+
| ^^^^^^^^
6+
LL | pub union Cloaked1 { _A: N16 }
7+
| ------------------------------ not a struct or enum
8+
9+
error[E0517]: attribute should be applied to struct or enum
10+
--> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8
11+
|
12+
LL | #[repr(no_niche)]
13+
| ^^^^^^^^
14+
LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) }
15+
| -------------------------------------------- not a struct or enum
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0517`.

0 commit comments

Comments
 (0)