Skip to content

Commit

Permalink
Add a Ranged wrapper struct to replace the rustc_scalar_range_valid…
Browse files Browse the repository at this point in the history
… attributes
  • Loading branch information
oli-obk committed Nov 3, 2022
1 parent 160b194 commit 097d12e
Show file tree
Hide file tree
Showing 111 changed files with 746 additions and 1,598 deletions.
44 changes: 28 additions & 16 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
pub trait DispatchFromDyn<T> {}

// &T -> &U
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
// &mut T -> &mut U
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
// *const T -> *const U
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
// *mut T -> *mut U
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}

#[lang = "receiver"]
Expand Down Expand Up @@ -285,7 +285,6 @@ impl PartialEq for u32 {
}
}


impl PartialEq for u64 {
fn eq(&self, other: &u64) -> bool {
(*self) == (*other)
Expand Down Expand Up @@ -358,7 +357,7 @@ impl<T: ?Sized> PartialEq for *const T {
}
}

impl <T: PartialEq> PartialEq for Option<T> {
impl<T: PartialEq> PartialEq for Option<T> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Some(lhs), Some(rhs)) => *lhs == *rhs,
Expand Down Expand Up @@ -469,7 +468,11 @@ pub fn panic(_msg: &'static str) -> ! {
#[track_caller]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
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);
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,
);
intrinsics::abort();
}
}
Expand All @@ -495,9 +498,8 @@ pub trait Deref {
}

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

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

extern {
extern "C" {
type VaListImpl;
}

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

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro stringify($($t:tt)*) { /* compiler built-in */ }
pub macro stringify($($t:tt)*) {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro file() { /* compiler built-in */ }
pub macro file() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro line() { /* compiler built-in */ }
pub macro line() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro cfg() { /* compiler built-in */ }
pub macro cfg() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro global_asm() { /* compiler built-in */ }
pub macro global_asm() {
/* compiler built-in */
}

pub static A_STATIC: u8 = 42;

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>

// *After* all of this, check the ABI. We need to check the ABI to handle
// types like `NonNull` where the `Scalar` info is more restrictive than what
// the fields say (`rustc_layout_scalar_valid_range_start`).
// the fields say (`Ranged<T, ...>`).
// But in most cases, this will just propagate what the fields say,
// and then we want the error to point at the field -- so, first recurse,
// then check ABI.
Expand All @@ -783,6 +783,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
}
}
Abi::ScalarPair(a_layout, b_layout) => {
// FIXME: range restrictions work on the first element of a pair.
// There is no `rustc_layout_scalar_valid_range_start` for pairs, so
// we would validate these things as we descend into the fields,
// but that can miss bugs in layout computation. Layout computation
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_const_eval/src/interpret/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,10 @@ macro_rules! make_value_visitor {
);
// ... that contains a `NonNull`... (gladly, only a single field here)
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
let raw_ptr = nonnull_ptr.project_field(self.ecx(), 0)?; // the actual raw ptr
let ranged = nonnull_ptr.project_field(self.ecx(), 0)?; // the Ranged struct
// ... which then contains a `Ranged<*const T>` ...
assert_eq!(ranged.layout().fields.count(), 1);
let raw_ptr = ranged.project_field(self.ecx(), 0)?; // the actual raw ptr
// ... whose only field finally is a raw ptr we can dereference.
self.visit_box(&raw_ptr)?;

Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct TypeChecker<'a, 'tcx> {
}

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
#[track_caller]
fn fail(&self, location: Location, msg: impl AsRef<str>) {
let span = self.body.source_info(location).span;
// We use `delay_span_bug` as we might see broken MIR when other errors have already
Expand Down Expand Up @@ -281,12 +282,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
let check_equal = |this: &Self, location, f_ty| {
if !this.mir_assign_valid_types(ty, f_ty) {
this.fail(
location,
format!(
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
parent, f, ty, f_ty
location,
format!(
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
parent, f, ty, f_ty
)
)
)
}
};

Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_error_messages/locales/en-US/passes.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,6 @@ passes_export_name =
attribute should be applied to a free function, impl method or static
.label = not a free function, impl method or static
passes_rustc_layout_scalar_valid_range_not_struct =
attribute should be applied to a struct
.label = not a struct
passes_rustc_layout_scalar_valid_range_arg =
expected exactly one integer literal argument
passes_rustc_legacy_const_generics_only =
#[rustc_legacy_const_generics] functions must only have const generics
.label = non-const generic parameter
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,16 +659,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes, Layout related:
// ==========================================================================

rustc_attr!(
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in libcore and libstd and will never be stable",
),
rustc_attr!(
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in libcore and libstd and will never be stable",
),
rustc_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ language_item_table! {
Index, sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1);
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);

Ranged, sym::ranged , ranged_type, Target::Struct, GenericRequirement::None;

UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;

Expand Down
45 changes: 20 additions & 25 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, InnerSpan, Span};
use rustc_target::abi::VariantIdx;
use rustc_target::abi::{Abi, VariantIdx};
use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};

use crate::nonstandard_style::{method_context, MethodLateContext};
Expand Down Expand Up @@ -2524,32 +2524,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
}
// Recurse and checks for some compound types. (but not unions)
Adt(adt_def, substs) if !adt_def.is_union() => {
// First check if this ADT has a layout attribute (like `NonNull` and friends).
use std::ops::Bound;
match cx.tcx.layout_scalar_valid_range(adt_def.did()) {
// We exploit here that `layout_scalar_valid_range` will never
// return `Bound::Excluded`. (And we have tests checking that we
// handle the attribute correctly.)
// We don't add a span since users cannot declare such types anyway.
(Bound::Included(lo), Bound::Included(hi)) if 0 < lo && lo < hi => {
return Some((format!("`{}` must be non-null", ty), None));
}
(Bound::Included(lo), Bound::Unbounded) if 0 < lo => {
return Some((format!("`{}` must be non-null", ty), None));
}
(Bound::Included(_), _) | (_, Bound::Included(_))
if init == InitKind::Uninit =>
{
return Some((
format!(
"`{}` must be initialized inside its custom valid range",
ty,
),
None,
));
// First check if this ADT has a constrained layout (like `NonNull` and friends).
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) {
match &layout.abi {
Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) => {
let range = scalar.valid_range(cx);
if !range.contains(0) {
return Some((format!("`{}` must be non-null", ty), None));
} else if init == InitKind::Uninit && !scalar.is_always_valid(cx) {
return Some((
format!(
"`{}` must be initialized inside its custom valid range",
ty,
),
None,
));
}
}
_ => {}
}
_ => {}
}

// Handle structs.
if adt_def.is_struct() {
return variant_find_init_error(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub fn symbols(input: TokenStream) -> TokenStream {
/// `u32::MAX`. You can also customize things like the `Debug` impl,
/// what traits are derived, and so forth via the macro.
#[proc_macro]
#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)]
#[allow_internal_unstable(step_trait, rustc_attrs, ranged_int, trusted_step)]
pub fn newtype_index(input: TokenStream) -> TokenStream {
newtype::newtype(input)
}
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_macros/src/newtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl Parse for Newtype {
}
impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
fn encode(&self, e: &mut E) {
e.emit_u32(self.private);
e.emit_u32(self.as_u32());
}
}
}
Expand Down Expand Up @@ -196,10 +196,10 @@ impl Parse for Newtype {
Ok(Self(quote! {
#(#attrs)*
#[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
#[rustc_layout_scalar_valid_range_end(#max)]
#[cfg_attr(bootstrap, rustc_layout_scalar_valid_range_end(#max))]
#[rustc_pass_by_value]
#vis struct #name {
private: u32,
private: std::num::Ranged<u32, {0..=#max}>,
}

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

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

/// Extracts the value of this index as a `usize`.
Expand Down
17 changes: 0 additions & 17 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,11 @@ pub enum UnsafetyViolationKind {
pub enum UnsafetyViolationDetails {
CallToUnsafeFunction,
UseOfInlineAssembly,
InitializingTypeWith,
CastOfPointerToInt,
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
AccessToUnionField,
MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField,
CallToFunctionWith,
}

Expand All @@ -54,11 +51,6 @@ impl UnsafetyViolationDetails {
"use of inline assembly",
"inline assembly is entirely unchecked and can cause undefined behavior",
),
InitializingTypeWith => (
"initializing type with `rustc_layout_scalar_valid_range` attr",
"initializing a layout restricted type's field with a value outside the valid \
range is undefined behavior",
),
CastOfPointerToInt => {
("cast of pointer to int", "casting pointers to integers in constants")
}
Expand All @@ -82,15 +74,6 @@ impl UnsafetyViolationDetails {
"the field may not be properly initialized: using uninitialized data will cause \
undefined behavior",
),
MutationOfLayoutConstrainedField => (
"mutation of layout constrained field",
"mutating layout constrained fields cannot statically be checked for valid values",
),
BorrowOfLayoutConstrainedField => (
"borrow of layout constrained field with interior mutability",
"references to fields of layout constrained fields lose the constraints. Coupled \
with interior mutability, the field can be changed to invalid values",
),
CallToFunctionWith => (
"call to function with `#[target_feature]`",
"can only be called if the required target features are available",
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_middle/src/ty/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ bitflags! {
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
/// Indicates whether the type is `UnsafeCell`.
const IS_UNSAFE_CELL = 1 << 9;
/// Indicates whether the type is `Ranged`.
const IS_RANGED = 1 << 10;
}
}

Expand Down Expand Up @@ -249,6 +251,9 @@ impl AdtDefData {
if Some(did) == tcx.lang_items().unsafe_cell_type() {
flags |= AdtFlags::IS_UNSAFE_CELL;
}
if Some(did) == tcx.lang_items().ranged_type() {
flags |= AdtFlags::IS_RANGED;
}

AdtDefData { did, variants, flags, repr }
}
Expand Down Expand Up @@ -341,6 +346,12 @@ impl<'tcx> AdtDef<'tcx> {
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
}

/// Returns `true` if this is `Ranged<T, RANGE>`.
#[inline]
pub fn is_ranged(self) -> bool {
self.flags().contains(AdtFlags::IS_RANGED)
}

/// Returns `true` if this is `ManuallyDrop<T>`.
#[inline]
pub fn is_manually_drop(self) -> bool {
Expand Down
Loading

0 comments on commit 097d12e

Please sign in to comment.