From 9245ba83047b14fc7c9cef4c7d2bf37828c445b6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 12 Jun 2020 19:25:14 +0200 Subject: [PATCH 1/7] Remove the const_raw_ptr_comparison feature gate. We can never supply a meaningful implementation of this. Instead, the follow up commits will create two intrinsics that approximate comparisons: * `ptr_maybe_eq` * `ptr_maybe_ne` The fact that `ptr_maybe_eq(a, b)` is not necessarily the same value as `!ptr_maybe_ne(a, b)` is a symptom of this entire problem. --- src/librustc_feature/active.rs | 3 -- src/librustc_feature/removed.rs | 5 ++ .../transform/check_consts/ops.rs | 26 +++++++---- src/librustc_mir/transform/check_unsafety.rs | 15 ------ src/librustc_typeck/collect/type_of.rs | 26 +++++------ .../ui/const-generics/fn-const-param-call.rs | 7 ++- .../const-generics/fn-const-param-call.stderr | 18 ++++++-- .../ui/const-generics/fn-const-param-infer.rs | 11 +++-- .../fn-const-param-infer.stderr | 41 +++-------------- .../raw-ptr-const-param-deref.rs | 7 ++- .../raw-ptr-const-param-deref.stderr | 18 ++++++-- .../ui/const-generics/raw-ptr-const-param.rs | 6 +-- .../const-generics/raw-ptr-const-param.stderr | 14 ++---- .../ui/consts/const-eval/const_raw_ptr_ops.rs | 15 +----- .../const-eval/const_raw_ptr_ops.stderr | 46 +++++-------------- .../consts/const-eval/const_raw_ptr_ops2.rs | 13 ++++++ .../const-eval/const_raw_ptr_ops2.stderr | 28 +++++++++++ .../consts/const-eval/promoted_raw_ptr_ops.rs | 2 +- .../ui/consts/miri_unleashed/ptr_arith.stderr | 2 +- src/test/ui/error-codes/E0395.rs | 4 +- src/test/ui/error-codes/E0395.stderr | 9 ++-- .../feature-gate-const_generics-ptr.rs | 4 +- .../feature-gate-const_generics-ptr.stderr | 10 +--- src/test/ui/issues/issue-25826.rs | 2 +- src/test/ui/issues/issue-25826.stderr | 7 ++- .../ui/unsafe/unsafe-unstable-const-fn.rs | 8 ++-- .../ui/unsafe/unsafe-unstable-const-fn.stderr | 8 ++-- 27 files changed, 165 insertions(+), 190 deletions(-) create mode 100644 src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs create mode 100644 src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index d186f35a12b5a..f167ed97f57e2 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -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), diff --git a/src/librustc_feature/removed.rs b/src/librustc_feature/removed.rs index 4e348054fbd4b..8d410894e8b19 100644 --- a/src/librustc_feature/removed.rs +++ b/src/librustc_feature/removed.rs @@ -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 // ------------------------------------------------------------------------- diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index d5059c98c9511..f09b598ce069d 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -284,18 +284,24 @@ impl NonConstOp for Panic { #[derive(Debug)] pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { - fn feature_gate() -> Option { - 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, + let mut err = ccx.tcx.sess.struct_span_err( span, - &format!("comparing raw pointers inside {}", ccx.const_kind()), - ) - .emit(); + "pointers cannot be compared in a meaningful way during const eval.", + ); + err.note( + "It is conceptually impossible for const eval to know in all cases whether two \ + pointers are equal. While sometimes it is clear (the address of a static item \ + is never equal to the address of another static item), comparing an integer \ + address with any allocation's address is impossible to do at compile-time.", + ); + err.note( + "That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all \ + comparisons where CTFE isn't sure whether two addresses are equal. The mirror \ + intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't \ + sure whether two addresses are inequal.", + ); + err.emit(); } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 7dbb2ebad8b99..ac7acff1eca9e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -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); diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index cf5f2ec69d8d8..3dd9c9c5c39db 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -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() { diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs index afa577fa67ff2..90c438b05cb81 100644 --- a/src/test/ui/const-generics/fn-const-param-call.rs +++ b/src/test/ui/const-generics/fn-const-param-call.rs @@ -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 u32>; +struct Wrapper u32>; //~ ERROR: using function pointers as const generic parameters impl u32> Wrapper { +//~^ ERROR: using function pointers as const generic parameters fn call() -> u32 { F() } diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr index 9c0f7e3ab9b87..b5811243caa8a 100644 --- a/src/test/ui/const-generics/fn-const-param-call.stderr +++ b/src/test/ui/const-generics/fn-const-param-call.stderr @@ -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 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 u32>; + | ^^^^^^^^^^^ + +error: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-call.rs:10:15 + | +LL | impl u32> Wrapper { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs index 08f6e0db31cae..14fa3b494b3fc 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.rs +++ b/src/test/ui/const-generics/fn-const-param-infer.rs @@ -1,7 +1,8 @@ -#![feature(const_generics, const_compare_raw_pointers)] +#![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete struct Checked 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(val: usize) -> bool { val != 1 } fn main() { let _: Option> = None; let _: Checked = Checked::; - let _: Checked = Checked::; //~ mismatched types + let _: Checked = Checked::; let _ = Checked::; let _ = Checked::<{generic_arg::}>; - let _ = Checked::<{generic_arg::}>; //~ mismatched types + let _ = Checked::<{generic_arg::}>; - let _ = Checked::; //~ type annotations needed + let _ = Checked::; let _ = Checked::<{generic::}>; let _: Checked<{generic::}> = Checked::<{generic::}>; - let _: Checked<{generic::}> = Checked::<{generic::}>; //~ mismatched types + let _: Checked<{generic::}> = Checked::<{generic::}>; } diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index de41d2984a655..7aaa41eb7d7b1 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -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 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 = Checked::; - | ^^^^^^^^^^^^^^^^^^ 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::}>; - | ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32` - | - = note: expected fn pointer `fn(usize) -> _` - found fn item `fn(u32) -> _ {generic_arg::}` - -error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:22:23 - | -LL | let _ = Checked::; - | ^^^^^^^ 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::}> = Checked::<{generic::}>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic:: as fn(usize) -> bool}`, found `{generic:: as fn(usize) -> bool}` - | - = note: expected type `{generic:: as fn(usize) -> bool}` - found type `{generic:: as fn(usize) -> bool}` +LL | struct Checked 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`. diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs index c498bfe2e9781..97ca9d6a44c9e 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs @@ -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; +struct Const; //~ ERROR: using raw pointers as const generic parameters -impl Const

{ +impl Const

{ //~ ERROR: using raw pointers as const generic parameters fn get() -> u32 { unsafe { *P diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr index 1ffc63ffdac03..1ce8bb9c05423 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr @@ -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 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; + | ^^^^^^^^^^ + +error: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param-deref.rs:8:15 + | +LL | impl Const

{ + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs index d7d970e952b65..237b410e073d6 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param.rs @@ -1,9 +1,9 @@ -#![feature(const_generics, const_compare_raw_pointers)] +#![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete -struct Const; +struct Const; //~ 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 _ }>; } diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr index 7a665397c1207..6e64f8a327fd5 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -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 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; + | ^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs index 9be1374f85d99..91c4bc8972ca5 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -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 compared // 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 compared diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index cc40728e6b574..dee555beca0ca 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -1,44 +1,20 @@ -error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:6:26 +error: pointers cannot be compared in a meaningful way 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: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. -error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:8:27 +error: pointers cannot be compared in a meaningful way 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: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs new file mode 100644 index 0000000000000..d2a7623837a23 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs @@ -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 diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr new file mode 100644 index 0000000000000..93f2261745d6f --- /dev/null +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -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 + diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs index c6fb5eeab5aec..d724fe3060b21 100644 --- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs @@ -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); diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr index 4b3fe9957002e..c5d136ea97dfa 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -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; diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs index bbefff27d7f68..28fba1d306139 100644 --- a/src/test/ui/error-codes/E0395.rs +++ b/src/test/ui/error-codes/E0395.rs @@ -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 compared in a meaningful way during const eval fn main() { } diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 20c8622f33726..748126f74407c 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -1,12 +1,11 @@ -error[E0658]: comparing raw pointers inside static - --> $DIR/E0395.rs:6:29 +error: pointers cannot be compared in a meaningful way 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 for more information - = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs index 1ab11ce3b4423..dc602ba7e6f21 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs @@ -1,9 +1,9 @@ struct ConstFn; //~^ 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; //~^ 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() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr index dc7ef55e7ab99..b2c96d3810f98 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -16,23 +16,17 @@ LL | struct ConstPtr; = note: see issue #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; | ^^^^ - | - = note: see issue #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; | ^^^^^^^^^^ - | - = note: see issue #53020 for more information - = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-25826.rs b/src/test/ui/issues/issue-25826.rs index 36a69cf4c22ff..cb0dfcfa953e4 100644 --- a/src/test/ui/issues/issue-25826.rs +++ b/src/test/ui/issues/issue-25826.rs @@ -1,6 +1,6 @@ fn id(t: T) -> T { t } fn main() { const A: bool = unsafe { id:: as *const () < id:: as *const () }; - //~^ ERROR comparing raw pointers inside constant + //~^ ERROR pointers cannot be compared in a meaningful way during const eval println!("{}", A); } diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index 3a5a6b509ba9d..b3692098341e7 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -1,12 +1,11 @@ -error[E0658]: comparing raw pointers inside constant +error: pointers cannot be compared in a meaningful way during const eval. --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #53020 for more information - = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs index d9d85ee913266..963d892931a75 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs @@ -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() {} diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr index d8f3737c8f541..4642a7a5fc9f8 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr @@ -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 From e09b62033926dff8bfedca35b93e0dfbf767749f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 16 Jun 2020 10:37:34 +0200 Subject: [PATCH 2/7] Add fuzzy pointer comparison intrinsics --- src/libcore/intrinsics.rs | 10 +++ src/libcore/lib.rs | 1 + src/libcore/ptr/const_ptr.rs | 66 +++++++++++++++++++ src/libcore/ptr/mut_ptr.rs | 66 +++++++++++++++++++ src/libcore/slice/mod.rs | 50 +++++++++++++- src/librustc_codegen_llvm/intrinsic.rs | 14 +++- src/librustc_mir/interpret/intrinsics.rs | 5 ++ .../transform/check_consts/ops.rs | 22 ++++--- src/librustc_span/symbol.rs | 2 + src/librustc_typeck/check/intrinsic.rs | 9 ++- .../const-eval/const_raw_ptr_ops.stderr | 10 +-- src/test/ui/consts/miri_unleashed/slice_eq.rs | 17 +++++ src/test/ui/error-codes/E0395.stderr | 5 +- src/test/ui/issues/issue-25826.stderr | 5 +- 14 files changed, 260 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/consts/miri_unleashed/slice_eq.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 9061145a695f8..4648f762bab42 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -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(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(ptr: *const T, other: *const T) -> bool; } // Some functions are defined here because they accidentally got made diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fe05e914e6d44..b2f6f789603a9 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -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)] diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index e39d18d7733a2..0e2e6848416b6 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -295,6 +295,72 @@ impl *const T { intrinsics::ptr_offset_from(self, origin) } + /// Returns whether two pointers are guaranteed 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: *const T) -> bool + where + T: Sized, + { + intrinsics::ptr_guaranteed_eq(self, other) + } + + /// Returns whether two pointers are guaranteed not 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 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::()`. /// diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 40b5e4e22340e..67ace1f72a0ab 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -273,6 +273,72 @@ impl *mut T { if self.is_null() { None } else { Some(&mut *self) } } + /// Returns whether two pointers are guaranteed 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 not 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 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::()`. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 21ba2b5abcfb6..12932b06d32d4 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5946,7 +5946,8 @@ where } } -// Use an equal-pointer optimization when types are `Eq` +// Remove after boostrap bump +#[cfg(bootstrap)] impl SlicePartialEq for [A] where A: PartialEq + Eq, @@ -5964,7 +5965,8 @@ where } } -// Use memcmp for bytewise equality when the types allow +// Remove after boostrap bump +#[cfg(bootstrap)] impl SlicePartialEq for [A] where A: PartialEq + BytewiseEquality, @@ -5983,6 +5985,50 @@ where } } +// Use an equal-pointer optimization when types are `Eq` +#[cfg(not(bootstrap))] +impl SlicePartialEq for [A] +where + A: PartialEq + Eq, +{ + default fn equal(&self, other: &[A]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr()) { + return true; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use memcmp for bytewise equality when the types allow +#[cfg(not(bootstrap))] +impl SlicePartialEq for [A] +where + A: PartialEq + BytewiseEquality, +{ + fn equal(&self, other: &[A]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + 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 + } + } +} + #[doc(hidden)] // intermediate trait for specialization of slice's PartialOrd trait SlicePartialOrd: Sized { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 95465939070a0..78c29588e2e1b 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -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,18 @@ 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(); + let a = self.ptrtoint(a, self.type_isize()); + let b = self.ptrtoint(b, self.type_isize()); + 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); diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ac28ccd181520..1b4113a61b451 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -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 => { + // 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()?; diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index f09b598ce069d..9f005c0b4dda8 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -290,17 +290,23 @@ impl NonConstOp for RawPtrComparison { "pointers cannot be compared in a meaningful way during const eval.", ); err.note( - "It is conceptually impossible for const eval to know in all cases whether two \ - pointers are equal. While sometimes it is clear (the address of a static item \ - is never equal to the address of another static item), comparing an integer \ - address with any allocation's address is impossible to do at compile-time.", + "see issue #53020 \ + for more information", ); err.note( - "That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all \ - comparisons where CTFE isn't sure whether two addresses are equal. The mirror \ - intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't \ - sure whether two addresses are inequal.", + "It is conceptually impossible for const eval to know in all cases whether two \ + pointers are equal. While sometimes it is clear (the address of a non-zst static item \ + is never equal to the address of another non-zst static item), comparing an integer \ + address with any allocation's address is impossible to do at compile-time.", ); + if ccx.tcx.sess.parse_sess.unstable_features.is_nightly_build() { + err.note( + "That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` \ + for all comparisons where CTFE is sure that two addresses are equal. The mirror \ + intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where \ + CTFE is sure that two addresses are inequal.", + ); + } err.emit(); } } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 970a26325926c..06d1f36622b94 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -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, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3ec6973a17d56..ef6c7c14404a7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -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) } diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index dee555beca0ca..6f27ac74ade83 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: pointers cannot be compared in a meaningful way during const eval. --> $DIR/const_raw_ptr_ops.rs:6:27 @@ -13,8 +14,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/miri_unleashed/slice_eq.rs b/src/test/ui/consts/miri_unleashed/slice_eq.rs new file mode 100644 index 0000000000000..fd843105daf2a --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/slice_eq.rs @@ -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); +} diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 748126f74407c..62949cf15e13c 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index b3692098341e7..cb24aede81a2c 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error From 84f1d73182f4882518d5eef067b18b49b49e985a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 18 Jun 2020 10:06:57 +0200 Subject: [PATCH 3/7] Tidy got confused on `rustc_const_unstable` `issue`s --- src/libcore/intrinsics.rs | 8 ++++---- src/tools/tidy/src/features.rs | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 4648f762bab42..2b34e98028232 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -11,7 +11,7 @@ //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation //! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to //! `librustc_mir/interpret/intrinsics.rs` and add a -//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. +//! `#[rustc_const_unstable(feature = "foo2", issue = "01234")]` to the intrinsic. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, //! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done @@ -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() -> &'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() -> 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(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(ptr: *const T, base: *const T) -> isize; /// Internal hook used by Miri to implement unwinding. diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d9320e9147cff..3fa637b5a696f 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -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; From 9e88b48133c703c04780a9474c029b4398ca3260 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 20 Jun 2020 13:25:55 +0200 Subject: [PATCH 4/7] Refer just to the issue in the raw ptr cmp diagnostic instead of explaining everything in the diagnostic --- src/librustc_mir/transform/check_consts/ops.rs | 16 +--------------- .../ui/consts/const-eval/const_raw_ptr_ops.rs | 4 ++-- .../consts/const-eval/const_raw_ptr_ops.stderr | 8 ++------ src/test/ui/error-codes/E0395.rs | 2 +- src/test/ui/error-codes/E0395.stderr | 4 +--- src/test/ui/issues/issue-25826.rs | 2 +- src/test/ui/issues/issue-25826.stderr | 4 +--- 7 files changed, 9 insertions(+), 31 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 9f005c0b4dda8..e1a040b2e0ea5 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -287,26 +287,12 @@ impl NonConstOp for RawPtrComparison { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { let mut err = ccx.tcx.sess.struct_span_err( span, - "pointers cannot be compared in a meaningful way during const eval.", + "pointers cannot be reliably compared during const eval.", ); err.note( "see issue #53020 \ for more information", ); - err.note( - "It is conceptually impossible for const eval to know in all cases whether two \ - pointers are equal. While sometimes it is clear (the address of a non-zst static item \ - is never equal to the address of another non-zst static item), comparing an integer \ - address with any allocation's address is impossible to do at compile-time.", - ); - if ccx.tcx.sess.parse_sess.unstable_features.is_nightly_build() { - err.note( - "That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` \ - for all comparisons where CTFE is sure that two addresses are equal. The mirror \ - intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where \ - CTFE is sure that two addresses are inequal.", - ); - } err.emit(); } } diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs index 91c4bc8972ca5..083ebfdd4da3f 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -1,6 +1,6 @@ fn main() {} // unconst and bad, will thus error in miri -const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be compared +const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably compared // unconst and bad, will thus error in miri -const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be compared +const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably compared diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index 6f27ac74ade83..21d3f5e7e8536 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -1,22 +1,18 @@ -error: pointers cannot be compared in a meaningful way during const eval. +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 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53020 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. -error: pointers cannot be compared in a meaningful way during const eval. +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 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53020 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs index 28fba1d306139..d2edd97efb232 100644 --- a/src/test/ui/error-codes/E0395.rs +++ b/src/test/ui/error-codes/E0395.rs @@ -2,7 +2,7 @@ static FOO: i32 = 42; static BAR: i32 = 42; static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; -//~^ ERROR pointers cannot be compared in a meaningful way during const eval +//~^ ERROR pointers cannot be reliably compared during const eval fn main() { } diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 62949cf15e13c..674cc69645029 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -1,12 +1,10 @@ -error: pointers cannot be compared in a meaningful way during const eval. +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 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25826.rs b/src/test/ui/issues/issue-25826.rs index cb0dfcfa953e4..d1093c205798a 100644 --- a/src/test/ui/issues/issue-25826.rs +++ b/src/test/ui/issues/issue-25826.rs @@ -1,6 +1,6 @@ fn id(t: T) -> T { t } fn main() { const A: bool = unsafe { id:: as *const () < id:: as *const () }; - //~^ ERROR pointers cannot be compared in a meaningful way during const eval + //~^ ERROR pointers cannot be reliably compared during const eval println!("{}", A); } diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index cb24aede81a2c..67d1b3ab9bed6 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -1,12 +1,10 @@ -error: pointers cannot be compared in a meaningful way during const eval. +error: pointers cannot be reliably compared during const eval. --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53020 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error From 53686b91caac6c6782b8d2a41675f4f0941aa254 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 20 Jun 2020 14:14:30 +0200 Subject: [PATCH 5/7] Satisfy tidy --- src/liballoc/raw_vec.rs | 2 +- src/libcore/intrinsics.rs | 2 +- src/librustc_mir/transform/check_consts/ops.rs | 8 ++++---- src/test/ui/consts/const-eval/const_raw_ptr_ops.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 805dbfe277584..87e73a1b91e69 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -60,7 +60,7 @@ impl RawVec { /// `#[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) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2b34e98028232..50e321f9c7158 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -11,7 +11,7 @@ //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation //! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to //! `librustc_mir/interpret/intrinsics.rs` and add a -//! `#[rustc_const_unstable(feature = "foo2", issue = "01234")]` to the intrinsic. +//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, //! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index e1a040b2e0ea5..ff22b6b184e54 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -285,10 +285,10 @@ impl NonConstOp for Panic { pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = ccx.tcx.sess.struct_span_err( - span, - "pointers cannot be reliably compared during const eval.", - ); + let mut err = ccx + .tcx + .sess + .struct_span_err(span, "pointers cannot be reliably compared during const eval."); err.note( "see issue #53020 \ for more information", diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs index 083ebfdd4da3f..e238e13b8e2da 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -1,6 +1,6 @@ fn main() {} // unconst and bad, will thus error in miri -const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably compared +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 X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably compared +const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably From 98e97a46e2201520f54082abe462728b0a770a6b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 20 Jun 2020 14:58:15 +0200 Subject: [PATCH 6/7] Address review comments --- src/libcore/ptr/const_ptr.rs | 4 +-- src/libcore/ptr/mut_ptr.rs | 4 +-- src/libcore/slice/mod.rs | 47 +++++++----------------------------- 3 files changed, 13 insertions(+), 42 deletions(-) diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 0e2e6848416b6..e5ac81d8789ec 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -295,7 +295,7 @@ impl *const T { intrinsics::ptr_offset_from(self, origin) } - /// Returns whether two pointers are guaranteed equal. + /// 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), @@ -328,7 +328,7 @@ impl *const T { intrinsics::ptr_guaranteed_eq(self, other) } - /// Returns whether two pointers are guaranteed not equal. + /// 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), diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 67ace1f72a0ab..b8ff5b0dc72cb 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -273,7 +273,7 @@ impl *mut T { if self.is_null() { None } else { Some(&mut *self) } } - /// Returns whether two pointers are guaranteed equal. + /// 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), @@ -306,7 +306,7 @@ impl *mut T { intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _) } - /// Returns whether two pointers are guaranteed not equal. + /// 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), diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 12932b06d32d4..c69aafe687cf8 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5946,8 +5946,7 @@ where } } -// Remove after boostrap bump -#[cfg(bootstrap)] +// Use an equal-pointer optimization when types are `Eq` impl SlicePartialEq for [A] where A: PartialEq + Eq, @@ -5957,47 +5956,14 @@ where return false; } + #[cfg(bootstrap)] if self.as_ptr() == other.as_ptr() { return true; } - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Remove after boostrap bump -#[cfg(bootstrap)] -impl SlicePartialEq for [A] -where - A: PartialEq + BytewiseEquality, -{ - fn equal(&self, other: &[A]) -> bool { - if self.len() != other.len() { - return false; - } - if self.as_ptr() == 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 - } - } -} - -// Use an equal-pointer optimization when types are `Eq` -#[cfg(not(bootstrap))] -impl SlicePartialEq for [A] -where - A: PartialEq + Eq, -{ - default fn equal(&self, other: &[A]) -> bool { - if self.len() != other.len() { - return false; - } - // 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; } @@ -6007,7 +5973,6 @@ where } // Use memcmp for bytewise equality when the types allow -#[cfg(not(bootstrap))] impl SlicePartialEq for [A] where A: PartialEq + BytewiseEquality, @@ -6017,8 +5982,14 @@ 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))] if self.as_ptr().guaranteed_eq(other.as_ptr()) { return true; } From e465b227d15fec8f16863ba8e77191ceb5c8670b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 21 Jun 2020 13:17:05 +0200 Subject: [PATCH 7/7] `icmp` can handle raw pointers just fine, there's no need to cast to int. --- src/librustc_codegen_llvm/intrinsic.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 78c29588e2e1b..0a8525f06fa3d 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -734,8 +734,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => { let a = args[0].immediate(); let b = args[1].immediate(); - let a = self.ptrtoint(a, self.type_isize()); - let b = self.ptrtoint(b, self.type_isize()); if name == "ptr_guaranteed_eq" { self.icmp(IntPredicate::IntEQ, a, b) } else {