Loosened rules involving statics mentioning other statics.
Updated tests accordingly.
This commit is contained in:
parent
74c89b0230
commit
13931762e9
@ -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:
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
@ -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() {
|
||||
}
|
@ -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`.
|
@ -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() {
|
||||
}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user