1
Fork 0

Place unions, pointer casts and pointer derefs behind extra feature gates

This commit is contained in:
Oliver Schneider 2018-07-02 19:00:07 +02:00
parent 9e472c2ace
commit 3ef863bfdf
20 changed files with 118 additions and 131 deletions

View file

@ -82,6 +82,7 @@
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(const_int_ops)]
#![feature(const_fn_union)]
#![feature(custom_attribute)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]

View file

@ -619,38 +619,6 @@ If you really want global mutable state, try using `static mut` or a global
`UnsafeCell`.
"##,
E0018: r##"
The value of static and constant integers must be known at compile time. You
can't cast a pointer to an integer because the address of a pointer can
vary.
For example, if you write:
```compile_fail,E0018
static MY_STATIC: u32 = 42;
static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
```
Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However,
the address can change when the program is linked, as well as change
between different executions due to ASLR, and many linkers would
not be able to calculate the value of `WHAT`.
On the other hand, static and constant pointers can point either to
a known numeric address or to the address of a symbol.
```
static MY_STATIC: u32 = 42;
static MY_STATIC_ADDR: &'static u32 = &MY_STATIC;
const CONST_ADDR: *const u8 = 0x5f3759df as *const u8;
```
This does not pose a problem by itself because they can't be
accessed directly.
"##,
E0019: r##"
A function call isn't allowed in the const's initialization expression
because the expression's value must be known at compile-time. Erroneous code
@ -1208,29 +1176,6 @@ fn main() {
```
"##,
E0396: r##"
The value behind a raw pointer can't be determined at compile-time
(or even link-time), which means it can't be used in a constant
expression. Erroneous code example:
```compile_fail,E0396
const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
const VALUE: u8 = unsafe { *REG_ADDR };
// error: raw pointers cannot be dereferenced in constants
```
A possible fix is to dereference your pointer at some point in run-time.
For example:
```
const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
let reg_value = unsafe { *REG_ADDR };
```
"##,
E0492: r##"
A borrow of a constant containing interior mutability was attempted. Erroneous
code example:

View file

@ -495,37 +495,41 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
if let ty::TyRawPtr(_) = base_ty.sty {
if this.mode != Mode::Fn {
let mut err = struct_span_err!(
this.tcx.sess,
this.span,
E0396,
"raw pointers cannot be dereferenced in {}s",
this.mode
if this.mode != Mode::Fn &&
!this.tcx.sess.features_untracked().const_raw_ptr_deref {
emit_feature_err(
&this.tcx.sess.parse_sess, "const_raw_ptr_deref",
this.span, GateIssue::Language,
&format!(
"dereferencing raw pointers in {}s is unstable",
this.mode,
),
);
err.span_label(this.span,
"dereference of raw pointer in constant");
if this.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"The value behind a raw pointer can't be determined \
at compile-time (or even link-time), which means it \
can't be used in a constant expression."
);
err.help("A possible fix is to dereference your pointer \
at some point in run-time.");
}
err.emit();
}
}
}
ProjectionElem::Field(..) |
ProjectionElem::Index(_) => {
if this.mode == Mode::Fn {
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
if let Some(def) = base_ty.ty_adt_def() {
if def.is_union() {
this.not_const();
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
if let Some(def) = base_ty.ty_adt_def() {
if def.is_union() {
match this.mode {
Mode::Fn => {},
Mode::ConstFn => {
if !this.tcx.sess.features_untracked().const_fn_union {
emit_feature_err(
&this.tcx.sess.parse_sess, "const_fn_union",
this.span, GateIssue::Language,
"unions in const fn are unstable",
);
}
},
| Mode::Static
| Mode::StaticMut
| Mode::Const
=> {},
}
}
}
@ -723,43 +727,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
(CastTy::Ptr(_), CastTy::Int(_)) |
(CastTy::FnPtr, CastTy::Int(_)) => {
self.add(Qualif::NOT_CONST);
if self.mode != Mode::Fn {
let mut err = struct_span_err!(
self.tcx.sess,
self.span,
E0018,
"raw pointers cannot be cast to integers in {}s",
self.mode
if self.mode != Mode::Fn &&
!self.tcx.sess.features_untracked().const_raw_ptr_deref {
emit_feature_err(
&self.tcx.sess.parse_sess, "const_raw_ptr_deref",
self.span, GateIssue::Language,
&format!(
"casting pointers to integers in {}s is unstable",
self.mode,
),
);
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note("\
The value of static and constant integers must be known at compile time. You can't cast a pointer \
to an integer because the address of a pointer can vary.
For example, if you write:
```
static MY_STATIC: u32 = 42;
static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
```
Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However, the address can change \
when the program is linked, as well as change between different executions due to ASLR, and many \
linkers would not be able to calculate the value of `WHAT`.
On the other hand, static and constant pointers can point either to a known numeric address or to \
the address of a symbol.
```
static MY_STATIC: u32 = 42;
static MY_STATIC_ADDR: &'static u32 = &MY_STATIC;
const CONST_ADDR: *const u8 = 0x5f3759df as *const u8;
```
This does not pose a problem by itself because they can't be accessed directly.");
}
err.emit();
}
}
_ => {}

View file

@ -216,6 +216,15 @@ declare_features! (
// Allows let bindings and destructuring in `const fn` functions and constants.
(active, const_let, "1.22.1", Some(48821), None),
// Allows accessing fields of unions inside const fn
(active, const_fn_union, "1.27.0", Some(51909), None),
// Allows casting raw pointers to `usize` during const eval
(active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None),
// Allows dereferencing raw pointers during const eval
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
// Allows using #[prelude_import] on glob `use` items.
//
// rustc internal

View file

@ -9,7 +9,7 @@
// except according to those terms.
fn main() {
const X: u32 = main as u32; //~ ERROR E0018
const X: u32 = main as u32; //~ ERROR casting pointers to integers in constants is unstable
const Y: u32 = 0;
const Z: u32 = &Y as *const u32 as u32; //~ ERROR E0018
const Z: u32 = &Y as *const u32 as u32; //~ ERROR is unstable
}

View file

@ -11,6 +11,7 @@
// Check that you can't dereference raw pointers in constants.
fn main() {
static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396
static C: u64 = unsafe {*(0xdeadbeef as *const u64)};
//~^ ERROR dereferencing raw pointers in statics is unstable
println!("{}", C);
}

View file

@ -1,9 +1,11 @@
error[E0396]: raw pointers cannot be dereferenced in statics
error[E0658]: dereferencing raw pointers in statics is unstable (see issue #51911)
--> $DIR/const-deref-ptr.rs:14:29
|
LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer in constant
LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0396`.
For more information about this error, try `rustc --explain E0658`.

View file

@ -11,6 +11,8 @@
// compile-pass
// run-pass
#![feature(const_fn_union)]
union Transmute<T: Copy, U: Copy> {
t: T,
u: U,

View file

@ -10,7 +10,7 @@
// compile-pass
#![feature(const_fn)]
#![feature(const_fn, const_fn_union)]
#![deny(const_err)]

View file

@ -10,6 +10,8 @@
//compile-pass
#![feature(const_fn_union)]
fn main() {}
static FOO: u32 = 42;

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(const_fn_union)]
fn main() {
let n: Int = 40;
match n {

View file

@ -1,5 +1,5 @@
error[E0030]: lower range bound must be less than or equal to upper
--> $DIR/ref_to_int_match.rs:15:9
--> $DIR/ref_to_int_match.rs:17:9
|
LL | 10..=BAR => {}, //~ ERROR lower range bound must be less than or equal to upper
| ^^ lower bound larger than upper bound

View file

@ -0,0 +1,11 @@
error: internal compiler error: unexpected region for local data ReStatic
--> $DIR/union_promotion.rs:19:29
|
LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough
| _____________________________^
LL | | Foo { a: &1 }.b == Foo { a: &2 }.b
LL | | };
| |_____^
error: aborting due to previous error

View file

@ -0,0 +1,19 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(const_raw_ptr_deref)]
const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
const VALUE: u8 = unsafe { *REG_ADDR };
//~^ ERROR this constant cannot be used
fn main() {
}

View file

@ -0,0 +1,12 @@
error: this constant cannot be used
--> $DIR/E0396-fixed.rs:15:1
|
LL | const VALUE: u8 = unsafe { *REG_ADDR };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^
| |
| a memory access tried to interpret some bytes as a pointer
|
= note: #[deny(const_err)] on by default
error: aborting due to previous error

View file

@ -10,7 +10,8 @@
const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
const VALUE: u8 = unsafe { *REG_ADDR }; //~ ERROR E0396
const VALUE: u8 = unsafe { *REG_ADDR };
//~^ ERROR dereferencing raw pointers in constants is unstable
fn main() {
}

View file

@ -1,9 +1,11 @@
error[E0396]: raw pointers cannot be dereferenced in constants
error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911)
--> $DIR/E0396.rs:13:28
|
LL | const VALUE: u8 = unsafe { *REG_ADDR }; //~ ERROR E0396
| ^^^^^^^^^ dereference of raw pointer in constant
LL | const VALUE: u8 = unsafe { *REG_ADDR };
| ^^^^^^^^^
|
= help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0396`.
For more information about this error, try `rustc --explain E0658`.

View file

@ -9,7 +9,7 @@
// except according to those terms.
static X: usize = 0 as *const usize as usize;
//~^ ERROR: raw pointers cannot be cast to integers in statics
//~^ ERROR: casting pointers to integers in statics is unstable
fn main() {
assert_eq!(X, 0);

View file

@ -10,6 +10,6 @@
fn main() {
const X: u32 = 1;
const Y: usize = &X as *const u32 as usize; //~ ERROR E0018
const Y: usize = &X as *const u32 as usize; //~ ERROR is unstable
println!("{}", Y);
}

View file

@ -9,6 +9,7 @@
// except according to those terms.
// compile-pass
#![feature(const_fn_union)]
union U {
a: usize,