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(concat_idents)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(const_int_ops)]
|
#![feature(const_int_ops)]
|
||||||
|
#![feature(const_fn_union)]
|
||||||
#![feature(custom_attribute)]
|
#![feature(custom_attribute)]
|
||||||
#![feature(doc_cfg)]
|
#![feature(doc_cfg)]
|
||||||
#![feature(doc_spotlight)]
|
#![feature(doc_spotlight)]
|
||||||
|
|
|
@ -619,38 +619,6 @@ If you really want global mutable state, try using `static mut` or a global
|
||||||
`UnsafeCell`.
|
`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##"
|
E0019: r##"
|
||||||
A function call isn't allowed in the const's initialization expression
|
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
|
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##"
|
E0492: r##"
|
||||||
A borrow of a constant containing interior mutability was attempted. Erroneous
|
A borrow of a constant containing interior mutability was attempted. Erroneous
|
||||||
code example:
|
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);
|
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
|
||||||
if let ty::TyRawPtr(_) = base_ty.sty {
|
if let ty::TyRawPtr(_) = base_ty.sty {
|
||||||
if this.mode != Mode::Fn {
|
if this.mode != Mode::Fn &&
|
||||||
let mut err = struct_span_err!(
|
!this.tcx.sess.features_untracked().const_raw_ptr_deref {
|
||||||
this.tcx.sess,
|
emit_feature_err(
|
||||||
this.span,
|
&this.tcx.sess.parse_sess, "const_raw_ptr_deref",
|
||||||
E0396,
|
this.span, GateIssue::Language,
|
||||||
"raw pointers cannot be dereferenced in {}s",
|
&format!(
|
||||||
this.mode
|
"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::Field(..) |
|
||||||
ProjectionElem::Index(_) => {
|
ProjectionElem::Index(_) => {
|
||||||
if this.mode == Mode::Fn {
|
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
|
||||||
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
|
if let Some(def) = base_ty.ty_adt_def() {
|
||||||
if let Some(def) = base_ty.ty_adt_def() {
|
if def.is_union() {
|
||||||
if def.is_union() {
|
match this.mode {
|
||||||
this.not_const();
|
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::Ptr(_), CastTy::Int(_)) |
|
||||||
(CastTy::FnPtr, CastTy::Int(_)) => {
|
(CastTy::FnPtr, CastTy::Int(_)) => {
|
||||||
self.add(Qualif::NOT_CONST);
|
self.add(Qualif::NOT_CONST);
|
||||||
if self.mode != Mode::Fn {
|
if self.mode != Mode::Fn &&
|
||||||
let mut err = struct_span_err!(
|
!self.tcx.sess.features_untracked().const_raw_ptr_deref {
|
||||||
self.tcx.sess,
|
emit_feature_err(
|
||||||
self.span,
|
&self.tcx.sess.parse_sess, "const_raw_ptr_deref",
|
||||||
E0018,
|
self.span, GateIssue::Language,
|
||||||
"raw pointers cannot be cast to integers in {}s",
|
&format!(
|
||||||
self.mode
|
"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.
|
// Allows let bindings and destructuring in `const fn` functions and constants.
|
||||||
(active, const_let, "1.22.1", Some(48821), None),
|
(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.
|
// Allows using #[prelude_import] on glob `use` items.
|
||||||
//
|
//
|
||||||
// rustc internal
|
// rustc internal
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
fn main() {
|
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 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.
|
// Check that you can't dereference raw pointers in constants.
|
||||||
|
|
||||||
fn main() {
|
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);
|
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
|
--> $DIR/const-deref-ptr.rs:14:29
|
||||||
|
|
|
|
||||||
LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396
|
LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)};
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer in constant
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to previous error
|
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
|
// compile-pass
|
||||||
// run-pass
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(const_fn_union)]
|
||||||
|
|
||||||
union Transmute<T: Copy, U: Copy> {
|
union Transmute<T: Copy, U: Copy> {
|
||||||
t: T,
|
t: T,
|
||||||
u: U,
|
u: U,
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
// compile-pass
|
// compile-pass
|
||||||
|
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn, const_fn_union)]
|
||||||
|
|
||||||
#![deny(const_err)]
|
#![deny(const_err)]
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
//compile-pass
|
//compile-pass
|
||||||
|
|
||||||
|
#![feature(const_fn_union)]
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
||||||
static FOO: u32 = 42;
|
static FOO: u32 = 42;
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(const_fn_union)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let n: Int = 40;
|
let n: Int = 40;
|
||||||
match n {
|
match n {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0030]: lower range bound must be less than or equal to upper
|
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
|
LL | 10..=BAR => {}, //~ ERROR lower range bound must be less than or equal to upper
|
||||||
| ^^ lower bound larger than upper bound
|
| ^^ 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 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() {
|
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
|
--> $DIR/E0396.rs:13:28
|
||||||
|
|
|
|
||||||
LL | const VALUE: u8 = unsafe { *REG_ADDR }; //~ ERROR E0396
|
LL | const VALUE: u8 = unsafe { *REG_ADDR };
|
||||||
| ^^^^^^^^^ dereference of raw pointer in constant
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to previous error
|
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.
|
// except according to those terms.
|
||||||
|
|
||||||
static X: usize = 0 as *const usize as usize;
|
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() {
|
fn main() {
|
||||||
assert_eq!(X, 0);
|
assert_eq!(X, 0);
|
||||||
|
|
|
@ -10,6 +10,6 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
const X: u32 = 1;
|
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);
|
println!("{}", Y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-pass
|
// compile-pass
|
||||||
|
#![feature(const_fn_union)]
|
||||||
|
|
||||||
union U {
|
union U {
|
||||||
a: usize,
|
a: usize,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue