Skip to content

Commit a876552

Browse files
committed
Auto merge of #113946 - dtolnay:revertniche, r=oli-obk
Revert "Prototype: Add unstable `-Z reference-niches` option" Clean revert of #113166. I confirmed this fixes #113941.
2 parents a5e2eca + 5bbf0a8 commit a876552

File tree

48 files changed

+294
-1065
lines changed

Some content is hidden

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

48 files changed

+294
-1065
lines changed

compiler/rustc_abi/src/lib.rs

+10-98
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,6 @@ bitflags! {
4949
}
5050
}
5151

52-
/// Which niches (beyond the `null` niche) are available on references.
53-
#[derive(Default, Copy, Clone, Hash, Debug, Eq, PartialEq)]
54-
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
55-
pub struct ReferenceNichePolicy {
56-
pub size: bool,
57-
pub align: bool,
58-
}
59-
6052
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6153
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
6254
pub enum IntegerType {
@@ -354,33 +346,6 @@ impl TargetDataLayout {
354346
}
355347
}
356348

357-
#[inline]
358-
pub fn target_usize_max(&self) -> u64 {
359-
self.pointer_size.unsigned_int_max().try_into().unwrap()
360-
}
361-
362-
#[inline]
363-
pub fn target_isize_min(&self) -> i64 {
364-
self.pointer_size.signed_int_min().try_into().unwrap()
365-
}
366-
367-
#[inline]
368-
pub fn target_isize_max(&self) -> i64 {
369-
self.pointer_size.signed_int_max().try_into().unwrap()
370-
}
371-
372-
/// Returns the (inclusive) range of possible addresses for an allocation with
373-
/// the given size and alignment.
374-
///
375-
/// Note that this doesn't take into account target-specific limitations.
376-
#[inline]
377-
pub fn address_range_for(&self, size: Size, align: Align) -> (u64, u64) {
378-
let end = Size::from_bytes(self.target_usize_max());
379-
let min = align.bytes();
380-
let max = (end - size).align_down_to(align).bytes();
381-
(min, max)
382-
}
383-
384349
#[inline]
385350
pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
386351
for &(size, align) in &self.vector_align {
@@ -508,12 +473,6 @@ impl Size {
508473
Size::from_bytes((self.bytes() + mask) & !mask)
509474
}
510475

511-
#[inline]
512-
pub fn align_down_to(self, align: Align) -> Size {
513-
let mask = align.bytes() - 1;
514-
Size::from_bytes(self.bytes() & !mask)
515-
}
516-
517476
#[inline]
518477
pub fn is_aligned(self, align: Align) -> bool {
519478
let mask = align.bytes() - 1;
@@ -1008,43 +967,6 @@ impl WrappingRange {
1008967
}
1009968
}
1010969

1011-
/// Returns `true` if `range` is contained in `self`.
1012-
#[inline(always)]
1013-
pub fn contains_range<I: Into<u128> + Ord>(&self, range: RangeInclusive<I>) -> bool {
1014-
if range.is_empty() {
1015-
return true;
1016-
}
1017-
1018-
let (vmin, vmax) = range.into_inner();
1019-
let (vmin, vmax) = (vmin.into(), vmax.into());
1020-
1021-
if self.start <= self.end {
1022-
self.start <= vmin && vmax <= self.end
1023-
} else {
1024-
// The last check is needed to cover the following case:
1025-
// `vmin ... start, end ... vmax`. In this special case there is no gap
1026-
// between `start` and `end` so we must return true.
1027-
self.start <= vmin || vmax <= self.end || self.start == self.end + 1
1028-
}
1029-
}
1030-
1031-
/// Returns `true` if `range` has an overlap with `self`.
1032-
#[inline(always)]
1033-
pub fn overlaps_range<I: Into<u128> + Ord>(&self, range: RangeInclusive<I>) -> bool {
1034-
if range.is_empty() {
1035-
return false;
1036-
}
1037-
1038-
let (vmin, vmax) = range.into_inner();
1039-
let (vmin, vmax) = (vmin.into(), vmax.into());
1040-
1041-
if self.start <= self.end {
1042-
self.start <= vmax && vmin <= self.end
1043-
} else {
1044-
self.start <= vmax || vmin <= self.end
1045-
}
1046-
}
1047-
1048970
/// Returns `self` with replaced `start`
1049971
#[inline(always)]
1050972
pub fn with_start(mut self, start: u128) -> Self {
@@ -1062,15 +984,9 @@ impl WrappingRange {
1062984
/// Returns `true` if `size` completely fills the range.
1063985
#[inline]
1064986
pub fn is_full_for(&self, size: Size) -> bool {
1065-
debug_assert!(self.is_in_range_for(size));
1066-
self.start == (self.end.wrapping_add(1) & size.unsigned_int_max())
1067-
}
1068-
1069-
/// Returns `true` if the range is valid for `size`.
1070-
#[inline(always)]
1071-
pub fn is_in_range_for(&self, size: Size) -> bool {
1072987
let max_value = size.unsigned_int_max();
1073-
self.start <= max_value && self.end <= max_value
988+
debug_assert!(self.start <= max_value && self.end <= max_value);
989+
self.start == (self.end.wrapping_add(1) & max_value)
1074990
}
1075991
}
1076992

@@ -1511,21 +1427,16 @@ impl Niche {
15111427

15121428
pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
15131429
assert!(count > 0);
1514-
if count > self.available(cx) {
1515-
return None;
1516-
}
15171430

15181431
let Self { value, valid_range: v, .. } = *self;
1519-
let max_value = value.size(cx).unsigned_int_max();
1520-
let distance_end_zero = max_value - v.end;
1432+
let size = value.size(cx);
1433+
assert!(size.bits() <= 128);
1434+
let max_value = size.unsigned_int_max();
15211435

1522-
// Null-pointer optimization. This is guaranteed by Rust (at least for `Option<_>`),
1523-
// and offers better codegen opportunities.
1524-
if count == 1 && matches!(value, Pointer(_)) && !v.contains(0) {
1525-
// Select which bound to move to minimize the number of lost niches.
1526-
let valid_range =
1527-
if v.start - 1 > distance_end_zero { v.with_end(0) } else { v.with_start(0) };
1528-
return Some((0, Scalar::Initialized { value, valid_range }));
1436+
let niche = v.end.wrapping_add(1)..v.start;
1437+
let available = niche.end.wrapping_sub(niche.start) & max_value;
1438+
if count > available {
1439+
return None;
15291440
}
15301441

15311442
// Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
@@ -1548,6 +1459,7 @@ impl Niche {
15481459
let end = v.end.wrapping_add(count) & max_value;
15491460
Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
15501461
};
1462+
let distance_end_zero = max_value - v.end;
15511463
if v.start > v.end {
15521464
// zero is unavailable because wrapping occurs
15531465
move_end(v)

compiler/rustc_codegen_gcc/src/type_of.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
339339
return pointee;
340340
}
341341

342-
let assume_valid_ptr = true;
343-
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset, assume_valid_ptr);
342+
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
344343

345344
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
346345
result

compiler/rustc_codegen_llvm/src/type_of.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
411411
if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
412412
return pointee;
413413
}
414-
let assume_valid_ptr = true;
415-
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset, assume_valid_ptr);
414+
415+
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
416416

417417
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
418418
result

compiler/rustc_const_eval/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ const_eval_not_enough_caller_args =
244244
const_eval_null_box = {$front_matter}: encountered a null box
245245
const_eval_null_fn_ptr = {$front_matter}: encountered a null function pointer
246246
const_eval_null_ref = {$front_matter}: encountered a null reference
247+
const_eval_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range}
247248
const_eval_nullary_intrinsic_fail =
248249
could not evaluate nullary intrinsic
249250

compiler/rustc_const_eval/src/const_eval/machine.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_hir::def::DefKind;
22
use rustc_hir::{LangItem, CRATE_HIR_ID};
33
use rustc_middle::mir;
4+
use rustc_middle::mir::interpret::PointerArithmetic;
45
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
56
use rustc_middle::ty::{self, Ty, TyCtxt};
67
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
@@ -16,7 +17,7 @@ use rustc_ast::Mutability;
1617
use rustc_hir::def_id::DefId;
1718
use rustc_middle::mir::AssertMessage;
1819
use rustc_span::symbol::{sym, Symbol};
19-
use rustc_target::abi::{Align, HasDataLayout as _, Size};
20+
use rustc_target::abi::{Align, Size};
2021
use rustc_target::spec::abi::Abi as CallAbi;
2122

2223
use crate::errors::{LongRunning, LongRunningWarn};
@@ -303,8 +304,8 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
303304
Ok(ControlFlow::Break(()))
304305
} else {
305306
// Not alignable in const, return `usize::MAX`.
306-
let usize_max = self.data_layout().target_usize_max();
307-
self.write_scalar(Scalar::from_target_usize(usize_max, self), dest)?;
307+
let usize_max = Scalar::from_target_usize(self.target_usize_max(), self);
308+
self.write_scalar(usize_max, dest)?;
308309
self.return_to_block(ret)?;
309310
Ok(ControlFlow::Break(()))
310311
}
@@ -332,7 +333,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
332333
// Inequality with integers other than null can never be known for sure.
333334
(Scalar::Int(int), ptr @ Scalar::Ptr(..))
334335
| (ptr @ Scalar::Ptr(..), Scalar::Int(int))
335-
if int.is_null() && !self.ptr_scalar_range(ptr)?.contains(&0) =>
336+
if int.is_null() && !self.scalar_may_be_null(ptr)? =>
336337
{
337338
0
338339
}

compiler/rustc_const_eval/src/errors.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
617617
MutableRefInConst => const_eval_mutable_ref_in_const,
618618
NullFnPtr => const_eval_null_fn_ptr,
619619
NeverVal => const_eval_never_val,
620+
NullablePtrOutOfRange { .. } => const_eval_nullable_ptr_out_of_range,
620621
PtrOutOfRange { .. } => const_eval_ptr_out_of_range,
621622
OutOfRange { .. } => const_eval_out_of_range,
622623
UnsafeCell => const_eval_unsafe_cell,
@@ -731,7 +732,9 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
731732
| InvalidFnPtr { value } => {
732733
err.set_arg("value", value);
733734
}
734-
PtrOutOfRange { range, max_value } => add_range_arg(range, max_value, handler, err),
735+
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
736+
add_range_arg(range, max_value, handler, err)
737+
}
735738
OutOfRange { range, max_value, value } => {
736739
err.set_arg("value", value);
737740
add_range_arg(range, max_value, handler, err);

compiler/rustc_const_eval/src/interpret/discriminant.rs

+10-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
33
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
44
use rustc_middle::{mir, ty};
5-
use rustc_target::abi::{self, TagEncoding, VariantIdx, Variants, WrappingRange};
5+
use rustc_target::abi::{self, TagEncoding};
6+
use rustc_target::abi::{VariantIdx, Variants};
67

78
use super::{ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Scalar};
89

@@ -179,24 +180,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
179180
// discriminant (encoded in niche/tag) and variant index are the same.
180181
let variants_start = niche_variants.start().as_u32();
181182
let variants_end = niche_variants.end().as_u32();
182-
let variants_len = u128::from(variants_end - variants_start);
183183
let variant = match tag_val.try_to_int() {
184184
Err(dbg_val) => {
185185
// So this is a pointer then, and casting to an int failed.
186186
// Can only happen during CTFE.
187-
// The pointer and niches ranges must be disjoint, then we know
188-
// this is the untagged variant (as the value is not in the niche).
189-
// Everything else, we conservatively reject.
190-
let range = self.ptr_scalar_range(tag_val)?;
191-
let niches = WrappingRange {
192-
start: niche_start,
193-
end: niche_start.wrapping_add(variants_len),
194-
};
195-
if niches.overlaps_range(range) {
187+
// The niche must be just 0, and the ptr not null, then we know this is
188+
// okay. Everything else, we conservatively reject.
189+
let ptr_valid = niche_start == 0
190+
&& variants_start == variants_end
191+
&& !self.scalar_may_be_null(tag_val)?;
192+
if !ptr_valid {
196193
throw_ub!(InvalidTag(dbg_val))
197-
} else {
198-
untagged_variant
199194
}
195+
untagged_variant
200196
}
201197
Ok(tag_bits) => {
202198
let tag_bits = tag_bits.assert_bits(tag_layout.size);
@@ -209,7 +205,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
209205
let variant_index_relative =
210206
variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
211207
// Check if this is in the range that indicates an actual discriminant.
212-
if variant_index_relative <= variants_len {
208+
if variant_index_relative <= u128::from(variants_end - variants_start) {
213209
let variant_index_relative = u32::try_from(variant_index_relative)
214210
.expect("we checked that this fits into a u32");
215211
// Then computing the absolute variant idx should not overflow any more.

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
use rustc_hir::def_id::DefId;
66
use rustc_middle::mir::{
77
self,
8-
interpret::{Allocation, ConstAllocation, ConstValue, GlobalId, InterpResult, Scalar},
8+
interpret::{
9+
Allocation, ConstAllocation, ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar,
10+
},
911
BinOp, NonDivergingIntrinsic,
1012
};
1113
use rustc_middle::ty;
1214
use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
1315
use rustc_middle::ty::GenericArgsRef;
1416
use rustc_middle::ty::{Ty, TyCtxt};
1517
use rustc_span::symbol::{sym, Symbol};
16-
use rustc_target::abi::{Abi, Align, HasDataLayout as _, Primitive, Size};
18+
use rustc_target::abi::{Abi, Align, Primitive, Size};
1719

1820
use super::{
1921
util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
@@ -359,12 +361,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
359361
)?;
360362

361363
// Perform division by size to compute return value.
362-
let dl = self.data_layout();
363364
let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
364-
assert!(0 <= dist && dist <= dl.target_isize_max());
365+
assert!(0 <= dist && dist <= self.target_isize_max());
365366
usize_layout
366367
} else {
367-
assert!(dl.target_isize_min() <= dist && dist <= dl.target_isize_max());
368+
assert!(self.target_isize_min() <= dist && dist <= self.target_isize_max());
368369
isize_layout
369370
};
370371
let pointee_layout = self.layout_of(instance_args.type_at(0))?;

compiler/rustc_const_eval/src/interpret/memory.rs

+15-26
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use std::assert_matches::assert_matches;
1010
use std::borrow::Cow;
1111
use std::collections::VecDeque;
1212
use std::fmt;
13-
use std::ops::RangeInclusive;
1413
use std::ptr;
1514

1615
use rustc_ast::Mutability;
@@ -1223,34 +1222,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
12231222

12241223
/// Machine pointer introspection.
12251224
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1226-
/// Turn a pointer-sized scalar into a (non-empty) range of possible values.
1225+
/// Test if this value might be null.
12271226
/// If the machine does not support ptr-to-int casts, this is conservative.
1228-
pub fn ptr_scalar_range(
1229-
&self,
1230-
scalar: Scalar<M::Provenance>,
1231-
) -> InterpResult<'tcx, RangeInclusive<u64>> {
1232-
if let Ok(int) = scalar.to_target_usize(self) {
1233-
return Ok(int..=int);
1234-
}
1235-
1236-
let ptr = scalar.to_pointer(self)?;
1237-
1238-
// Can only happen during CTFE.
1239-
Ok(match self.ptr_try_get_alloc_id(ptr) {
1240-
Ok((alloc_id, offset, _)) => {
1241-
let offset = offset.bytes();
1242-
let (size, align, _) = self.get_alloc_info(alloc_id);
1243-
let dl = self.data_layout();
1244-
if offset > size.bytes() {
1245-
// If the pointer is out-of-bounds, we do not have a
1246-
// meaningful range to return.
1247-
0..=dl.target_usize_max()
1248-
} else {
1249-
let (min, max) = dl.address_range_for(size, align);
1250-
(min + offset)..=(max + offset)
1227+
pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> {
1228+
Ok(match scalar.try_to_int() {
1229+
Ok(int) => int.is_null(),
1230+
Err(_) => {
1231+
// Can only happen during CTFE.
1232+
let ptr = scalar.to_pointer(self)?;
1233+
match self.ptr_try_get_alloc_id(ptr) {
1234+
Ok((alloc_id, offset, _)) => {
1235+
let (size, _align, _kind) = self.get_alloc_info(alloc_id);
1236+
// If the pointer is out-of-bounds, it may be null.
1237+
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
1238+
offset > size
1239+
}
1240+
Err(_offset) => bug!("a non-int scalar is always a pointer"),
12511241
}
12521242
}
1253-
Err(_offset) => bug!("a non-int scalar is always a pointer"),
12541243
})
12551244
}
12561245

0 commit comments

Comments
 (0)