Skip to content

Commit 37de63d

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#68303 Fix rust-lang#68206
2 parents 0b6825b + ee633e8 commit 37de63d

File tree

15 files changed

+507
-12
lines changed

15 files changed

+507
-12
lines changed

src/libcore/cell.rs

Lines changed: 1 addition & 0 deletions
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
}

src/libcore/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
#![feature(const_caller_location)]
136136
#![cfg_attr(bootstrap, feature(slice_patterns))]
137137
#![feature(assoc_int_consts)]
138+
#![cfg_attr(not(bootstrap), feature(no_niche))] // rust-lang/rust#68303
138139

139140
#[prelude_import]
140141
#[allow(unused)]

src/librustc/ty/layout.rs

Lines changed: 18 additions & 7 deletions
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.

src/librustc/ty/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2036,7 +2036,8 @@ bitflags! {
20362036
const IS_TRANSPARENT = 1 << 2;
20372037
// Internal only for now. If true, don't reorder fields.
20382038
const IS_LINEAR = 1 << 3;
2039-
2039+
// If true, don't expose any niche to type's context.
2040+
const HIDE_NICHE = 1 << 4;
20402041
// Any of these flags being set prevent field reordering optimisation.
20412042
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits |
20422043
ReprFlags::IS_SIMD.bits |
@@ -2073,6 +2074,7 @@ impl ReprOptions {
20732074
ReprFlags::empty()
20742075
}
20752076
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
2077+
attr::ReprNoNiche => ReprFlags::HIDE_NICHE,
20762078
attr::ReprSimd => ReprFlags::IS_SIMD,
20772079
attr::ReprInt(i) => {
20782080
size = Some(i);
@@ -2113,6 +2115,10 @@ impl ReprOptions {
21132115
pub fn linear(&self) -> bool {
21142116
self.flags.contains(ReprFlags::IS_LINEAR)
21152117
}
2118+
#[inline]
2119+
pub fn hide_niche(&self) -> bool {
2120+
self.flags.contains(ReprFlags::HIDE_NICHE)
2121+
}
21162122

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

src/librustc_builtin_macros/deriving/generic/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,8 @@ fn find_repr_type_name(sess: &ParseSess, type_attrs: &[ast::Attribute]) -> &'sta
824824
attr::ReprPacked(_)
825825
| attr::ReprSimd
826826
| attr::ReprAlign(_)
827-
| attr::ReprTransparent => continue,
827+
| attr::ReprTransparent
828+
| attr::ReprNoNiche => continue,
828829

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

src/librustc_feature/active.rs

Lines changed: 4 additions & 0 deletions
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
// -------------------------------------------------------------------------

src/librustc_passes/check_attr.rs

Lines changed: 21 additions & 3 deletions
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 {
@@ -287,6 +288,21 @@ impl CheckAttrVisitor<'tcx> {
287288
_ => ("a", "struct, enum, or union"),
288289
}
289290
}
291+
sym::no_niche => {
292+
if !self.tcx.features().enabled(sym::no_niche) {
293+
feature_err(
294+
&self.tcx.sess.parse_sess,
295+
sym::no_niche,
296+
hint.span(),
297+
"the attribute `repr(no_niche)` is currently unstable",
298+
)
299+
.emit();
300+
}
301+
match target {
302+
Target::Struct | Target::Enum => continue,
303+
_ => ("a", "struct or enum"),
304+
}
305+
}
290306
sym::i8
291307
| sym::u8
292308
| sym::i16
@@ -314,8 +330,10 @@ impl CheckAttrVisitor<'tcx> {
314330
// This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
315331
let hint_spans = hints.iter().map(|hint| hint.span());
316332

317-
// Error on repr(transparent, <anything else>).
318-
if is_transparent && hints.len() > 1 {
333+
// Error on repr(transparent, <anything else apart from no_niche>).
334+
let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche;
335+
let non_no_niche_count = hints.iter().filter(non_no_niche).count();
336+
if is_transparent && non_no_niche_count > 1 {
319337
let hint_spans: Vec<_> = hint_spans.clone().collect();
320338
struct_span_err!(
321339
self.tcx.sess,

src/librustc_span/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ symbols! {
487487
None,
488488
non_exhaustive,
489489
non_modrs_mods,
490+
no_niche,
490491
no_stack_check,
491492
no_start,
492493
no_std,
@@ -583,6 +584,7 @@ symbols! {
583584
repr128,
584585
repr_align,
585586
repr_align_enum,
587+
repr_no_niche,
586588
repr_packed,
587589
repr_simd,
588590
repr_transparent,

src/libsyntax/attr/builtin.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ pub enum ReprAttr {
820820
ReprSimd,
821821
ReprTransparent,
822822
ReprAlign(u32),
823+
ReprNoNiche,
823824
}
824825

825826
#[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone, HashStable_Generic)]
@@ -875,6 +876,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
875876
sym::packed => Some(ReprPacked(1)),
876877
sym::simd => Some(ReprSimd),
877878
sym::transparent => Some(ReprTransparent),
879+
sym::no_niche => Some(ReprNoNiche),
878880
name => int_type_of_word(name).map(ReprInt),
879881
};
880882

Lines changed: 32 additions & 0 deletions
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+
}
Lines changed: 20 additions & 0 deletions
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() { }
Lines changed: 35 additions & 0 deletions
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`.
Lines changed: 14 additions & 0 deletions
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() { }
Lines changed: 19 additions & 0 deletions
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)