Skip to content

Commit

Permalink
Remove the const_raw_ptr_comparison feature gate.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
oli-obk committed Jun 19, 2020
1 parent 72417d8 commit 9245ba8
Show file tree
Hide file tree
Showing 27 changed files with 165 additions and 190 deletions.
3 changes: 0 additions & 3 deletions src/librustc_feature/active.rs
Expand Up @@ -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),

Expand Down
5 changes: 5 additions & 0 deletions src/librustc_feature/removed.rs
Expand Up @@ -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
// -------------------------------------------------------------------------
Expand Down
26 changes: 16 additions & 10 deletions src/librustc_mir/transform/check_consts/ops.rs
Expand Up @@ -284,18 +284,24 @@ 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,
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();
}
}

Expand Down
15 changes: 0 additions & 15 deletions src/librustc_mir/transform/check_unsafety.rs
Expand Up @@ -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);
Expand Down
26 changes: 11 additions & 15 deletions src/librustc_typeck/collect/type_of.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -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()
{
Expand Down
7 changes: 3 additions & 4 deletions 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<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()
}
Expand Down
18 changes: 15 additions & 3 deletions 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 <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
@@ -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 }
Expand All @@ -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
@@ -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
@@ -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
Expand Down
18 changes: 15 additions & 3 deletions 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 <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
@@ -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
@@ -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
@@ -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

0 comments on commit 9245ba8

Please sign in to comment.