Skip to content

Commit

Permalink
Loosened rules involving statics mentioning other statics.
Browse files Browse the repository at this point in the history
Updated tests accordingly.
  • Loading branch information
Alexander Regueiro committed Jun 30, 2018
1 parent 74c89b0 commit 1393176
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 215 deletions.
55 changes: 0 additions & 55 deletions src/librustc_mir/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down
123 changes: 26 additions & 97 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
}

Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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.
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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));
}
}
}
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion src/test/compile-fail/issue-16538.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
18 changes: 0 additions & 18 deletions src/test/ui/error-codes/E0394.rs

This file was deleted.

11 changes: 0 additions & 11 deletions src/test/ui/error-codes/E0394.stderr

This file was deleted.

19 changes: 0 additions & 19 deletions src/test/ui/error-codes/E0494.rs

This file was deleted.

Loading

0 comments on commit 1393176

Please sign in to comment.