Place unions, pointer casts and pointer derefs behind extra feature gates
This commit is contained in:
parent
9e472c2ace
commit
3ef863bfdf
20 changed files with 118 additions and 131 deletions
|
@ -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)]
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
// compile-pass
|
||||
// run-pass
|
||||
|
||||
#![feature(const_fn_union)]
|
||||
|
||||
union Transmute<T: Copy, U: Copy> {
|
||||
t: T,
|
||||
u: U,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
// compile-pass
|
||||
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_fn, const_fn_union)]
|
||||
|
||||
#![deny(const_err)]
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
//compile-pass
|
||||
|
||||
#![feature(const_fn_union)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
static FOO: u32 = 42;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
11
src/test/ui/const-eval/union_promotion.nll.stderr
Normal file
11
src/test/ui/const-eval/union_promotion.nll.stderr
Normal 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
|
||||
|
19
src/test/ui/error-codes/E0396-fixed.rs
Normal file
19
src/test/ui/error-codes/E0396-fixed.rs
Normal 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() {
|
||||
}
|
12
src/test/ui/error-codes/E0396-fixed.stderr
Normal file
12
src/test/ui/error-codes/E0396-fixed.stderr
Normal 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
|
||||
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
// compile-pass
|
||||
#![feature(const_fn_union)]
|
||||
|
||||
union U {
|
||||
a: usize,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue