Loosened rules involving statics mentioning other statics.

Updated tests accordingly.
This commit is contained in:
Alexander Regueiro 2018-05-27 17:07:23 +01:00
parent 74c89b0230
commit 13931762e9
8 changed files with 27 additions and 215 deletions

View File

@ -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:

View File

@ -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,11 +450,16 @@ 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") {
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");
@ -504,7 +467,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
return;
}
}
}
if self.mode == Mode::Const || self.mode == Mode::ConstFn {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
@ -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,

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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 <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.
#![allow(warnings)]
static A: u32 = 0;
static B: u32 = A;
//~^ ERROR E0394
fn main() {
}

View File

@ -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`.

View File

@ -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 <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.
struct Foo {
a: u32
}
static S : Foo = Foo { a : 0 };
static A : &'static u32 = &S.a; //~ ERROR E0494
fn main() {
}

View File

@ -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`.