Skip to content

Commit d404d21

Browse files
committed
Add #[repr(no_niche)].
This repr-hint makes a struct/enum hide any niche within from its surrounding type-construction context. It is meant (at least initially) as an implementation detail for resolving issue 68303. We will not stabilize the repr-hint unless someone finds motivation for doing so. (So, declaration of `no_niche` feature lives in section of file where other internal implementation details are grouped, and deliberately leaves out the tracking issue number.) incorporated review feedback, and fixed post-rebase.
1 parent c4071d0 commit d404d21

File tree

7 files changed

+56
-12
lines changed

7 files changed

+56
-12
lines changed

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.

src/librustc/ty/mod.rs

+7-1
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

+2-1
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

+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
// -------------------------------------------------------------------------

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 {
@@ -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

+2
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

+2
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

0 commit comments

Comments
 (0)