Skip to content

Commit 097d12e

Browse files
committed
Add a Ranged wrapper struct to replace the rustc_scalar_range_valid attributes
1 parent 160b194 commit 097d12e

File tree

111 files changed

+746
-1598
lines changed

Some content is hidden

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

111 files changed

+746
-1598
lines changed

compiler/rustc_codegen_cranelift/example/mini_core.rs

+28-16
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
3434
pub trait DispatchFromDyn<T> {}
3535

3636
// &T -> &U
37-
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
37+
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
3838
// &mut T -> &mut U
39-
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
39+
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
4040
// *const T -> *const U
41-
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
41+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
4242
// *mut T -> *mut U
43-
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
43+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
4444
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
4545

4646
#[lang = "receiver"]
@@ -285,7 +285,6 @@ impl PartialEq for u32 {
285285
}
286286
}
287287

288-
289288
impl PartialEq for u64 {
290289
fn eq(&self, other: &u64) -> bool {
291290
(*self) == (*other)
@@ -358,7 +357,7 @@ impl<T: ?Sized> PartialEq for *const T {
358357
}
359358
}
360359

361-
impl <T: PartialEq> PartialEq for Option<T> {
360+
impl<T: PartialEq> PartialEq for Option<T> {
362361
fn eq(&self, other: &Self) -> bool {
363362
match (self, other) {
364363
(Some(lhs), Some(rhs)) => *lhs == *rhs,
@@ -469,7 +468,11 @@ pub fn panic(_msg: &'static str) -> ! {
469468
#[track_caller]
470469
fn panic_bounds_check(index: usize, len: usize) -> ! {
471470
unsafe {
472-
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
471+
libc::printf(
472+
"index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
473+
len,
474+
index,
475+
);
473476
intrinsics::abort();
474477
}
475478
}
@@ -495,9 +498,8 @@ pub trait Deref {
495498
}
496499

497500
#[repr(transparent)]
498-
#[rustc_layout_scalar_valid_range_start(1)]
499501
#[rustc_nonnull_optimization_guaranteed]
500-
pub struct NonNull<T: ?Sized>(pub *const T);
502+
pub struct NonNull<T: ?Sized>(pub Ranged<*const T, { 1..=(usize::MAX as u128) }>);
501503

502504
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
503505
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
@@ -585,7 +587,7 @@ pub mod libc {
585587
// functions. legacy_stdio_definitions.lib which provides the printf wrapper functions as normal
586588
// symbols to link against.
587589
#[cfg_attr(unix, link(name = "c"))]
588-
#[cfg_attr(target_env="msvc", link(name="legacy_stdio_definitions"))]
590+
#[cfg_attr(target_env = "msvc", link(name = "legacy_stdio_definitions"))]
589591
extern "C" {
590592
pub fn printf(format: *const i8, ...) -> i32;
591593
}
@@ -624,7 +626,7 @@ impl<T> Index<usize> for [T] {
624626
}
625627
}
626628

627-
extern {
629+
extern "C" {
628630
type VaListImpl;
629631
}
630632

@@ -634,23 +636,33 @@ pub struct VaList<'a>(&'a mut VaListImpl);
634636

635637
#[rustc_builtin_macro]
636638
#[rustc_macro_transparency = "semitransparent"]
637-
pub macro stringify($($t:tt)*) { /* compiler built-in */ }
639+
pub macro stringify($($t:tt)*) {
640+
/* compiler built-in */
641+
}
638642

639643
#[rustc_builtin_macro]
640644
#[rustc_macro_transparency = "semitransparent"]
641-
pub macro file() { /* compiler built-in */ }
645+
pub macro file() {
646+
/* compiler built-in */
647+
}
642648

643649
#[rustc_builtin_macro]
644650
#[rustc_macro_transparency = "semitransparent"]
645-
pub macro line() { /* compiler built-in */ }
651+
pub macro line() {
652+
/* compiler built-in */
653+
}
646654

647655
#[rustc_builtin_macro]
648656
#[rustc_macro_transparency = "semitransparent"]
649-
pub macro cfg() { /* compiler built-in */ }
657+
pub macro cfg() {
658+
/* compiler built-in */
659+
}
650660

651661
#[rustc_builtin_macro]
652662
#[rustc_macro_transparency = "semitransparent"]
653-
pub macro global_asm() { /* compiler built-in */ }
663+
pub macro global_asm() {
664+
/* compiler built-in */
665+
}
654666

655667
pub static A_STATIC: u8 = 42;
656668

compiler/rustc_const_eval/src/interpret/validity.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
761761

762762
// *After* all of this, check the ABI. We need to check the ABI to handle
763763
// types like `NonNull` where the `Scalar` info is more restrictive than what
764-
// the fields say (`rustc_layout_scalar_valid_range_start`).
764+
// the fields say (`Ranged<T, ...>`).
765765
// But in most cases, this will just propagate what the fields say,
766766
// and then we want the error to point at the field -- so, first recurse,
767767
// then check ABI.
@@ -783,6 +783,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
783783
}
784784
}
785785
Abi::ScalarPair(a_layout, b_layout) => {
786+
// FIXME: range restrictions work on the first element of a pair.
786787
// There is no `rustc_layout_scalar_valid_range_start` for pairs, so
787788
// we would validate these things as we descend into the fields,
788789
// but that can miss bugs in layout computation. Layout computation

compiler/rustc_const_eval/src/interpret/visitor.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,10 @@ macro_rules! make_value_visitor {
466466
);
467467
// ... that contains a `NonNull`... (gladly, only a single field here)
468468
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
469-
let raw_ptr = nonnull_ptr.project_field(self.ecx(), 0)?; // the actual raw ptr
469+
let ranged = nonnull_ptr.project_field(self.ecx(), 0)?; // the Ranged struct
470+
// ... which then contains a `Ranged<*const T>` ...
471+
assert_eq!(ranged.layout().fields.count(), 1);
472+
let raw_ptr = ranged.project_field(self.ecx(), 0)?; // the actual raw ptr
470473
// ... whose only field finally is a raw ptr we can dereference.
471474
self.visit_box(&raw_ptr)?;
472475

compiler/rustc_const_eval/src/transform/validate.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ struct TypeChecker<'a, 'tcx> {
121121
}
122122

123123
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
124+
#[track_caller]
124125
fn fail(&self, location: Location, msg: impl AsRef<str>) {
125126
let span = self.body.source_info(location).span;
126127
// We use `delay_span_bug` as we might see broken MIR when other errors have already
@@ -281,12 +282,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
281282
let check_equal = |this: &Self, location, f_ty| {
282283
if !this.mir_assign_valid_types(ty, f_ty) {
283284
this.fail(
284-
location,
285-
format!(
286-
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
287-
parent, f, ty, f_ty
285+
location,
286+
format!(
287+
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
288+
parent, f, ty, f_ty
289+
)
288290
)
289-
)
290291
}
291292
};
292293

compiler/rustc_error_messages/locales/en-US/passes.ftl

-7
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,6 @@ passes_export_name =
211211
attribute should be applied to a free function, impl method or static
212212
.label = not a free function, impl method or static
213213
214-
passes_rustc_layout_scalar_valid_range_not_struct =
215-
attribute should be applied to a struct
216-
.label = not a struct
217-
218-
passes_rustc_layout_scalar_valid_range_arg =
219-
expected exactly one integer literal argument
220-
221214
passes_rustc_legacy_const_generics_only =
222215
#[rustc_legacy_const_generics] functions must only have const generics
223216
.label = non-const generic parameter

compiler/rustc_feature/src/builtin_attrs.rs

-10
Original file line numberDiff line numberDiff line change
@@ -659,16 +659,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
659659
// Internal attributes, Layout related:
660660
// ==========================================================================
661661

662-
rustc_attr!(
663-
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
664-
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
665-
niche optimizations in libcore and libstd and will never be stable",
666-
),
667-
rustc_attr!(
668-
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
669-
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
670-
niche optimizations in libcore and libstd and will never be stable",
671-
),
672662
rustc_attr!(
673663
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
674664
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \

compiler/rustc_hir/src/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ language_item_table! {
193193
Index, sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1);
194194
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
195195

196+
Ranged, sym::ranged , ranged_type, Target::Struct, GenericRequirement::None;
197+
196198
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
197199
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
198200

compiler/rustc_lint/src/builtin.rs

+20-25
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use rustc_span::edition::Edition;
5252
use rustc_span::source_map::Spanned;
5353
use rustc_span::symbol::{kw, sym, Ident, Symbol};
5454
use rustc_span::{BytePos, InnerSpan, Span};
55-
use rustc_target::abi::VariantIdx;
55+
use rustc_target::abi::{Abi, VariantIdx};
5656
use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
5757

5858
use crate::nonstandard_style::{method_context, MethodLateContext};
@@ -2524,32 +2524,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
25242524
}
25252525
// Recurse and checks for some compound types. (but not unions)
25262526
Adt(adt_def, substs) if !adt_def.is_union() => {
2527-
// First check if this ADT has a layout attribute (like `NonNull` and friends).
2528-
use std::ops::Bound;
2529-
match cx.tcx.layout_scalar_valid_range(adt_def.did()) {
2530-
// We exploit here that `layout_scalar_valid_range` will never
2531-
// return `Bound::Excluded`. (And we have tests checking that we
2532-
// handle the attribute correctly.)
2533-
// We don't add a span since users cannot declare such types anyway.
2534-
(Bound::Included(lo), Bound::Included(hi)) if 0 < lo && lo < hi => {
2535-
return Some((format!("`{}` must be non-null", ty), None));
2536-
}
2537-
(Bound::Included(lo), Bound::Unbounded) if 0 < lo => {
2538-
return Some((format!("`{}` must be non-null", ty), None));
2539-
}
2540-
(Bound::Included(_), _) | (_, Bound::Included(_))
2541-
if init == InitKind::Uninit =>
2542-
{
2543-
return Some((
2544-
format!(
2545-
"`{}` must be initialized inside its custom valid range",
2546-
ty,
2547-
),
2548-
None,
2549-
));
2527+
// First check if this ADT has a constrained layout (like `NonNull` and friends).
2528+
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) {
2529+
match &layout.abi {
2530+
Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) => {
2531+
let range = scalar.valid_range(cx);
2532+
if !range.contains(0) {
2533+
return Some((format!("`{}` must be non-null", ty), None));
2534+
} else if init == InitKind::Uninit && !scalar.is_always_valid(cx) {
2535+
return Some((
2536+
format!(
2537+
"`{}` must be initialized inside its custom valid range",
2538+
ty,
2539+
),
2540+
None,
2541+
));
2542+
}
2543+
}
2544+
_ => {}
25502545
}
2551-
_ => {}
25522546
}
2547+
25532548
// Handle structs.
25542549
if adt_def.is_struct() {
25552550
return variant_find_init_error(

compiler/rustc_macros/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn symbols(input: TokenStream) -> TokenStream {
4747
/// `u32::MAX`. You can also customize things like the `Debug` impl,
4848
/// what traits are derived, and so forth via the macro.
4949
#[proc_macro]
50-
#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)]
50+
#[allow_internal_unstable(step_trait, rustc_attrs, ranged_int, trusted_step)]
5151
pub fn newtype_index(input: TokenStream) -> TokenStream {
5252
newtype::newtype(input)
5353
}

compiler/rustc_macros/src/newtype.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl Parse for Newtype {
138138
}
139139
impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
140140
fn encode(&self, e: &mut E) {
141-
e.emit_u32(self.private);
141+
e.emit_u32(self.as_u32());
142142
}
143143
}
144144
}
@@ -196,10 +196,10 @@ impl Parse for Newtype {
196196
Ok(Self(quote! {
197197
#(#attrs)*
198198
#[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
199-
#[rustc_layout_scalar_valid_range_end(#max)]
199+
#[cfg_attr(bootstrap, rustc_layout_scalar_valid_range_end(#max))]
200200
#[rustc_pass_by_value]
201201
#vis struct #name {
202-
private: u32,
202+
private: std::num::Ranged<u32, {0..=#max}>,
203203
}
204204

205205
#(#consts)*
@@ -249,7 +249,7 @@ impl Parse for Newtype {
249249
/// Prefer using `from_u32`.
250250
#[inline]
251251
#vis const unsafe fn from_u32_unchecked(value: u32) -> Self {
252-
Self { private: value }
252+
Self { private: std::num::Ranged::new_unchecked(value) }
253253
}
254254

255255
/// Extracts the value of this index as a `usize`.
@@ -261,7 +261,7 @@ impl Parse for Newtype {
261261
/// Extracts the value of this index as a `u32`.
262262
#[inline]
263263
#vis const fn as_u32(self) -> u32 {
264-
self.private
264+
self.private.get()
265265
}
266266

267267
/// Extracts the value of this index as a `usize`.

compiler/rustc_middle/src/mir/query.rs

-17
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,11 @@ pub enum UnsafetyViolationKind {
3030
pub enum UnsafetyViolationDetails {
3131
CallToUnsafeFunction,
3232
UseOfInlineAssembly,
33-
InitializingTypeWith,
3433
CastOfPointerToInt,
3534
UseOfMutableStatic,
3635
UseOfExternStatic,
3736
DerefOfRawPointer,
3837
AccessToUnionField,
39-
MutationOfLayoutConstrainedField,
40-
BorrowOfLayoutConstrainedField,
4138
CallToFunctionWith,
4239
}
4340

@@ -54,11 +51,6 @@ impl UnsafetyViolationDetails {
5451
"use of inline assembly",
5552
"inline assembly is entirely unchecked and can cause undefined behavior",
5653
),
57-
InitializingTypeWith => (
58-
"initializing type with `rustc_layout_scalar_valid_range` attr",
59-
"initializing a layout restricted type's field with a value outside the valid \
60-
range is undefined behavior",
61-
),
6254
CastOfPointerToInt => {
6355
("cast of pointer to int", "casting pointers to integers in constants")
6456
}
@@ -82,15 +74,6 @@ impl UnsafetyViolationDetails {
8274
"the field may not be properly initialized: using uninitialized data will cause \
8375
undefined behavior",
8476
),
85-
MutationOfLayoutConstrainedField => (
86-
"mutation of layout constrained field",
87-
"mutating layout constrained fields cannot statically be checked for valid values",
88-
),
89-
BorrowOfLayoutConstrainedField => (
90-
"borrow of layout constrained field with interior mutability",
91-
"references to fields of layout constrained fields lose the constraints. Coupled \
92-
with interior mutability, the field can be changed to invalid values",
93-
),
9477
CallToFunctionWith => (
9578
"call to function with `#[target_feature]`",
9679
"can only be called if the required target features are available",

compiler/rustc_middle/src/ty/adt.rs

+11
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ bitflags! {
5151
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
5252
/// Indicates whether the type is `UnsafeCell`.
5353
const IS_UNSAFE_CELL = 1 << 9;
54+
/// Indicates whether the type is `Ranged`.
55+
const IS_RANGED = 1 << 10;
5456
}
5557
}
5658

@@ -249,6 +251,9 @@ impl AdtDefData {
249251
if Some(did) == tcx.lang_items().unsafe_cell_type() {
250252
flags |= AdtFlags::IS_UNSAFE_CELL;
251253
}
254+
if Some(did) == tcx.lang_items().ranged_type() {
255+
flags |= AdtFlags::IS_RANGED;
256+
}
252257

253258
AdtDefData { did, variants, flags, repr }
254259
}
@@ -341,6 +346,12 @@ impl<'tcx> AdtDef<'tcx> {
341346
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
342347
}
343348

349+
/// Returns `true` if this is `Ranged<T, RANGE>`.
350+
#[inline]
351+
pub fn is_ranged(self) -> bool {
352+
self.flags().contains(AdtFlags::IS_RANGED)
353+
}
354+
344355
/// Returns `true` if this is `ManuallyDrop<T>`.
345356
#[inline]
346357
pub fn is_manually_drop(self) -> bool {

0 commit comments

Comments
 (0)