mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Rollup merge of #133116 - RalfJung:const-null-ptr, r=dtolnay
stabilize const_ptr_is_null FCP passed in https://github.com/rust-lang/rust/issues/74939. The second commit cleans up const stability around UB checks a bit, now that everything they need (except for `const_eval_select`) is stable. Fixes https://github.com/rust-lang/rust/issues/74939
This commit is contained in:
commit
af1c8be400
@ -263,6 +263,12 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// See documentation on the `ptr_guaranteed_cmp` intrinsic.
|
/// See documentation on the `ptr_guaranteed_cmp` intrinsic.
|
||||||
|
/// Returns `2` if the result is unknown.
|
||||||
|
/// Returns `1` if the pointers are guaranteed equal.
|
||||||
|
/// Returns `0` if the pointers are guaranteed inequal.
|
||||||
|
///
|
||||||
|
/// Note that this intrinsic is exposed on stable for comparison with null. In other words, any
|
||||||
|
/// change to this function that affects comparison with null is insta-stable!
|
||||||
fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
|
fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
|
||||||
interp_ok(match (a, b) {
|
interp_ok(match (a, b) {
|
||||||
// Comparisons between integers are always known.
|
// Comparisons between integers are always known.
|
||||||
|
@ -3292,8 +3292,8 @@ pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T)
|
|||||||
|
|
||||||
/// See documentation of `<*const T>::guaranteed_eq` for details.
|
/// See documentation of `<*const T>::guaranteed_eq` for details.
|
||||||
/// Returns `2` if the result is unknown.
|
/// Returns `2` if the result is unknown.
|
||||||
/// Returns `1` if the pointers are guaranteed equal
|
/// Returns `1` if the pointers are guaranteed equal.
|
||||||
/// Returns `0` if the pointers are guaranteed inequal
|
/// Returns `0` if the pointers are guaranteed inequal.
|
||||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))]
|
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
@ -4014,9 +4014,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
|
|||||||
count: usize = count,
|
count: usize = count,
|
||||||
) => {
|
) => {
|
||||||
let zero_size = count == 0 || size == 0;
|
let zero_size = count == 0 || size == 0;
|
||||||
ub_checks::is_aligned_and_not_null(src, align, zero_size)
|
ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
|
||||||
&& ub_checks::is_aligned_and_not_null(dst, align, zero_size)
|
&& ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
|
||||||
&& ub_checks::is_nonoverlapping(src, dst, size, count)
|
&& ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -4120,8 +4120,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
|||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
zero_size: bool = T::IS_ZST || count == 0,
|
zero_size: bool = T::IS_ZST || count == 0,
|
||||||
) =>
|
) =>
|
||||||
ub_checks::is_aligned_and_not_null(src, align, zero_size)
|
ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
|
||||||
&& ub_checks::is_aligned_and_not_null(dst, align, zero_size)
|
&& ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
|
||||||
);
|
);
|
||||||
copy(src, dst, count)
|
copy(src, dst, count)
|
||||||
}
|
}
|
||||||
@ -4202,7 +4202,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
|
|||||||
addr: *const () = dst as *const (),
|
addr: *const () = dst as *const (),
|
||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
zero_size: bool = T::IS_ZST || count == 0,
|
zero_size: bool = T::IS_ZST || count == 0,
|
||||||
) => ub_checks::is_aligned_and_not_null(addr, align, zero_size)
|
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
|
||||||
);
|
);
|
||||||
write_bytes(dst, val, count)
|
write_bytes(dst, val, count)
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,7 @@
|
|||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![cfg_attr(bootstrap, feature(const_exact_div))]
|
#![cfg_attr(bootstrap, feature(const_exact_div))]
|
||||||
#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
|
#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
|
||||||
|
#![cfg_attr(bootstrap, feature(const_ub_checks))]
|
||||||
#![feature(array_ptr_get)]
|
#![feature(array_ptr_get)]
|
||||||
#![feature(asm_experimental_arch)]
|
#![feature(asm_experimental_arch)]
|
||||||
#![feature(const_align_of_val)]
|
#![feature(const_align_of_val)]
|
||||||
@ -121,7 +122,6 @@
|
|||||||
#![feature(const_heap)]
|
#![feature(const_heap)]
|
||||||
#![feature(const_nonnull_new)]
|
#![feature(const_nonnull_new)]
|
||||||
#![feature(const_pin_2)]
|
#![feature(const_pin_2)]
|
||||||
#![feature(const_ptr_is_null)]
|
|
||||||
#![feature(const_ptr_sub_ptr)]
|
#![feature(const_ptr_sub_ptr)]
|
||||||
#![feature(const_raw_ptr_comparison)]
|
#![feature(const_raw_ptr_comparison)]
|
||||||
#![feature(const_size_of_val)]
|
#![feature(const_size_of_val)]
|
||||||
@ -132,7 +132,6 @@
|
|||||||
#![feature(const_type_id)]
|
#![feature(const_type_id)]
|
||||||
#![feature(const_type_name)]
|
#![feature(const_type_name)]
|
||||||
#![feature(const_typed_swap)]
|
#![feature(const_typed_swap)]
|
||||||
#![feature(const_ub_checks)]
|
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(coverage_attribute)]
|
#![feature(coverage_attribute)]
|
||||||
#![feature(do_not_recommend)]
|
#![feature(do_not_recommend)]
|
||||||
|
@ -29,16 +29,18 @@ impl<T: ?Sized> *const T {
|
|||||||
/// assert!(!ptr.is_null());
|
/// assert!(!ptr.is_null());
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_diagnostic_item = "ptr_const_is_null"]
|
#[rustc_diagnostic_item = "ptr_const_is_null"]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
pub const fn is_null(self) -> bool {
|
pub const fn is_null(self) -> bool {
|
||||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||||
// considering their "data" part for null-ness.
|
// considering their "data" part for null-ness.
|
||||||
let ptr = self as *const u8;
|
let ptr = self as *const u8;
|
||||||
const_eval_select!(
|
const_eval_select!(
|
||||||
@capture { ptr: *const u8 } -> bool:
|
@capture { ptr: *const u8 } -> bool:
|
||||||
if const #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] {
|
// This use of `const_raw_ptr_comparison` has been explicitly blessed by t-lang.
|
||||||
|
if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] {
|
||||||
match (ptr).guaranteed_eq(null_mut()) {
|
match (ptr).guaranteed_eq(null_mut()) {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
// To remain maximally convervative, we stop execution when we don't
|
// To remain maximally convervative, we stop execution when we don't
|
||||||
@ -280,7 +282,7 @@ impl<T: ?Sized> *const T {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
||||||
// SAFETY: the caller must guarantee that `self` is valid
|
// SAFETY: the caller must guarantee that `self` is valid
|
||||||
|
@ -1103,9 +1103,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
|||||||
count: usize = count,
|
count: usize = count,
|
||||||
) => {
|
) => {
|
||||||
let zero_size = size == 0 || count == 0;
|
let zero_size = size == 0 || count == 0;
|
||||||
ub_checks::is_aligned_and_not_null(x, align, zero_size)
|
ub_checks::maybe_is_aligned_and_not_null(x, align, zero_size)
|
||||||
&& ub_checks::is_aligned_and_not_null(y, align, zero_size)
|
&& ub_checks::maybe_is_aligned_and_not_null(y, align, zero_size)
|
||||||
&& ub_checks::is_nonoverlapping(x, y, size, count)
|
&& ub_checks::maybe_is_nonoverlapping(x, y, size, count)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1216,7 +1216,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
|
|||||||
addr: *const () = dst as *const (),
|
addr: *const () = dst as *const (),
|
||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
is_zst: bool = T::IS_ZST,
|
is_zst: bool = T::IS_ZST,
|
||||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||||
);
|
);
|
||||||
mem::replace(&mut *dst, src)
|
mem::replace(&mut *dst, src)
|
||||||
}
|
}
|
||||||
@ -1369,7 +1369,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
|
|||||||
addr: *const () = src as *const (),
|
addr: *const () = src as *const (),
|
||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
is_zst: bool = T::IS_ZST,
|
is_zst: bool = T::IS_ZST,
|
||||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||||
);
|
);
|
||||||
crate::intrinsics::read_via_copy(src)
|
crate::intrinsics::read_via_copy(src)
|
||||||
}
|
}
|
||||||
@ -1573,7 +1573,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
|
|||||||
addr: *mut () = dst as *mut (),
|
addr: *mut () = dst as *mut (),
|
||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
is_zst: bool = T::IS_ZST,
|
is_zst: bool = T::IS_ZST,
|
||||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||||
);
|
);
|
||||||
intrinsics::write_via_move(dst, src)
|
intrinsics::write_via_move(dst, src)
|
||||||
}
|
}
|
||||||
@ -1745,7 +1745,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
|||||||
addr: *const () = src as *const (),
|
addr: *const () = src as *const (),
|
||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
is_zst: bool = T::IS_ZST,
|
is_zst: bool = T::IS_ZST,
|
||||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||||
);
|
);
|
||||||
intrinsics::volatile_load(src)
|
intrinsics::volatile_load(src)
|
||||||
}
|
}
|
||||||
@ -1825,7 +1825,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
|
|||||||
addr: *mut () = dst as *mut (),
|
addr: *mut () = dst as *mut (),
|
||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
is_zst: bool = T::IS_ZST,
|
is_zst: bool = T::IS_ZST,
|
||||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||||
);
|
);
|
||||||
intrinsics::volatile_store(dst, src);
|
intrinsics::volatile_store(dst, src);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ impl<T: ?Sized> *mut T {
|
|||||||
/// assert!(!ptr.is_null());
|
/// assert!(!ptr.is_null());
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_diagnostic_item = "ptr_is_null"]
|
#[rustc_diagnostic_item = "ptr_is_null"]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_null(self) -> bool {
|
pub const fn is_null(self) -> bool {
|
||||||
@ -271,7 +271,7 @@ impl<T: ?Sized> *mut T {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
||||||
// SAFETY: the caller must guarantee that `self` is valid for a
|
// SAFETY: the caller must guarantee that `self` is valid for a
|
||||||
@ -619,7 +619,7 @@ impl<T: ?Sized> *mut T {
|
|||||||
/// println!("{s:?}"); // It'll print: "[4, 2, 3]".
|
/// println!("{s:?}"); // It'll print: "[4, 2, 3]".
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
|
pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
|
||||||
// SAFETY: the caller must guarantee that `self` is be valid for
|
// SAFETY: the caller must guarantee that `self` is be valid for
|
||||||
|
@ -132,7 +132,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
|
|||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
len: usize = len,
|
len: usize = len,
|
||||||
) =>
|
) =>
|
||||||
ub_checks::is_aligned_and_not_null(data, align, false)
|
ub_checks::maybe_is_aligned_and_not_null(data, align, false)
|
||||||
&& ub_checks::is_valid_allocation_size(size, len)
|
&& ub_checks::is_valid_allocation_size(size, len)
|
||||||
);
|
);
|
||||||
&*ptr::slice_from_raw_parts(data, len)
|
&*ptr::slice_from_raw_parts(data, len)
|
||||||
@ -186,7 +186,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
|
|||||||
align: usize = align_of::<T>(),
|
align: usize = align_of::<T>(),
|
||||||
len: usize = len,
|
len: usize = len,
|
||||||
) =>
|
) =>
|
||||||
ub_checks::is_aligned_and_not_null(data, align, false)
|
ub_checks::maybe_is_aligned_and_not_null(data, align, false)
|
||||||
&& ub_checks::is_valid_allocation_size(size, len)
|
&& ub_checks::is_valid_allocation_size(size, len)
|
||||||
);
|
);
|
||||||
&mut *ptr::slice_from_raw_parts_mut(data, len)
|
&mut *ptr::slice_from_raw_parts_mut(data, len)
|
||||||
|
@ -64,8 +64,6 @@ macro_rules! assert_unsafe_precondition {
|
|||||||
#[rustc_no_mir_inline]
|
#[rustc_no_mir_inline]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
|
|
||||||
#[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks
|
|
||||||
const fn precondition_check($($name:$ty),*) {
|
const fn precondition_check($($name:$ty),*) {
|
||||||
if !$e {
|
if !$e {
|
||||||
::core::panicking::panic_nounwind(
|
::core::panicking::panic_nounwind(
|
||||||
@ -116,12 +114,16 @@ pub(crate) const fn check_language_ub() -> bool {
|
|||||||
/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
|
/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
|
||||||
/// check is anyway not executed in `const`.
|
/// check is anyway not executed in `const`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
|
pub(crate) const fn maybe_is_aligned_and_not_null(
|
||||||
|
ptr: *const (),
|
||||||
|
align: usize,
|
||||||
|
is_zst: bool,
|
||||||
|
) -> bool {
|
||||||
// This is just for safety checks so we can const_eval_select.
|
// This is just for safety checks so we can const_eval_select.
|
||||||
const_eval_select!(
|
const_eval_select!(
|
||||||
@capture { ptr: *const (), align: usize, is_zst: bool } -> bool:
|
@capture { ptr: *const (), align: usize, is_zst: bool } -> bool:
|
||||||
if const #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] {
|
if const {
|
||||||
is_zst || !ptr.is_null()
|
is_zst || !ptr.is_null()
|
||||||
} else {
|
} else {
|
||||||
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
|
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
|
||||||
@ -141,8 +143,8 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
|
|||||||
/// Note that in const-eval this function just returns `true` and therefore must
|
/// Note that in const-eval this function just returns `true` and therefore must
|
||||||
/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
|
/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
pub(crate) const fn is_nonoverlapping(
|
pub(crate) const fn maybe_is_nonoverlapping(
|
||||||
src: *const (),
|
src: *const (),
|
||||||
dst: *const (),
|
dst: *const (),
|
||||||
size: usize,
|
size: usize,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![feature(const_ptr_is_null)]
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
const IS_NULL: () = {
|
const IS_NULL: () = {
|
||||||
|
@ -8,7 +8,7 @@ note: inside `std::ptr::const_ptr::<impl *const T>::is_null::compiletime`
|
|||||||
note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
|
note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
|
||||||
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||||
note: inside `MAYBE_NULL`
|
note: inside `MAYBE_NULL`
|
||||||
--> $DIR/const-ptr-is-null.rs:17:14
|
--> $DIR/const-ptr-is-null.rs:16:14
|
||||||
|
|
|
|
||||||
LL | assert!(!ptr.wrapping_sub(512).is_null());
|
LL | assert!(!ptr.wrapping_sub(512).is_null());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//@ compile-flags: --crate-type=lib
|
//@ compile-flags: --crate-type=lib
|
||||||
//@ check-pass
|
//@ check-pass
|
||||||
|
|
||||||
#![feature(const_ptr_is_null)]
|
|
||||||
#![allow(useless_ptr_null_checks)]
|
#![allow(useless_ptr_null_checks)]
|
||||||
|
|
||||||
const FOO: &usize = &42;
|
const FOO: &usize = &42;
|
||||||
|
Loading…
Reference in New Issue
Block a user