Skip to content

Commit 6563374

Browse files
committed
rustc: replace interior_unsafe with a Freeze trait.
1 parent 3f5c311 commit 6563374

File tree

10 files changed

+83
-20
lines changed

10 files changed

+83
-20
lines changed

src/libcore/marker.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
1717
#![stable(feature = "rust1", since = "1.0.0")]
1818

19+
use cell::UnsafeCell;
1920
use cmp;
2021
use hash::Hash;
2122
use hash::Hasher;
@@ -553,3 +554,19 @@ mod impls {
553554
#[stable(feature = "rust1", since = "1.0.0")]
554555
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
555556
}
557+
558+
/// Compiler-internal trait used to determine whether a type contains
559+
/// any `UnsafeCell` internally, but not through an indirection.
560+
/// This affects, for example, whether a `static` of that type is
561+
/// placed in read-only static memory or writable static memory.
562+
#[cfg_attr(not(stage0), lang = "freeze")]
563+
unsafe trait Freeze {}
564+
565+
unsafe impl Freeze for .. {}
566+
567+
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
568+
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
569+
unsafe impl<T: ?Sized> Freeze for *const T {}
570+
unsafe impl<T: ?Sized> Freeze for *mut T {}
571+
unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
572+
unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}

src/librustc/middle/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ language_item_table! {
274274
UnsizeTraitLangItem, "unsize", unsize_trait;
275275
CopyTraitLangItem, "copy", copy_trait;
276276
SyncTraitLangItem, "sync", sync_trait;
277+
FreezeTraitLangItem, "freeze", freeze_trait;
277278

278279
DropTraitLangItem, "drop", drop_trait;
279280

src/librustc/ty/contents.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ bitflags! {
2424
/// easier for me (nmatsakis) to think about what is contained within
2525
/// a type than to think about what is *not* contained within a type.
2626
flags TypeContents: u8 {
27-
const INTERIOR_UNSAFE = 0b01,
28-
const OWNS_DTOR = 0b10,
27+
const OWNS_DTOR = 0b1,
2928
}
3029
}
3130

@@ -34,10 +33,6 @@ impl TypeContents {
3433
if cond {*self} else {TypeContents::empty()}
3534
}
3635

37-
pub fn interior_unsafe(&self) -> bool {
38-
self.intersects(TypeContents::INTERIOR_UNSAFE)
39-
}
40-
4136
pub fn needs_drop(&self, _: TyCtxt) -> bool {
4237
self.intersects(TypeContents::OWNS_DTOR)
4338
}
@@ -124,17 +119,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
124119
// unions don't have destructors regardless of the child types
125120
- TypeContents::OWNS_DTOR.when(def.is_union())
126121
| TypeContents::OWNS_DTOR.when(def.has_dtor(tcx))
127-
| TypeContents::INTERIOR_UNSAFE.when(
128-
Some(def.did) == tcx.lang_items.unsafe_cell_type())
129122
}
130123

131-
132124
ty::TyDynamic(..) |
133125
ty::TyProjection(..) |
134126
ty::TyParam(_) |
135-
ty::TyAnon(..) => {
136-
TypeContents::INTERIOR_UNSAFE | TypeContents::OWNS_DTOR
137-
}
127+
ty::TyAnon(..) => TypeContents::OWNS_DTOR,
138128

139129
ty::TyInfer(_) |
140130
ty::TyError => {

src/librustc/ty/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ bitflags! {
425425
const IS_SIZED = 1 << 17,
426426
const MOVENESS_CACHED = 1 << 18,
427427
const MOVES_BY_DEFAULT = 1 << 19,
428+
const FREEZENESS_CACHED = 1 << 20,
429+
const IS_FREEZE = 1 << 21,
428430
}
429431
}
430432

@@ -1181,6 +1183,9 @@ pub struct ParameterEnvironment<'tcx> {
11811183

11821184
/// A cache for `type_is_sized`
11831185
pub is_sized_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
1186+
1187+
/// A cache for `type_is_freeze`
1188+
pub is_freeze_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
11841189
}
11851190

11861191
impl<'a, 'tcx> ParameterEnvironment<'tcx> {
@@ -1195,6 +1200,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
11951200
free_id_outlive: self.free_id_outlive,
11961201
is_copy_cache: RefCell::new(FxHashMap()),
11971202
is_sized_cache: RefCell::new(FxHashMap()),
1203+
is_freeze_cache: RefCell::new(FxHashMap()),
11981204
}
11991205
}
12001206

@@ -2531,6 +2537,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
25312537
free_id_outlive: free_id_outlive,
25322538
is_copy_cache: RefCell::new(FxHashMap()),
25332539
is_sized_cache: RefCell::new(FxHashMap()),
2540+
is_freeze_cache: RefCell::new(FxHashMap()),
25342541
}
25352542
}
25362543

@@ -2603,6 +2610,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
26032610
free_id_outlive: free_id_outlive,
26042611
is_copy_cache: RefCell::new(FxHashMap()),
26052612
is_sized_cache: RefCell::new(FxHashMap()),
2613+
is_freeze_cache: RefCell::new(FxHashMap()),
26062614
};
26072615

26082616
let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));

src/librustc/ty/util.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,50 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
655655
result
656656
}
657657

658+
/// Returns `true` if and only if there are no `UnsafeCell`s
659+
/// nested within the type (ignoring `PhantomData` or pointers).
660+
#[inline]
661+
pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
662+
param_env: &ParameterEnvironment<'tcx>,
663+
span: Span) -> bool
664+
{
665+
if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) {
666+
return self.flags.get().intersects(TypeFlags::IS_FREEZE);
667+
}
668+
669+
self.is_freeze_uncached(tcx, param_env, span)
670+
}
671+
672+
fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
673+
param_env: &ParameterEnvironment<'tcx>,
674+
span: Span) -> bool {
675+
assert!(!self.needs_infer());
676+
677+
// Fast-path for primitive types
678+
let result = match self.sty {
679+
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
680+
TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
681+
TyStr | TyNever => Some(true),
682+
683+
TyArray(..) | TySlice(_) |
684+
TyTuple(..) | TyClosure(..) | TyAdt(..) |
685+
TyDynamic(..) | TyProjection(..) | TyParam(..) |
686+
TyInfer(..) | TyAnon(..) | TyError => None
687+
}.unwrap_or_else(|| {
688+
self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem),
689+
&param_env.is_freeze_cache, span) });
690+
691+
if !self.has_param_types() && !self.has_self_ty() {
692+
self.flags.set(self.flags.get() | if result {
693+
TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE
694+
} else {
695+
TypeFlags::FREEZENESS_CACHED
696+
});
697+
}
698+
699+
result
700+
}
701+
658702
#[inline]
659703
pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
660704
-> Result<&'tcx Layout, LayoutError<'tcx>> {

src/librustc_mir/transform/qualify_consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl<'a, 'tcx> Qualif {
8080
fn restrict(&mut self, ty: Ty<'tcx>,
8181
tcx: TyCtxt<'a, 'tcx, 'tcx>,
8282
param_env: &ty::ParameterEnvironment<'tcx>) {
83-
if !ty.type_contents(tcx).interior_unsafe() {
83+
if ty.is_freeze(tcx, param_env, DUMMY_SP) {
8484
*self = *self - Qualif::MUTABLE_INTERIOR;
8585
}
8686
if !tcx.type_needs_drop_given_env(ty, param_env) {

src/librustc_passes/consts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use rustc::lint::builtin::CONST_ERR;
4646

4747
use rustc::hir::{self, PatKind, RangeEnd};
4848
use syntax::ast;
49-
use syntax_pos::Span;
49+
use syntax_pos::{Span, DUMMY_SP};
5050
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
5151

5252
use std::collections::hash_map::Entry;
@@ -85,7 +85,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
8585

8686
// Adds the worst effect out of all the values of one type.
8787
fn add_type(&mut self, ty: Ty<'gcx>) {
88-
if ty.type_contents(self.tcx).interior_unsafe() {
88+
if !ty.is_freeze(self.tcx, &self.param_env, DUMMY_SP) {
8989
self.promotable = false;
9090
}
9191

src/librustc_trans/abi.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -746,13 +746,13 @@ impl<'a, 'tcx> FnType<'tcx> {
746746
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
747747
// both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
748748
// on memory dependencies rather than pointer equality
749-
let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
749+
let is_freeze = ccx.shared().type_is_freeze(mt.ty);
750750

751-
if mt.mutbl != hir::MutMutable && !interior_unsafe {
751+
if mt.mutbl != hir::MutMutable && is_freeze {
752752
arg.attrs.set(ArgAttribute::NoAlias);
753753
}
754754

755-
if mt.mutbl == hir::MutImmutable && !interior_unsafe {
755+
if mt.mutbl == hir::MutImmutable && is_freeze {
756756
arg.attrs.set(ArgAttribute::ReadOnly);
757757
}
758758

src/librustc_trans/consts.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
261261
// As an optimization, all shared statics which do not have interior
262262
// mutability are placed into read-only memory.
263263
if m != hir::MutMutable {
264-
let tcontents = ty.type_contents(ccx.tcx());
265-
if !tcontents.interior_unsafe() {
264+
if ccx.shared().type_is_freeze(ty) {
266265
llvm::LLVMSetGlobalConstant(g, llvm::True);
267266
}
268267
}

src/librustc_trans/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
399399
ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP)
400400
}
401401

402+
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
403+
ty.is_freeze(self.tcx, &self.empty_param_env, DUMMY_SP)
404+
}
405+
402406
pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
403407
&self.exported_symbols
404408
}

0 commit comments

Comments
 (0)