@@ -46,8 +46,10 @@ bitflags! {
4646 // they have none of these qualifications, with
4747 // the exception of `STATIC_REF` (in statics only).
4848 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 ;
5153
5254 // Constant containing an ADT that implements Drop.
5355 const NEEDS_DROP = 1 << 1 ;
@@ -63,9 +65,9 @@ bitflags! {
6365 // promote_consts decided they weren't simple enough.
6466 const NOT_PROMOTABLE = 1 << 4 ;
6567
66- // Const items can only have MUTABLE_INTERIOR
68+ // Const items can only have UNSHAREABLE_INTERIOR
6769 // and NOT_PROMOTABLE without producing an error.
68- const CONST_ERROR = !Qualif :: MUTABLE_INTERIOR . bits &
70+ const CONST_ERROR = !Qualif :: UNSHAREABLE_INTERIOR . bits &
6971 !Qualif :: NOT_PROMOTABLE . bits;
7072 }
7173}
@@ -75,8 +77,8 @@ impl<'a, 'tcx> Qualif {
7577 fn restrict ( & mut self , ty : Ty < ' tcx > ,
7678 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
7779 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 ;
8082 }
8183 if !ty. needs_drop ( tcx, param_env) {
8284 * self = * self - Qualif :: NEEDS_DROP ;
@@ -206,7 +208,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
206208
207209 /// Add the given type's qualification to self.qualif.
208210 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 ) ;
210212 self . qualif . restrict ( ty, self . tcx , self . param_env ) ;
211213 }
212214
@@ -679,18 +681,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
679681 // Constants cannot be borrowed if they contain interior mutability as
680682 // it means that our "silent insertion of statics" could change
681683 // 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
684686 // NOT_CONST (see `if forbidden_mut` below), to avoid
685687 // duplicate errors (from reborrowing, for example).
686- self . qualif = self . qualif - Qualif :: MUTABLE_INTERIOR ;
688+ self . qualif = self . qualif - Qualif :: UNSHAREABLE_INTERIOR ;
687689 if self . mode != Mode :: Fn {
688690 span_err ! ( self . tcx. sess, self . span, E0492 ,
689691 "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") ;
691694 }
692695 } else {
693- // We allow immutable borrows of frozen data.
696+ // We allow immutable borrows of frozen non-Sync data.
694697 forbidden_mut = false ;
695698 }
696699 }
@@ -712,11 +715,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
712715 if self . mir . local_kind ( local) == LocalKind :: Temp {
713716 if let Some ( qualif) = self . local_qualif [ local] {
714717 // `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.
716719 // 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.:
718721 // `let _: &'static _ = &(Cell::new(1), 2).1;`
719- if ( qualif - Qualif :: MUTABLE_INTERIOR ) . is_empty ( ) {
722+ if ( qualif - Qualif :: UNSHAREABLE_INTERIOR ) . is_empty ( ) {
720723 self . promotion_candidates . push ( candidate) ;
721724 }
722725 }
@@ -794,10 +797,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
794797 self . add ( Qualif :: NEEDS_DROP ) ;
795798 }
796799
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 ) ;
801811 }
802812 }
803813 }
@@ -1247,6 +1257,7 @@ impl MirPass for QualifyAndPromoteConstants {
12471257 }
12481258 }
12491259 let ty = mir. return_ty ( ) ;
1260+ // Not using ty.is_sync() to get the right kind of error message
12501261 tcx. infer_ctxt ( ) . enter ( |infcx| {
12511262 let param_env = ty:: ParamEnv :: empty ( ) ;
12521263 let cause = traits:: ObligationCause :: new ( mir. span , id, traits:: SharedStatic ) ;
0 commit comments