@@ -46,8 +46,10 @@ bitflags! {
46
46
// they have none of these qualifications, with
47
47
// the exception of `STATIC_REF` (in statics only).
48
48
struct Qualif : u8 {
49
- // Constant containing interior mutability (UnsafeCell).
50
- const MUTABLE_INTERIOR = 1 << 0 ;
49
+ // Constant containing interior mutability (UnsafeCell) or non-Sync data.
50
+ // Both of these prevent sound re-use of the same global static memory for
51
+ // the same data across multiple threads.
52
+ const UNSHAREABLE_INTERIOR = 1 << 0 ;
51
53
52
54
// Constant containing an ADT that implements Drop.
53
55
const NEEDS_DROP = 1 << 1 ;
@@ -63,9 +65,9 @@ bitflags! {
63
65
// promote_consts decided they weren't simple enough.
64
66
const NOT_PROMOTABLE = 1 << 4 ;
65
67
66
- // Const items can only have MUTABLE_INTERIOR
68
+ // Const items can only have UNSHAREABLE_INTERIOR
67
69
// and NOT_PROMOTABLE without producing an error.
68
- const CONST_ERROR = !Qualif :: MUTABLE_INTERIOR . bits &
70
+ const CONST_ERROR = !Qualif :: UNSHAREABLE_INTERIOR . bits &
69
71
!Qualif :: NOT_PROMOTABLE . bits;
70
72
}
71
73
}
@@ -75,8 +77,8 @@ impl<'a, 'tcx> Qualif {
75
77
fn restrict ( & mut self , ty : Ty < ' tcx > ,
76
78
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
77
79
param_env : ty:: ParamEnv < ' tcx > ) {
78
- if ty. is_freeze ( tcx, param_env, DUMMY_SP ) {
79
- * self = * self - Qualif :: MUTABLE_INTERIOR ;
80
+ if ty. is_freeze ( tcx, param_env, DUMMY_SP ) && ty . is_sync ( tcx , param_env , DUMMY_SP ) {
81
+ * self = * self - Qualif :: UNSHAREABLE_INTERIOR ;
80
82
}
81
83
if !ty. needs_drop ( tcx, param_env) {
82
84
* self = * self - Qualif :: NEEDS_DROP ;
@@ -206,7 +208,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
206
208
207
209
/// Add the given type's qualification to self.qualif.
208
210
fn add_type ( & mut self , ty : Ty < ' tcx > ) {
209
- self . add ( Qualif :: MUTABLE_INTERIOR | Qualif :: NEEDS_DROP ) ;
211
+ self . add ( Qualif :: UNSHAREABLE_INTERIOR | Qualif :: NEEDS_DROP ) ;
210
212
self . qualif . restrict ( ty, self . tcx , self . param_env ) ;
211
213
}
212
214
@@ -679,18 +681,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
679
681
// Constants cannot be borrowed if they contain interior mutability as
680
682
// it means that our "silent insertion of statics" could change
681
683
// initializer values (very bad).
682
- if self . qualif . contains ( Qualif :: MUTABLE_INTERIOR ) {
683
- // A reference of a MUTABLE_INTERIOR place is instead
684
+ if self . qualif . contains ( Qualif :: UNSHAREABLE_INTERIOR ) {
685
+ // A reference of a UNSHAREABLE_INTERIOR place is instead
684
686
// NOT_CONST (see `if forbidden_mut` below), to avoid
685
687
// duplicate errors (from reborrowing, for example).
686
- self . qualif = self . qualif - Qualif :: MUTABLE_INTERIOR ;
688
+ self . qualif = self . qualif - Qualif :: UNSHAREABLE_INTERIOR ;
687
689
if self . mode != Mode :: Fn {
688
690
span_err ! ( self . tcx. sess, self . span, E0492 ,
689
691
"cannot borrow a constant which may contain \
690
- interior mutability, create a static instead") ;
692
+ interior mutability or non-`Sync` data. If your \
693
+ data is `Sync`, create a static instead") ;
691
694
}
692
695
} else {
693
- // We allow immutable borrows of frozen data.
696
+ // We allow immutable borrows of frozen non-Sync data.
694
697
forbidden_mut = false ;
695
698
}
696
699
}
@@ -712,11 +715,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
712
715
if self . mir . local_kind ( local) == LocalKind :: Temp {
713
716
if let Some ( qualif) = self . local_qualif [ local] {
714
717
// `forbidden_mut` is false, so we can safely ignore
715
- // `MUTABLE_INTERIOR ` from the local's qualifications.
718
+ // `UNSHAREABLE_INTERIOR ` from the local's qualifications.
716
719
// This allows borrowing fields which don't have
717
- // `MUTABLE_INTERIOR `, from a type that does, e.g.:
720
+ // `UNSHAREABLE_INTERIOR `, from a type that does, e.g.:
718
721
// `let _: &'static _ = &(Cell::new(1), 2).1;`
719
- if ( qualif - Qualif :: MUTABLE_INTERIOR ) . is_empty ( ) {
722
+ if ( qualif - Qualif :: UNSHAREABLE_INTERIOR ) . is_empty ( ) {
720
723
self . promotion_candidates . push ( candidate) ;
721
724
}
722
725
}
@@ -794,10 +797,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
794
797
self . add ( Qualif :: NEEDS_DROP ) ;
795
798
}
796
799
797
- if Some ( def. did ) == self . tcx . lang_items ( ) . unsafe_cell_type ( ) {
798
- let ty = rvalue. ty ( self . mir , self . tcx ) ;
799
- self . add_type ( ty) ;
800
- assert ! ( self . qualif. contains( Qualif :: MUTABLE_INTERIOR ) ) ;
800
+ // We are looking at a concrete type constructor, and we know
801
+ // the only way to construct "fresh" non-Freeze data is `UnsafeCell`.
802
+ // So we can check for that instead of `Freeze`.
803
+ // There is no similar shortcut for Sync, though.
804
+ let ty = rvalue. ty ( self . mir , self . tcx ) ;
805
+ let freeze = Some ( def. did ) != self . tcx . lang_items ( ) . unsafe_cell_type ( ) ;
806
+ let sync = ty. is_sync ( self . tcx , self . param_env , DUMMY_SP ) ;
807
+ if !( freeze && sync)
808
+ {
809
+ // Not freeze and sync? Be careful.
810
+ self . add ( Qualif :: UNSHAREABLE_INTERIOR ) ;
801
811
}
802
812
}
803
813
}
@@ -1247,6 +1257,7 @@ impl MirPass for QualifyAndPromoteConstants {
1247
1257
}
1248
1258
}
1249
1259
let ty = mir. return_ty ( ) ;
1260
+ // Not using ty.is_sync() to get the right kind of error message
1250
1261
tcx. infer_ctxt ( ) . enter ( |infcx| {
1251
1262
let param_env = ty:: ParamEnv :: empty ( ) ;
1252
1263
let cause = traits:: ObligationCause :: new ( mir. span , id, traits:: SharedStatic ) ;
0 commit comments