Skip to content

Commit 1393176

Browse files
author
Alexander Regueiro
committed
Loosened rules involving statics mentioning other statics.
Updated tests accordingly.
1 parent 74c89b0 commit 1393176

File tree

8 files changed

+27
-215
lines changed

8 files changed

+27
-215
lines changed

src/librustc_mir/diagnostics.rs

-55
Original file line numberDiff line numberDiff line change
@@ -1145,33 +1145,6 @@ fn main() {
11451145
```
11461146
"##,
11471147

1148-
E0394: r##"
1149-
A static was referred to by value by another static.
1150-
1151-
Erroneous code examples:
1152-
1153-
```compile_fail,E0394
1154-
static A: u32 = 0;
1155-
static B: u32 = A; // error: cannot refer to other statics by value, use the
1156-
// address-of operator or a constant instead
1157-
```
1158-
1159-
A static cannot be referred by value. To fix this issue, either use a
1160-
constant:
1161-
1162-
```
1163-
const A: u32 = 0; // `A` is now a constant
1164-
static B: u32 = A; // ok!
1165-
```
1166-
1167-
Or refer to `A` by reference:
1168-
1169-
```
1170-
static A: u32 = 0;
1171-
static B: &'static u32 = &A; // ok!
1172-
```
1173-
"##,
1174-
11751148
E0395: r##"
11761149
The value assigned to a constant scalar must be known at compile time,
11771150
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
13331306
cell are synchronized.
13341307
"##,
13351308

1336-
E0494: r##"
1337-
A reference of an interior static was assigned to another const/static.
1338-
Erroneous code example:
1339-
1340-
```compile_fail,E0494
1341-
struct Foo {
1342-
a: u32
1343-
}
1344-
1345-
static S : Foo = Foo { a : 0 };
1346-
static A : &'static u32 = &S.a;
1347-
// error: cannot refer to the interior of another static, use a
1348-
// constant instead
1349-
```
1350-
1351-
The "base" variable has to be a const if you want another static/const variable
1352-
to refer to one of its fields. Example:
1353-
1354-
```
1355-
struct Foo {
1356-
a: u32
1357-
}
1358-
1359-
const S : Foo = Foo { a : 0 };
1360-
static A : &'static u32 = &S.a; // ok!
1361-
```
1362-
"##,
1363-
13641309
E0499: r##"
13651310
A variable was borrowed as mutable more than once. Erroneous code example:
13661311

src/librustc_mir/transform/qualify_consts.rs

+26-97
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,13 @@ bitflags! {
5656
// Function argument.
5757
const FN_ARGUMENT = 1 << 2;
5858

59-
// Static place or move from a static.
60-
const STATIC = 1 << 3;
61-
62-
// Reference to a static.
63-
const STATIC_REF = 1 << 4;
64-
6559
// Not constant at all - non-`const fn` calls, asm!,
6660
// pointer comparisons, ptr-to-int casts, etc.
67-
const NOT_CONST = 1 << 5;
61+
const NOT_CONST = 1 << 3;
6862

6963
// Refers to temporaries which cannot be promoted as
7064
// promote_consts decided they weren't simple enough.
71-
const NOT_PROMOTABLE = 1 << 6;
65+
const NOT_PROMOTABLE = 1 << 4;
7266

7367
// Const items can only have MUTABLE_INTERIOR
7468
// and NOT_PROMOTABLE without producing an error.
@@ -226,42 +220,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
226220
self.add(original);
227221
}
228222

229-
/// Check if a Local with the current qualifications is promotable.
230-
fn can_promote(&self, qualif: Qualif) -> bool {
231-
// References to statics are allowed, but only in other statics.
232-
if self.mode == Mode::Static || self.mode == Mode::StaticMut {
233-
(qualif - Qualif::STATIC_REF).is_empty()
234-
} else {
235-
qualif.is_empty()
236-
}
237-
}
238-
239-
/// Check if a Place with the current qualifications could
240-
/// be consumed, by either an operand or a Deref projection.
241-
fn try_consume(&mut self) -> bool {
242-
if self.qualif.intersects(Qualif::STATIC) && self.mode != Mode::Fn {
243-
let msg = if self.mode == Mode::Static ||
244-
self.mode == Mode::StaticMut {
245-
"cannot refer to other statics by value, use the \
246-
address-of operator or a constant instead"
247-
} else {
248-
"cannot refer to statics by value, use a constant instead"
249-
};
250-
struct_span_err!(self.tcx.sess, self.span, E0394, "{}", msg)
251-
.span_label(self.span, "referring to another static by value")
252-
.note("use the address-of operator or a constant instead")
253-
.emit();
254-
255-
// Replace STATIC with NOT_CONST to avoid further errors.
256-
self.qualif = self.qualif - Qualif::STATIC;
257-
self.add(Qualif::NOT_CONST);
258-
259-
false
260-
} else {
261-
true
262-
}
263-
}
264-
265223
/// Assign the current qualification to the given destination.
266224
fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
267225
trace!("assign: {:?}", dest);
@@ -305,7 +263,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
305263
}) if self.mir.local_kind(index) == LocalKind::Temp
306264
&& self.mir.local_decls[index].ty.is_box()
307265
&& self.local_qualif[index].map_or(false, |qualif| {
308-
qualif.intersects(Qualif::NOT_CONST)
266+
qualif.contains(Qualif::NOT_CONST)
309267
}) => {
310268
// Part of `box expr`, we should've errored
311269
// already for the Box allocation Rvalue.
@@ -492,17 +450,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
492450
match *place {
493451
Place::Local(ref local) => self.visit_local(local, context, location),
494452
Place::Static(ref global) => {
495-
self.add(Qualif::STATIC);
453+
// Only allow statics (not consts) to refer to other statics.
454+
if !(self.mode == Mode::Static || self.mode == Mode::StaticMut) {
455+
self.add(Qualif::NOT_CONST);
456+
}
496457

497458
if self.mode != Mode::Fn {
498-
for attr in &self.tcx.get_attrs(global.def_id)[..] {
499-
if attr.check_name("thread_local") {
500-
span_err!(self.tcx.sess, self.span, E0625,
501-
"thread-local statics cannot be \
502-
accessed at compile-time");
503-
self.add(Qualif::NOT_CONST);
504-
return;
505-
}
459+
if self.tcx
460+
.get_attrs(global.def_id)
461+
.iter()
462+
.any(|attr| attr.check_name("thread_local")) {
463+
span_err!(self.tcx.sess, self.span, E0625,
464+
"thread-local statics cannot be \
465+
accessed at compile-time");
466+
self.add(Qualif::NOT_CONST);
467+
return;
506468
}
507469
}
508470

@@ -527,15 +489,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
527489
this.super_place(place, context, location);
528490
match proj.elem {
529491
ProjectionElem::Deref => {
530-
if !this.try_consume() {
531-
return;
532-
}
533-
534-
if this.qualif.intersects(Qualif::STATIC_REF) {
535-
this.qualif = this.qualif - Qualif::STATIC_REF;
536-
this.add(Qualif::STATIC);
537-
}
538-
539492
this.add(Qualif::NOT_CONST);
540493

541494
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> {
573526
this.not_const();
574527
}
575528
}
576-
} else if this.qualif.intersects(Qualif::STATIC) {
577-
span_err!(this.tcx.sess, this.span, E0494,
578-
"cannot refer to the interior of another \
579-
static, use a constant instead");
580529
}
530+
581531
let ty = place.ty(this.mir, this.tcx).to_ty(this.tcx);
582532
this.qualif.restrict(ty, this.tcx, this.param_env);
583533
}
@@ -599,7 +549,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
599549
Operand::Move(_) => {
600550
self.nest(|this| {
601551
this.super_operand(operand, location);
602-
this.try_consume();
603552
});
604553

605554
// Mark the consumed locals to indicate later drops are noops.
@@ -651,14 +600,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
651600
region,
652601
kind
653602
}, location);
654-
if !this.try_consume() {
655-
return;
656-
}
657-
658-
if this.qualif.intersects(Qualif::STATIC_REF) {
659-
this.qualif = this.qualif - Qualif::STATIC_REF;
660-
this.add(Qualif::STATIC);
661-
}
662603
});
663604
} else {
664605
self.super_rvalue(rvalue, location);
@@ -678,22 +619,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
678619
Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
679620
Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
680621
Rvalue::Cast(CastKind::Unsize, ..) |
681-
Rvalue::Discriminant(..) => {}
682-
683-
Rvalue::Len(_) => {
684-
// Static places in consts would have errored already,
685-
// don't treat length checks as reads from statics.
686-
self.qualif = self.qualif - Qualif::STATIC;
687-
}
622+
Rvalue::Discriminant(..) |
623+
Rvalue::Len(_) => {}
688624

689625
Rvalue::Ref(_, kind, ref place) => {
690-
// Static places in consts would have errored already,
691-
// only keep track of references to them here.
692-
if self.qualif.intersects(Qualif::STATIC) {
693-
self.qualif = self.qualif - Qualif::STATIC;
694-
self.add(Qualif::STATIC_REF);
695-
}
696-
697626
let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
698627

699628
// Default to forbidding the borrow and/or its promotion,
@@ -744,7 +673,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
744673
// Constants cannot be borrowed if they contain interior mutability as
745674
// it means that our "silent insertion of statics" could change
746675
// initializer values (very bad).
747-
if self.qualif.intersects(Qualif::MUTABLE_INTERIOR) {
676+
if self.qualif.contains(Qualif::MUTABLE_INTERIOR) {
748677
// A reference of a MUTABLE_INTERIOR place is instead
749678
// NOT_CONST (see `if forbidden_mut` below), to avoid
750679
// duplicate errors (from reborrowing, for example).
@@ -781,7 +710,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
781710
// This allows borrowing fields which don't have
782711
// `MUTABLE_INTERIOR`, from a type that does, e.g.:
783712
// `let _: &'static _ = &(Cell::new(1), 2).1;`
784-
if self.can_promote(qualif - Qualif::MUTABLE_INTERIOR) {
713+
if (qualif - Qualif::MUTABLE_INTERIOR).is_empty() {
785714
self.promotion_candidates.push(candidate);
786715
}
787716
}
@@ -889,7 +818,7 @@ This does not pose a problem by itself because they can't be accessed directly."
889818
if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() {
890819
let ty = rvalue.ty(self.mir, self.tcx);
891820
self.add_type(ty);
892-
assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR));
821+
assert!(self.qualif.contains(Qualif::MUTABLE_INTERIOR));
893822
}
894823
}
895824
}
@@ -949,7 +878,7 @@ This does not pose a problem by itself because they can't be accessed directly."
949878
}
950879
let candidate = Candidate::Argument { bb, index: i };
951880
if is_shuffle && i == 2 {
952-
if this.can_promote(this.qualif) {
881+
if this.qualif.is_empty() {
953882
this.promotion_candidates.push(candidate);
954883
} else {
955884
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."
965894
if !constant_arguments.contains(&i) {
966895
return
967896
}
968-
if this.can_promote(this.qualif) {
897+
if this.qualif.is_empty() {
969898
this.promotion_candidates.push(candidate);
970899
} else {
971900
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."
1059988
// HACK(eddyb) Emulate a bit of dataflow analysis,
1060989
// conservatively, that drop elaboration will do.
1061990
let needs_drop = if let Place::Local(local) = *place {
1062-
if self.local_qualif[local].map_or(true, |q| q.intersects(Qualif::NEEDS_DROP)) {
991+
if self.local_qualif[local].map_or(true, |q| q.contains(Qualif::NEEDS_DROP)) {
1063992
Some(self.mir.local_decls[local].source_info.span)
1064993
} else {
1065994
None
@@ -1111,7 +1040,7 @@ This does not pose a problem by itself because they can't be accessed directly."
11111040
}
11121041

11131042
// Avoid a generic error for other uses of arguments.
1114-
if self.qualif.intersects(Qualif::FN_ARGUMENT) {
1043+
if self.qualif.contains(Qualif::FN_ARGUMENT) {
11151044
let decl = &self.mir.local_decls[index];
11161045
let mut err = feature_err(
11171046
&self.tcx.sess.parse_sess,

src/test/compile-fail/issue-16538.rs

-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ mod Y {
2222

2323
static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
2424
//~^ ERROR `*const usize` cannot be shared between threads safely [E0277]
25-
//~| ERROR cannot refer to other statics by value, use the address-of operator or a constant instead
2625
//~| ERROR E0015
2726

2827
fn main() {}

src/test/compile-fail/issue-17718-borrow-interior.rs src/test/run-pass/issue-17718-borrow-interior.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,13 @@
99
// except according to those terms.
1010

1111
struct S { a: usize }
12+
1213
static A: S = S { a: 3 };
1314
static B: &'static usize = &A.a;
14-
//~^ ERROR: cannot refer to the interior of another static
1515
static C: &'static usize = &(A.a);
16-
//~^ ERROR: cannot refer to the interior of another static
1716

1817
static D: [usize; 1] = [1];
1918
static E: usize = D[0];
20-
//~^ ERROR: cannot refer to the interior of another static
21-
//~^^ ERROR: cannot refer to other statics by value
2219
static F: &'static usize = &D[0];
23-
//~^ ERROR: cannot refer to the interior of another static
2420

2521
fn main() {}

src/test/ui/error-codes/E0394.rs

-18
This file was deleted.

src/test/ui/error-codes/E0394.stderr

-11
This file was deleted.

src/test/ui/error-codes/E0494.rs

-19
This file was deleted.

0 commit comments

Comments
 (0)