Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A way forward for pointer equality in const eval #73398

Merged
merged 7 commits into from
Jun 23, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/liballoc/raw_vec.rs
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ impl<T> RawVec<T, Global> {
/// `#[rustc_force_min_const_fn]` attribute which requires conformance
/// with `min_const_fn` but does not necessarily allow calling it in
/// `stable(...) const fn` / user code not enabling `foo` when
/// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
/// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present.
pub const NEW: Self = Self::new();

/// Creates the biggest possible `RawVec` (on the system heap)
16 changes: 13 additions & 3 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -1012,7 +1012,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`std::any::type_name`](../../std/any/fn.type_name.html)
#[rustc_const_unstable(feature = "const_type_name", issue = "none")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub fn type_name<T: ?Sized>() -> &'static str;

/// Gets an identifier which is globally unique to the specified type. This
@@ -1021,7 +1021,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
#[rustc_const_unstable(feature = "const_type_id", issue = "none")]
#[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
pub fn type_id<T: ?Sized + 'static>() -> u64;

/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@@ -1931,7 +1931,7 @@ extern "rust-intrinsic" {
pub fn nontemporal_store<T>(ptr: *mut T, val: T);

/// See documentation of `<*const T>::offset_from` for details.
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "none")]
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;

/// Internal hook used by Miri to implement unwinding.
@@ -1948,6 +1948,16 @@ extern "rust-intrinsic" {
#[cfg(not(bootstrap))]
#[lang = "count_code_region"]
pub fn count_code_region(index: u32);

/// See documentation of `<*const T>::guaranteed_eq` for details.
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[cfg(not(bootstrap))]
pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;

/// See documentation of `<*const T>::guaranteed_ne` for details.
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[cfg(not(bootstrap))]
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
}

// Some functions are defined here because they accidentally got made
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@
#![feature(const_generics)]
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
#![feature(const_result)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_slice_ptr_len)]
66 changes: 66 additions & 0 deletions src/libcore/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
@@ -295,6 +295,72 @@ impl<T: ?Sized> *const T {
intrinsics::ptr_offset_from(self, origin)
}

/// Returns whether two pointers are guaranteed to be equal.
///
/// At runtime this function behaves like `self == other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine equality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be equal.
/// But when it returns `true`, the pointers are guaranteed to be equal.
///
/// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_ne`]: #method.guaranteed_ne
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can unsafe code rely on a return value of true (similar to relying on std::mem::needs_drop returning false)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it can. The comment says

But when it returns true, the pointers are guaranteed to be equal.

I thought that was clear enough?

/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const fn guaranteed_eq(self, other: *const T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_eq(self, other)
}

/// Returns whether two pointers are guaranteed to be inequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be inequal.
/// But when it returns `true`, the pointers are guaranteed to be inequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_eq`]: #method.guaranteed_eq
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const fn guaranteed_ne(self, other: *const T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_ne(self, other)
}

/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
66 changes: 66 additions & 0 deletions src/libcore/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
@@ -273,6 +273,72 @@ impl<T: ?Sized> *mut T {
if self.is_null() { None } else { Some(&mut *self) }
}

/// Returns whether two pointers are guaranteed to be equal.
///
/// At runtime this function behaves like `self == other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine equality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be equal.
/// But when it returns `true`, the pointers are guaranteed to be equal.
///
/// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_ne`]: #method.guaranteed_ne
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const fn guaranteed_eq(self, other: *mut T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
}

/// Returns whether two pointers are guaranteed to be inequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
/// spuriously return `false` for pointers that later actually turn out to be inequal.
/// But when it returns `true`, the pointers are guaranteed to be inequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
///
/// [`guaranteed_eq`]: #method.guaranteed_eq
///
/// The return value may change depending on the compiler version and unsafe code may not
/// rely on the result of this function for soundness. It is suggested to only use this function
/// for performance optimizations where spurious `false` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
/// differences, and it should also not be stabilized before we have a better understanding
/// of this issue.
/// ```
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
#[cfg(not(bootstrap))]
pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
where
T: Sized,
{
intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
}

/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
17 changes: 17 additions & 0 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
@@ -5956,10 +5956,18 @@ where
return false;
}

#[cfg(bootstrap)]
if self.as_ptr() == other.as_ptr() {
return true;
}

// While performance would suffer if `guaranteed_eq` just returned `false`
// for all arguments, correctness and return value of this function are not affected.
#[cfg(not(bootstrap))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this changed? This function is not const.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet, we're working towards that. I have a local branch where I'm trying to run this in -Zunleash-the-miri-inside-of-you mode.

if self.as_ptr().guaranteed_eq(other.as_ptr()) {
return true;
}

self.iter().zip(other.iter()).all(|(x, y)| x == y)
}
}
@@ -5973,9 +5981,18 @@ where
if self.len() != other.len() {
return false;
}

#[cfg(bootstrap)]
if self.as_ptr() == other.as_ptr() {
return true;
}

// While performance would suffer if `guaranteed_eq` just returned `false`
// for all arguments, correctness and return value of this function are not affected.
#[cfg(not(bootstrap))]
if self.as_ptr().guaranteed_eq(other.as_ptr()) {
return true;
}
unsafe {
let size = mem::size_of_val(self);
memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
12 changes: 11 additions & 1 deletion src/librustc_codegen_llvm/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ use log::debug;
use rustc_ast::ast;
use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::glue;
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -731,6 +731,16 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
return;
}

"ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
let a = args[0].immediate();
let b = args[1].immediate();
if name == "ptr_guaranteed_eq" {
self.icmp(IntPredicate::IntEQ, a, b)
} else {
self.icmp(IntPredicate::IntNE, a, b)
}
}

"ptr_offset_from" => {
let ty = substs.type_at(0);
let pointee_size = self.size_of(ty);
3 changes: 0 additions & 3 deletions src/librustc_feature/active.rs
Original file line number Diff line number Diff line change
@@ -401,9 +401,6 @@ declare_features! (
/// Allows dereferencing raw pointers during const eval.
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),

/// Allows comparing raw pointers during const eval.
(active, const_compare_raw_pointers, "1.27.0", Some(53020), None),

/// Allows `#[doc(alias = "...")]`.
(active, doc_alias, "1.27.0", Some(50146), None),

5 changes: 5 additions & 0 deletions src/librustc_feature/removed.rs
Original file line number Diff line number Diff line change
@@ -113,6 +113,11 @@ declare_features! (
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
/// Allows `#[no_debug]`.
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),

/// Allows comparing raw pointers during const eval.
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
Some("cannot be allowed in const eval in any meaningful way")),

// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------
5 changes: 5 additions & 0 deletions src/librustc_mir/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -291,6 +291,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
self.write_scalar(offset_ptr, dest)?;
}
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that this implementation will also be used by Miri, which is a bug. Can we somehow make it be used only during CTCE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't miri fall back to this only if it has no own impl? So we can just give miri an impl that behaves differently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Miri prefers the CTFE impls, to make sure we test those properly.

I am working on a PR that adds these to Miri in a way that it prefers its own impls.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it is: rust-lang/miri#1459

// FIXME: return `true` for at least some comparisons where we can reliably
// determine the result of runtime (in)equality tests at compile-time.
self.write_scalar(Scalar::from_bool(false), dest)?;
}
sym::ptr_offset_from => {
let a = self.read_immediate(args[0])?.to_scalar()?;
let b = self.read_immediate(args[1])?.to_scalar()?;
20 changes: 9 additions & 11 deletions src/librustc_mir/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
@@ -284,18 +284,16 @@ impl NonConstOp for Panic {
#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
fn feature_gate() -> Option<Symbol> {
Some(sym::const_compare_raw_pointers)
}

fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
span,
&format!("comparing raw pointers inside {}", ccx.const_kind()),
)
.emit();
let mut err = ccx
.tcx
.sess
.struct_span_err(span, "pointers cannot be reliably compared during const eval.");
err.note(
"see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
for more information",
);
err.emit();
}
}

15 changes: 0 additions & 15 deletions src/librustc_mir/transform/check_unsafety.rs
Original file line number Diff line number Diff line change
@@ -171,21 +171,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
_ => {}
}
}
// raw pointer and fn pointer operations are unsafe as it is not clear whether one
// pointer would be "less" or "equal" to another, because we cannot know where llvm
// or the linker will place various statics in memory. Without this information the
// result of a comparison of addresses would differ between runtime and compile-time.
Rvalue::BinaryOp(_, ref lhs, _)
if self.const_context && self.tcx.features().const_compare_raw_pointers =>
{
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
self.require_unsafe(
"pointer operation",
"operations on pointers in constants",
UnsafetyViolationKind::General,
);
}
}
_ => {}
}
self.super_rvalue(rvalue, location);
2 changes: 2 additions & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
@@ -588,6 +588,8 @@ symbols! {
proc_macro_non_items,
proc_macro_path_invoc,
profiler_runtime,
ptr_guaranteed_eq,
ptr_guaranteed_ne,
ptr_offset_from,
pub_restricted,
pure,
9 changes: 6 additions & 3 deletions src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -74,9 +74,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
| "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
| "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
| "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
| "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => {
hir::Unsafety::Normal
}
| "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
| "maxnumf64" | "type_name" => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
}
@@ -258,6 +257,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
(1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
}

"ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
}

"ptr_offset_from" => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
}
26 changes: 11 additions & 15 deletions src/librustc_typeck/collect/type_of.rs
Original file line number Diff line number Diff line change
@@ -10,8 +10,7 @@ use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits;

@@ -303,25 +302,22 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
if !tcx.features().const_compare_raw_pointers {
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
feature_err(
&tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
tcx.sess
.struct_span_err(
hir_ty.span,
&format!(
"using {} as const generic parameters is unstable",
"using {} as const generic parameters is forbidden",
unsupported_type
),
)
.emit();
};
}
};
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
{
7 changes: 3 additions & 4 deletions src/test/ui/const-generics/fn-const-param-call.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
// run-pass

#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete

fn function() -> u32 {
17
}

struct Wrapper<const F: fn() -> u32>;
struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters

impl<const F: fn() -> u32> Wrapper<F> {
//~^ ERROR: using function pointers as const generic parameters
fn call() -> u32 {
F()
}
18 changes: 15 additions & 3 deletions src/test/ui/const-generics/fn-const-param-call.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/fn-const-param-call.rs:3:12
--> $DIR/fn-const-param-call.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information

warning: 1 warning emitted
error: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:8:25
|
LL | struct Wrapper<const F: fn() -> u32>;
| ^^^^^^^^^^^

error: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:10:15
|
LL | impl<const F: fn() -> u32> Wrapper<F> {
| ^^^^^^^^^^^

error: aborting due to 2 previous errors; 1 warning emitted

11 changes: 6 additions & 5 deletions src/test/ui/const-generics/fn-const-param-infer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete

struct Checked<const F: fn(usize) -> bool>;
//~^ ERROR: using function pointers as const generic parameters

fn not_one(val: usize) -> bool { val != 1 }
fn not_two(val: usize) -> bool { val != 2 }
@@ -13,14 +14,14 @@ fn generic<T>(val: usize) -> bool { val != 1 }
fn main() {
let _: Option<Checked<not_one>> = None;
let _: Checked<not_one> = Checked::<not_one>;
let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types
let _: Checked<not_one> = Checked::<not_two>;

let _ = Checked::<generic_arg>;
let _ = Checked::<{generic_arg::<usize>}>;
let _ = Checked::<{generic_arg::<u32>}>; //~ mismatched types
let _ = Checked::<{generic_arg::<u32>}>;

let _ = Checked::<generic>; //~ type annotations needed
let _ = Checked::<generic>;
let _ = Checked::<{generic::<u16>}>;
let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
}
41 changes: 6 additions & 35 deletions src/test/ui/const-generics/fn-const-param-infer.stderr
Original file line number Diff line number Diff line change
@@ -1,46 +1,17 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/fn-const-param-infer.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information

error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:16:31
error: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-infer.rs:4:25
|
LL | let _: Checked<not_one> = Checked::<not_two>;
| ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
|
= note: expected type `{not_one as fn(usize) -> bool}`
found type `{not_two as fn(usize) -> bool}`

error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:20:24
|
LL | let _ = Checked::<{generic_arg::<u32>}>;
| ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32`
|
= note: expected fn pointer `fn(usize) -> _`
found fn item `fn(u32) -> _ {generic_arg::<u32>}`

error[E0282]: type annotations needed
--> $DIR/fn-const-param-infer.rs:22:23
|
LL | let _ = Checked::<generic>;
| ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic`

error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:25:40
|
LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
|
= note: expected type `{generic::<u32> as fn(usize) -> bool}`
found type `{generic::<u16> as fn(usize) -> bool}`
LL | struct Checked<const F: fn(usize) -> bool>;
| ^^^^^^^^^^^^^^^^^

error: aborting due to 4 previous errors; 1 warning emitted
error: aborting due to previous error; 1 warning emitted

Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
7 changes: 3 additions & 4 deletions src/test/ui/const-generics/raw-ptr-const-param-deref.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// run-pass
#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete

const A: u32 = 3;

struct Const<const P: *const u32>;
struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters

impl<const P: *const u32> Const<P> {
impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters
fn get() -> u32 {
unsafe {
*P
18 changes: 15 additions & 3 deletions src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/raw-ptr-const-param-deref.rs:2:12
--> $DIR/raw-ptr-const-param-deref.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information

warning: 1 warning emitted
error: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:6:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^

error: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:8:15
|
LL | impl<const P: *const u32> Const<P> {
| ^^^^^^^^^^

error: aborting due to 2 previous errors; 1 warning emitted

6 changes: 3 additions & 3 deletions src/test/ui/const-generics/raw-ptr-const-param.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![feature(const_generics, const_compare_raw_pointers)]
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete

struct Const<const P: *const u32>;
struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters

fn main() {
let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types
let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>;
}
14 changes: 5 additions & 9 deletions src/test/ui/const-generics/raw-ptr-const-param.stderr
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/raw-ptr-const-param.rs:1:12
|
LL | #![feature(const_generics, const_compare_raw_pointers)]
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information

error[E0308]: mismatched types
--> $DIR/raw-ptr-const-param.rs:7:40
error: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param.rs:4:23
|
LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
|
= note: expected type `{0xf as *const u32}`
found type `{0xa as *const u32}`
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0308`.
15 changes: 2 additions & 13 deletions src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]

fn main() {}

// unconst and bad, will thus error in miri
const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
// unconst and bad, will thus error in miri
const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR any use of this
// unconst and fine
const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
// unconst and bad, will thus error in miri
const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
// unconst and fine
const Z: i32 = unsafe { *(&1 as *const i32) };
const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
// unconst and bad, will thus error in miri
const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably
44 changes: 9 additions & 35 deletions src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
Original file line number Diff line number Diff line change
@@ -1,44 +1,18 @@
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:6:26
error: pointers cannot be reliably compared during const eval.
--> $DIR/const_raw_ptr_ops.rs:4:26
|
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
| -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
| |
| "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[deny(const_err)]` on by default
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information

error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:8:27
error: pointers cannot be reliably compared during const eval.
--> $DIR/const_raw_ptr_ops.rs:6:27
|
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
| --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
| |
| "pointer arithmetic or comparison" needs an rfc before being allowed inside constants

error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:12:28
|
LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
| ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
| |
| "pointer-to-integer cast" needs an rfc before being allowed inside constants

error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:16:26
|
LL | const Z2: i32 = unsafe { *(42 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer

error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:17:26
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
LL | const Z3: i32 = unsafe { *(44 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information

error: aborting due to 5 previous errors
error: aborting due to 2 previous errors

13 changes: 13 additions & 0 deletions src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]

fn main() {}

// unconst and fine
const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
// unconst and bad, will thus error in miri
const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
// unconst and fine
const Z: i32 = unsafe { *(&1 as *const i32) };
// unconst and bad, will thus error in miri
const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
28 changes: 28 additions & 0 deletions src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops2.rs:8:28
|
LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
| ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
| |
| "pointer-to-integer cast" needs an rfc before being allowed inside constants
|
= note: `#[deny(const_err)]` on by default

error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops2.rs:12:26
|
LL | const Z2: i32 = unsafe { *(42 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer

error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops2.rs:13:26
|
LL | const Z3: i32 = unsafe { *(44 as *const i32) };
| -------------------------^^^^^^^^^^^^^^^^^^^---
| |
| unable to turn bytes into a pointer

error: aborting due to 3 previous errors

2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]

fn main() {
let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
2 changes: 1 addition & 1 deletion src/test/ui/consts/miri_unleashed/ptr_arith.stderr
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ LL | let _v = x + 0;

warning: skipping const checks
|
help: skipping check for `const_compare_raw_pointers` feature
help: skipping check that does not even have a feature gate
--> $DIR/ptr_arith.rs:9:14
|
LL | let _v = x == x;
17 changes: 17 additions & 0 deletions src/test/ui/consts/miri_unleashed/slice_eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
// run-pass

#![feature(const_raw_ptr_comparison)]

const EMPTY_SLICE: &[i32] = &[];
const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);

fn main() {
assert!(!EMPTY_EQ);
assert!(!EMPTY_EQ2);
assert!(!EMPTY_NE);
assert!(!EMPTY_NE2);
}
4 changes: 1 addition & 3 deletions src/test/ui/error-codes/E0395.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// gate-test-const_compare_raw_pointers

static FOO: i32 = 42;
static BAR: i32 = 42;

static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
//~^ ERROR comparing raw pointers inside static
//~^ ERROR pointers cannot be reliably compared during const eval

fn main() {
}
6 changes: 2 additions & 4 deletions src/test/ui/error-codes/E0395.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
error[E0658]: comparing raw pointers inside static
--> $DIR/E0395.rs:6:29
error: pointers cannot be reliably compared during const eval.
--> $DIR/E0395.rs:4:29
|
LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
4 changes: 2 additions & 2 deletions src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
struct ConstFn<const F: fn()>;
//~^ ERROR const generics are unstable
//~^^ ERROR using function pointers as const generic parameters is unstable
//~^^ ERROR using function pointers as const generic parameters is forbidden

struct ConstPtr<const P: *const u32>;
//~^ ERROR const generics are unstable
//~^^ ERROR using raw pointers as const generic parameters is unstable
//~^^ ERROR using raw pointers as const generic parameters is forbidden

fn main() {}
10 changes: 2 additions & 8 deletions src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
Original file line number Diff line number Diff line change
@@ -16,23 +16,17 @@ LL | struct ConstPtr<const P: *const u32>;
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
= help: add `#![feature(const_generics)]` to the crate attributes to enable

error[E0658]: using function pointers as const generic parameters is unstable
error: using function pointers as const generic parameters is forbidden
--> $DIR/feature-gate-const_generics-ptr.rs:1:25
|
LL | struct ConstFn<const F: fn()>;
| ^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable

error[E0658]: using raw pointers as const generic parameters is unstable
error: using raw pointers as const generic parameters is forbidden
--> $DIR/feature-gate-const_generics-ptr.rs:5:26
|
LL | struct ConstPtr<const P: *const u32>;
| ^^^^^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable

error: aborting due to 4 previous errors

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-25826.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn id<T>(t: T) -> T { t }
fn main() {
const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
//~^ ERROR comparing raw pointers inside constant
//~^ ERROR pointers cannot be reliably compared during const eval
println!("{}", A);
}
4 changes: 1 addition & 3 deletions src/test/ui/issues/issue-25826.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
error[E0658]: comparing raw pointers inside constant
error: pointers cannot be reliably compared during const eval.
--> $DIR/issue-25826.rs:3:30
|
LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
8 changes: 4 additions & 4 deletions src/test/ui/unsafe/unsafe-unstable-const-fn.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#![stable(feature = "foo", since = "1.33.0")]
#![feature(staged_api)]
#![feature(const_compare_raw_pointers)]
#![feature(const_raw_ptr_deref)]
#![feature(const_fn)]

#[stable(feature = "foo", since = "1.33.0")]
#[rustc_const_unstable(feature = "const_foo", issue = "none")]
const fn unstable(a: *const i32, b: *const i32) -> bool {
a == b
//~^ pointer operation is unsafe
const fn unstable(a: *const i32, b: i32) -> bool {
*a == b
//~^ dereference of raw pointer is unsafe
}

fn main() {}
8 changes: 4 additions & 4 deletions src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0133]: pointer operation is unsafe and requires unsafe function or block
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
--> $DIR/unsafe-unstable-const-fn.rs:9:5
|
LL | a == b
| ^^^^^^ pointer operation
LL | *a == b
| ^^ dereference of raw pointer
|
= note: operations on pointers in constants
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior

error: aborting due to previous error

5 changes: 1 addition & 4 deletions src/tools/tidy/src/features.rs
Original file line number Diff line number Diff line change
@@ -444,10 +444,7 @@ fn map_lib_features(
level: Status::Unstable,
since: None,
has_gate_test: false,
// FIXME(#57563): #57563 is now used as a common tracking issue,
// although we would like to have specific tracking issues for each
// `rustc_const_unstable` in the future.
tracking_issue: NonZeroU32::new(57563),
tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none),
};
mf(Ok((feature_name, feature)), file, i + 1);
continue;