From 13931762e9832d215bb6ffcfbe4cbd126050b91c Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sun, 27 May 2018 17:07:23 +0100 Subject: [PATCH] Loosened rules involving statics mentioning other statics. Updated tests accordingly. --- src/librustc_mir/diagnostics.rs | 55 -------- src/librustc_mir/transform/qualify_consts.rs | 123 ++++-------------- src/test/compile-fail/issue-16538.rs | 1 - .../issue-17718-borrow-interior.rs | 6 +- src/test/ui/error-codes/E0394.rs | 18 --- src/test/ui/error-codes/E0394.stderr | 11 -- src/test/ui/error-codes/E0494.rs | 19 --- src/test/ui/error-codes/E0494.stderr | 9 -- 8 files changed, 27 insertions(+), 215 deletions(-) rename src/test/{compile-fail => run-pass}/issue-17718-borrow-interior.rs (70%) delete mode 100644 src/test/ui/error-codes/E0394.rs delete mode 100644 src/test/ui/error-codes/E0394.stderr delete mode 100644 src/test/ui/error-codes/E0494.rs delete mode 100644 src/test/ui/error-codes/E0494.stderr diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index c2da1bee395..3c751d52b06 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -1145,33 +1145,6 @@ fn main() { ``` "##, -E0394: r##" -A static was referred to by value by another static. - -Erroneous code examples: - -```compile_fail,E0394 -static A: u32 = 0; -static B: u32 = A; // error: cannot refer to other statics by value, use the - // address-of operator or a constant instead -``` - -A static cannot be referred by value. To fix this issue, either use a -constant: - -``` -const A: u32 = 0; // `A` is now a constant -static B: u32 = A; // ok! -``` - -Or refer to `A` by reference: - -``` -static A: u32 = 0; -static B: &'static u32 = &A; // ok! -``` -"##, - E0395: r##" The value assigned to a constant scalar must be known at compile time, which is not the case when comparing raw pointers. @@ -1333,34 +1306,6 @@ Remember this solution is unsafe! You will have to ensure that accesses to the cell are synchronized. "##, -E0494: r##" -A reference of an interior static was assigned to another const/static. -Erroneous code example: - -```compile_fail,E0494 -struct Foo { - a: u32 -} - -static S : Foo = Foo { a : 0 }; -static A : &'static u32 = &S.a; -// error: cannot refer to the interior of another static, use a -// constant instead -``` - -The "base" variable has to be a const if you want another static/const variable -to refer to one of its fields. Example: - -``` -struct Foo { - a: u32 -} - -const S : Foo = Foo { a : 0 }; -static A : &'static u32 = &S.a; // ok! -``` -"##, - E0499: r##" A variable was borrowed as mutable more than once. Erroneous code example: diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 144ebce76e1..66106c7eca1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -56,19 +56,13 @@ bitflags! { // Function argument. const FN_ARGUMENT = 1 << 2; - // Static place or move from a static. - const STATIC = 1 << 3; - - // Reference to a static. - const STATIC_REF = 1 << 4; - // Not constant at all - non-`const fn` calls, asm!, // pointer comparisons, ptr-to-int casts, etc. - const NOT_CONST = 1 << 5; + const NOT_CONST = 1 << 3; // Refers to temporaries which cannot be promoted as // promote_consts decided they weren't simple enough. - const NOT_PROMOTABLE = 1 << 6; + const NOT_PROMOTABLE = 1 << 4; // Const items can only have MUTABLE_INTERIOR // and NOT_PROMOTABLE without producing an error. @@ -226,42 +220,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { self.add(original); } - /// Check if a Local with the current qualifications is promotable. - fn can_promote(&self, qualif: Qualif) -> bool { - // References to statics are allowed, but only in other statics. - if self.mode == Mode::Static || self.mode == Mode::StaticMut { - (qualif - Qualif::STATIC_REF).is_empty() - } else { - qualif.is_empty() - } - } - - /// Check if a Place with the current qualifications could - /// be consumed, by either an operand or a Deref projection. - fn try_consume(&mut self) -> bool { - if self.qualif.intersects(Qualif::STATIC) && self.mode != Mode::Fn { - let msg = if self.mode == Mode::Static || - self.mode == Mode::StaticMut { - "cannot refer to other statics by value, use the \ - address-of operator or a constant instead" - } else { - "cannot refer to statics by value, use a constant instead" - }; - struct_span_err!(self.tcx.sess, self.span, E0394, "{}", msg) - .span_label(self.span, "referring to another static by value") - .note("use the address-of operator or a constant instead") - .emit(); - - // Replace STATIC with NOT_CONST to avoid further errors. - self.qualif = self.qualif - Qualif::STATIC; - self.add(Qualif::NOT_CONST); - - false - } else { - true - } - } - /// Assign the current qualification to the given destination. fn assign(&mut self, dest: &Place<'tcx>, location: Location) { trace!("assign: {:?}", dest); @@ -305,7 +263,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { }) if self.mir.local_kind(index) == LocalKind::Temp && self.mir.local_decls[index].ty.is_box() && self.local_qualif[index].map_or(false, |qualif| { - qualif.intersects(Qualif::NOT_CONST) + qualif.contains(Qualif::NOT_CONST) }) => { // Part of `box expr`, we should've errored // already for the Box allocation Rvalue. @@ -492,17 +450,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { match *place { Place::Local(ref local) => self.visit_local(local, context, location), Place::Static(ref global) => { - self.add(Qualif::STATIC); + // Only allow statics (not consts) to refer to other statics. + if !(self.mode == Mode::Static || self.mode == Mode::StaticMut) { + self.add(Qualif::NOT_CONST); + } if self.mode != Mode::Fn { - for attr in &self.tcx.get_attrs(global.def_id)[..] { - if attr.check_name("thread_local") { - span_err!(self.tcx.sess, self.span, E0625, - "thread-local statics cannot be \ - accessed at compile-time"); - self.add(Qualif::NOT_CONST); - return; - } + if self.tcx + .get_attrs(global.def_id) + .iter() + .any(|attr| attr.check_name("thread_local")) { + span_err!(self.tcx.sess, self.span, E0625, + "thread-local statics cannot be \ + accessed at compile-time"); + self.add(Qualif::NOT_CONST); + return; } } @@ -527,15 +489,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { this.super_place(place, context, location); match proj.elem { ProjectionElem::Deref => { - if !this.try_consume() { - return; - } - - if this.qualif.intersects(Qualif::STATIC_REF) { - this.qualif = this.qualif - Qualif::STATIC_REF; - this.add(Qualif::STATIC); - } - this.add(Qualif::NOT_CONST); let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); @@ -573,11 +526,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { this.not_const(); } } - } else if this.qualif.intersects(Qualif::STATIC) { - span_err!(this.tcx.sess, this.span, E0494, - "cannot refer to the interior of another \ - static, use a constant instead"); } + let ty = place.ty(this.mir, this.tcx).to_ty(this.tcx); this.qualif.restrict(ty, this.tcx, this.param_env); } @@ -599,7 +549,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Operand::Move(_) => { self.nest(|this| { this.super_operand(operand, location); - this.try_consume(); }); // Mark the consumed locals to indicate later drops are noops. @@ -651,14 +600,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { region, kind }, location); - if !this.try_consume() { - return; - } - - if this.qualif.intersects(Qualif::STATIC_REF) { - this.qualif = this.qualif - Qualif::STATIC_REF; - this.add(Qualif::STATIC); - } }); } else { self.super_rvalue(rvalue, location); @@ -678,22 +619,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Rvalue::Cast(CastKind::UnsafeFnPointer, ..) | Rvalue::Cast(CastKind::ClosureFnPointer, ..) | Rvalue::Cast(CastKind::Unsize, ..) | - Rvalue::Discriminant(..) => {} - - Rvalue::Len(_) => { - // Static places in consts would have errored already, - // don't treat length checks as reads from statics. - self.qualif = self.qualif - Qualif::STATIC; - } + Rvalue::Discriminant(..) | + Rvalue::Len(_) => {} Rvalue::Ref(_, kind, ref place) => { - // Static places in consts would have errored already, - // only keep track of references to them here. - if self.qualif.intersects(Qualif::STATIC) { - self.qualif = self.qualif - Qualif::STATIC; - self.add(Qualif::STATIC_REF); - } - let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); // Default to forbidding the borrow and/or its promotion, @@ -744,7 +673,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Constants cannot be borrowed if they contain interior mutability as // it means that our "silent insertion of statics" could change // initializer values (very bad). - if self.qualif.intersects(Qualif::MUTABLE_INTERIOR) { + if self.qualif.contains(Qualif::MUTABLE_INTERIOR) { // A reference of a MUTABLE_INTERIOR place is instead // NOT_CONST (see `if forbidden_mut` below), to avoid // duplicate errors (from reborrowing, for example). @@ -781,7 +710,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // This allows borrowing fields which don't have // `MUTABLE_INTERIOR`, from a type that does, e.g.: // `let _: &'static _ = &(Cell::new(1), 2).1;` - if self.can_promote(qualif - Qualif::MUTABLE_INTERIOR) { + if (qualif - Qualif::MUTABLE_INTERIOR).is_empty() { self.promotion_candidates.push(candidate); } } @@ -889,7 +818,7 @@ This does not pose a problem by itself because they can't be accessed directly." if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() { let ty = rvalue.ty(self.mir, self.tcx); self.add_type(ty); - assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR)); + assert!(self.qualif.contains(Qualif::MUTABLE_INTERIOR)); } } } @@ -949,7 +878,7 @@ This does not pose a problem by itself because they can't be accessed directly." } let candidate = Candidate::Argument { bb, index: i }; if is_shuffle && i == 2 { - if this.can_promote(this.qualif) { + if this.qualif.is_empty() { this.promotion_candidates.push(candidate); } else { span_err!(this.tcx.sess, this.span, E0526, @@ -965,7 +894,7 @@ This does not pose a problem by itself because they can't be accessed directly." if !constant_arguments.contains(&i) { return } - if this.can_promote(this.qualif) { + if this.qualif.is_empty() { this.promotion_candidates.push(candidate); } else { this.tcx.sess.span_err(this.span, @@ -1059,7 +988,7 @@ This does not pose a problem by itself because they can't be accessed directly." // HACK(eddyb) Emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. let needs_drop = if let Place::Local(local) = *place { - if self.local_qualif[local].map_or(true, |q| q.intersects(Qualif::NEEDS_DROP)) { + if self.local_qualif[local].map_or(true, |q| q.contains(Qualif::NEEDS_DROP)) { Some(self.mir.local_decls[local].source_info.span) } else { None @@ -1111,7 +1040,7 @@ This does not pose a problem by itself because they can't be accessed directly." } // Avoid a generic error for other uses of arguments. - if self.qualif.intersects(Qualif::FN_ARGUMENT) { + if self.qualif.contains(Qualif::FN_ARGUMENT) { let decl = &self.mir.local_decls[index]; let mut err = feature_err( &self.tcx.sess.parse_sess, diff --git a/src/test/compile-fail/issue-16538.rs b/src/test/compile-fail/issue-16538.rs index 7df445c676c..cc652119377 100644 --- a/src/test/compile-fail/issue-16538.rs +++ b/src/test/compile-fail/issue-16538.rs @@ -22,7 +22,6 @@ mod Y { static foo: *const Y::X = Y::foo(Y::x as *const Y::X); //~^ ERROR `*const usize` cannot be shared between threads safely [E0277] -//~| ERROR cannot refer to other statics by value, use the address-of operator or a constant instead //~| ERROR E0015 fn main() {} diff --git a/src/test/compile-fail/issue-17718-borrow-interior.rs b/src/test/run-pass/issue-17718-borrow-interior.rs similarity index 70% rename from src/test/compile-fail/issue-17718-borrow-interior.rs rename to src/test/run-pass/issue-17718-borrow-interior.rs index 31352c57f1b..77df168c257 100644 --- a/src/test/compile-fail/issue-17718-borrow-interior.rs +++ b/src/test/run-pass/issue-17718-borrow-interior.rs @@ -9,17 +9,13 @@ // except according to those terms. struct S { a: usize } + static A: S = S { a: 3 }; static B: &'static usize = &A.a; -//~^ ERROR: cannot refer to the interior of another static static C: &'static usize = &(A.a); -//~^ ERROR: cannot refer to the interior of another static static D: [usize; 1] = [1]; static E: usize = D[0]; -//~^ ERROR: cannot refer to the interior of another static -//~^^ ERROR: cannot refer to other statics by value static F: &'static usize = &D[0]; -//~^ ERROR: cannot refer to the interior of another static fn main() {} diff --git a/src/test/ui/error-codes/E0394.rs b/src/test/ui/error-codes/E0394.rs deleted file mode 100644 index dae8e14c5ef..00000000000 --- a/src/test/ui/error-codes/E0394.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -#![allow(warnings)] - -static A: u32 = 0; -static B: u32 = A; -//~^ ERROR E0394 - -fn main() { -} diff --git a/src/test/ui/error-codes/E0394.stderr b/src/test/ui/error-codes/E0394.stderr deleted file mode 100644 index 6c89957de07..00000000000 --- a/src/test/ui/error-codes/E0394.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0394]: cannot refer to other statics by value, use the address-of operator or a constant instead - --> $DIR/E0394.rs:14:17 - | -LL | static B: u32 = A; - | ^ referring to another static by value - | - = note: use the address-of operator or a constant instead - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0394`. diff --git a/src/test/ui/error-codes/E0494.rs b/src/test/ui/error-codes/E0494.rs deleted file mode 100644 index 5f8632ac1c2..00000000000 --- a/src/test/ui/error-codes/E0494.rs +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -struct Foo { - a: u32 -} - -static S : Foo = Foo { a : 0 }; -static A : &'static u32 = &S.a; //~ ERROR E0494 - -fn main() { -} diff --git a/src/test/ui/error-codes/E0494.stderr b/src/test/ui/error-codes/E0494.stderr deleted file mode 100644 index 65e6b1fe670..00000000000 --- a/src/test/ui/error-codes/E0494.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0494]: cannot refer to the interior of another static, use a constant instead - --> $DIR/E0494.rs:16:27 - | -LL | static A : &'static u32 = &S.a; //~ ERROR E0494 - | ^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0494`.