diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a4a01990c22a5..dc4a2d7c0d7b1 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -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)] diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 3c751d52b0664..e38b8633108c8 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -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: diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 208679d2aa08a..025e639d9282b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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(); } } _ => {} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a3822a4a1f93b..5ae9ae7f404a3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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 diff --git a/src/test/compile-fail/cast-ptr-to-int-const.rs b/src/test/compile-fail/cast-ptr-to-int-const.rs index 7c32e31d23b24..30f94e1b5da03 100644 --- a/src/test/compile-fail/cast-ptr-to-int-const.rs +++ b/src/test/compile-fail/cast-ptr-to-int-const.rs @@ -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 } diff --git a/src/test/ui/const-deref-ptr.rs b/src/test/ui/const-deref-ptr.rs index fa15f3e87c694..3d0477feb2060 100644 --- a/src/test/ui/const-deref-ptr.rs +++ b/src/test/ui/const-deref-ptr.rs @@ -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); } diff --git a/src/test/ui/const-deref-ptr.stderr b/src/test/ui/const-deref-ptr.stderr index 61db58104d2d2..94a383bcf1620 100644 --- a/src/test/ui/const-deref-ptr.stderr +++ b/src/test/ui/const-deref-ptr.stderr @@ -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`. diff --git a/src/test/ui/const-eval/const_transmute.rs b/src/test/ui/const-eval/const_transmute.rs index e661444a7b47d..8dd1476d25a77 100644 --- a/src/test/ui/const-eval/const_transmute.rs +++ b/src/test/ui/const-eval/const_transmute.rs @@ -11,6 +11,8 @@ // compile-pass // run-pass +#![feature(const_fn_union)] + union Transmute { t: T, u: U, diff --git a/src/test/ui/const-eval/promoted_const_fn_fail.rs b/src/test/ui/const-eval/promoted_const_fn_fail.rs index f0f35ce614e61..19db07dd330ae 100644 --- a/src/test/ui/const-eval/promoted_const_fn_fail.rs +++ b/src/test/ui/const-eval/promoted_const_fn_fail.rs @@ -10,7 +10,7 @@ // compile-pass -#![feature(const_fn)] +#![feature(const_fn, const_fn_union)] #![deny(const_err)] diff --git a/src/test/ui/const-eval/ref_to_float_transmute.rs b/src/test/ui/const-eval/ref_to_float_transmute.rs index 77d5222cb9c74..1758ac72b633b 100644 --- a/src/test/ui/const-eval/ref_to_float_transmute.rs +++ b/src/test/ui/const-eval/ref_to_float_transmute.rs @@ -10,6 +10,8 @@ //compile-pass +#![feature(const_fn_union)] + fn main() {} static FOO: u32 = 42; diff --git a/src/test/ui/const-eval/ref_to_int_match.rs b/src/test/ui/const-eval/ref_to_int_match.rs index 8ad7f11f0cee8..cb942f465e40f 100644 --- a/src/test/ui/const-eval/ref_to_int_match.rs +++ b/src/test/ui/const-eval/ref_to_int_match.rs @@ -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 { diff --git a/src/test/ui/const-eval/ref_to_int_match.stderr b/src/test/ui/const-eval/ref_to_int_match.stderr index 64ea57702d706..e82a16c066fdb 100644 --- a/src/test/ui/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/const-eval/ref_to_int_match.stderr @@ -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 diff --git a/src/test/ui/const-eval/union_promotion.nll.stderr b/src/test/ui/const-eval/union_promotion.nll.stderr new file mode 100644 index 0000000000000..ea95a8b42a480 --- /dev/null +++ b/src/test/ui/const-eval/union_promotion.nll.stderr @@ -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 + diff --git a/src/test/ui/error-codes/E0396-fixed.rs b/src/test/ui/error-codes/E0396-fixed.rs new file mode 100644 index 0000000000000..08d20e7850d94 --- /dev/null +++ b/src/test/ui/error-codes/E0396-fixed.rs @@ -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 or the MIT license +// , 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() { +} diff --git a/src/test/ui/error-codes/E0396-fixed.stderr b/src/test/ui/error-codes/E0396-fixed.stderr new file mode 100644 index 0000000000000..7d3c98c8ea808 --- /dev/null +++ b/src/test/ui/error-codes/E0396-fixed.stderr @@ -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 + diff --git a/src/test/ui/error-codes/E0396.rs b/src/test/ui/error-codes/E0396.rs index 7f34acdfb9007..6434620d26ab2 100644 --- a/src/test/ui/error-codes/E0396.rs +++ b/src/test/ui/error-codes/E0396.rs @@ -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() { } diff --git a/src/test/ui/error-codes/E0396.stderr b/src/test/ui/error-codes/E0396.stderr index 87dfd50dc9735..70331acc0e9a6 100644 --- a/src/test/ui/error-codes/E0396.stderr +++ b/src/test/ui/error-codes/E0396.stderr @@ -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`. diff --git a/src/test/ui/issue-17458.rs b/src/test/ui/issue-17458.rs index f5b7a0c13b728..354d389158d61 100644 --- a/src/test/ui/issue-17458.rs +++ b/src/test/ui/issue-17458.rs @@ -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); diff --git a/src/test/ui/issue-18294.rs b/src/test/ui/issue-18294.rs index efc1ba1635c95..28dc6846f69e1 100644 --- a/src/test/ui/issue-18294.rs +++ b/src/test/ui/issue-18294.rs @@ -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); } diff --git a/src/test/ui/union/union-const-eval.rs b/src/test/ui/union/union-const-eval.rs index 3ae76e1a82a5c..c640acec05e80 100644 --- a/src/test/ui/union/union-const-eval.rs +++ b/src/test/ui/union/union-const-eval.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-pass +#![feature(const_fn_union)] union U { a: usize,