Skip to content

Commit 75fb009

Browse files
committed
Auto merge of #26023 - arielb1:fast-sized, r=eddyb
r? @eddyb The change to `trans::common::type_is_sized` is because we currently abort, rather than return random results, on overflow.
2 parents 19a3971 + 39e6855 commit 75fb009

File tree

5 files changed

+122
-68
lines changed

5 files changed

+122
-68
lines changed

src/librustc/middle/check_rvalues.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
6060
cmt: mc::cmt<'tcx>,
6161
_: euv::ConsumeMode) {
6262
debug!("consume; cmt: {:?}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
63-
if !ty::type_is_sized(self.param_env, span, cmt.ty) {
63+
if !ty::type_is_sized(Some(self.param_env), self.tcx, span, cmt.ty) {
6464
span_err!(self.tcx.sess, span, E0161,
6565
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
6666
ty_to_string(self.tcx, cmt.ty));

src/librustc/middle/intrinsicck.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
212212
debug!("with_each_combination: space={:?}, index={}, param_ty={}",
213213
space, index, param_ty.repr(self.tcx));
214214

215-
if !ty::type_is_sized(param_env, span, param_ty) {
215+
if !ty::type_is_sized(Some(param_env), self.tcx, span, param_ty) {
216216
debug!("with_each_combination: param_ty is not known to be sized");
217217

218218
substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;

src/librustc/middle/ty.rs

+115-54
Original file line numberDiff line numberDiff line change
@@ -756,16 +756,6 @@ pub struct ctxt<'tcx> {
756756
/// Caches the representation hints for struct definitions.
757757
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
758758

759-
/// Caches whether types are known to impl Copy. Note that type
760-
/// parameters are never placed into this cache, because their
761-
/// results are dependent on the parameter environment.
762-
pub type_impls_copy_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
763-
764-
/// Caches whether types are known to impl Sized. Note that type
765-
/// parameters are never placed into this cache, because their
766-
/// results are dependent on the parameter environment.
767-
pub type_impls_sized_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
768-
769759
/// Maps Expr NodeId's to their constant qualification.
770760
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
771761

@@ -827,6 +817,23 @@ bitflags! {
827817
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
828818
TypeFlags::HAS_SELF.bits |
829819
TypeFlags::HAS_REGIONS.bits,
820+
821+
// Flags representing the nominal content of a type,
822+
// computed by FlagsComputetion
823+
const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits |
824+
TypeFlags::HAS_SELF.bits |
825+
TypeFlags::HAS_TY_INFER.bits |
826+
TypeFlags::HAS_RE_INFER.bits |
827+
TypeFlags::HAS_RE_LATE_BOUND.bits |
828+
TypeFlags::HAS_REGIONS.bits |
829+
TypeFlags::HAS_TY_ERR.bits |
830+
TypeFlags::HAS_PROJECTION.bits,
831+
832+
// Caches for type_is_sized, type_moves_by_default
833+
const SIZEDNESS_CACHED = 1 << 16,
834+
const IS_SIZED = 1 << 17,
835+
const MOVENESS_CACHED = 1 << 18,
836+
const MOVES_BY_DEFAULT = 1 << 19,
830837
}
831838
}
832839

@@ -859,8 +866,8 @@ macro_rules! sty_debug_print {
859866
ty::ty_err => /* unimportant */ continue,
860867
$(ty::$variant(..) => &mut $variant,)*
861868
};
862-
let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
863-
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
869+
let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
870+
let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
864871

865872
variant.total += 1;
866873
total.total += 1;
@@ -908,7 +915,7 @@ impl<'tcx> ctxt<'tcx> {
908915
#[derive(Debug)]
909916
pub struct TyS<'tcx> {
910917
pub sty: sty<'tcx>,
911-
pub flags: TypeFlags,
918+
pub flags: Cell<TypeFlags>,
912919

913920
// the maximal depth of any bound regions appearing in this type.
914921
region_depth: u32,
@@ -964,23 +971,23 @@ impl<'tcx> Borrow<sty<'tcx>> for InternedTy<'tcx> {
964971
}
965972

966973
pub fn type_has_params(ty: Ty) -> bool {
967-
ty.flags.intersects(TypeFlags::HAS_PARAMS)
974+
ty.flags.get().intersects(TypeFlags::HAS_PARAMS)
968975
}
969976
pub fn type_has_self(ty: Ty) -> bool {
970-
ty.flags.intersects(TypeFlags::HAS_SELF)
977+
ty.flags.get().intersects(TypeFlags::HAS_SELF)
971978
}
972979
pub fn type_has_ty_infer(ty: Ty) -> bool {
973-
ty.flags.intersects(TypeFlags::HAS_TY_INFER)
980+
ty.flags.get().intersects(TypeFlags::HAS_TY_INFER)
974981
}
975982
pub fn type_needs_infer(ty: Ty) -> bool {
976-
ty.flags.intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
983+
ty.flags.get().intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
977984
}
978985
pub fn type_has_projection(ty: Ty) -> bool {
979-
ty.flags.intersects(TypeFlags::HAS_PROJECTION)
986+
ty.flags.get().intersects(TypeFlags::HAS_PROJECTION)
980987
}
981988

982989
pub fn type_has_late_bound_regions(ty: Ty) -> bool {
983-
ty.flags.intersects(TypeFlags::HAS_RE_LATE_BOUND)
990+
ty.flags.get().intersects(TypeFlags::HAS_RE_LATE_BOUND)
984991
}
985992

986993
/// An "escaping region" is a bound region whose binder is not part of `t`.
@@ -2770,8 +2777,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
27702777
stability: RefCell::new(stability),
27712778
selection_cache: traits::SelectionCache::new(),
27722779
repr_hint_cache: RefCell::new(DefIdMap()),
2773-
type_impls_copy_cache: RefCell::new(HashMap::new()),
2774-
type_impls_sized_cache: RefCell::new(HashMap::new()),
27752780
const_qualif_map: RefCell::new(NodeMap()),
27762781
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
27772782
cast_kinds: RefCell::new(NodeMap()),
@@ -2871,7 +2876,7 @@ fn intern_ty<'tcx>(type_arena: &'tcx TypedArena<TyS<'tcx>>,
28712876

28722877
let ty = match () {
28732878
() => type_arena.alloc(TyS { sty: st,
2874-
flags: flags.flags,
2879+
flags: Cell::new(flags.flags),
28752880
region_depth: flags.depth, }),
28762881
};
28772882

@@ -2902,7 +2907,7 @@ impl FlagComputation {
29022907
}
29032908

29042909
fn add_flags(&mut self, flags: TypeFlags) {
2905-
self.flags = self.flags | flags;
2910+
self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
29062911
}
29072912

29082913
fn add_depth(&mut self, depth: u32) {
@@ -3008,7 +3013,7 @@ impl FlagComputation {
30083013
}
30093014

30103015
fn add_ty(&mut self, ty: Ty) {
3011-
self.add_flags(ty.flags);
3016+
self.add_flags(ty.flags.get());
30123017
self.add_depth(ty.region_depth);
30133018
}
30143019

@@ -3389,11 +3394,11 @@ pub fn type_is_nil(ty: Ty) -> bool {
33893394
}
33903395

33913396
pub fn type_is_error(ty: Ty) -> bool {
3392-
ty.flags.intersects(TypeFlags::HAS_TY_ERR)
3397+
ty.flags.get().intersects(TypeFlags::HAS_TY_ERR)
33933398
}
33943399

33953400
pub fn type_needs_subst(ty: Ty) -> bool {
3396-
ty.flags.intersects(TypeFlags::NEEDS_SUBST)
3401+
ty.flags.get().intersects(TypeFlags::NEEDS_SUBST)
33973402
}
33983403

33993404
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
@@ -3911,42 +3916,30 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
39113916
}
39123917
}
39133918

3914-
fn type_impls_bound<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
3915-
cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
3919+
fn type_impls_bound<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
3920+
tcx: &ty::ctxt<'tcx>,
39163921
ty: Ty<'tcx>,
39173922
bound: ty::BuiltinBound,
39183923
span: Span)
39193924
-> bool
39203925
{
3921-
assert!(!ty::type_needs_infer(ty));
3922-
3923-
if !type_has_params(ty) && !type_has_self(ty) {
3924-
match cache.borrow().get(&ty) {
3925-
None => {}
3926-
Some(&result) => {
3927-
debug!("type_impls_bound({}, {:?}) = {:?} (cached)",
3928-
ty.repr(param_env.tcx),
3929-
bound,
3930-
result);
3931-
return result
3932-
}
3926+
let pe;
3927+
let param_env = match param_env {
3928+
Some(e) => e,
3929+
None => {
3930+
pe = empty_parameter_environment(tcx);
3931+
&pe
39333932
}
3934-
}
3935-
3936-
let infcx = infer::new_infer_ctxt(param_env.tcx);
3933+
};
3934+
let infcx = infer::new_infer_ctxt(tcx);
39373935

39383936
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
39393937

39403938
debug!("type_impls_bound({}, {:?}) = {:?}",
3941-
ty.repr(param_env.tcx),
3939+
ty.repr(tcx),
39423940
bound,
39433941
is_impld);
39443942

3945-
if !type_has_params(ty) && !type_has_self(ty) {
3946-
let old_value = cache.borrow_mut().insert(ty, is_impld);
3947-
assert!(old_value.is_none());
3948-
}
3949-
39503943
is_impld
39513944
}
39523945

@@ -3955,17 +3948,85 @@ pub fn type_moves_by_default<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
39553948
ty: Ty<'tcx>)
39563949
-> bool
39573950
{
3958-
let tcx = param_env.tcx;
3959-
!type_impls_bound(param_env, &tcx.type_impls_copy_cache, ty, ty::BoundCopy, span)
3951+
if ty.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
3952+
return ty.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT);
3953+
}
3954+
3955+
assert!(!ty::type_needs_infer(ty));
3956+
3957+
// Fast-path for primitive types
3958+
let result = match ty.sty {
3959+
ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
3960+
ty_ptr(..) | ty_bare_fn(..) | ty_rptr(_, mt {
3961+
mutbl: ast::MutImmutable, ..
3962+
}) => Some(false),
3963+
3964+
ty_str | ty_uniq(..) | ty_rptr(_, mt {
3965+
mutbl: ast::MutMutable, ..
3966+
}) => Some(true),
3967+
3968+
ty_vec(..) | ty_trait(..) | ty_tup(..) |
3969+
ty_closure(..) | ty_enum(..) | ty_struct(..) |
3970+
ty_projection(..) | ty_param(..) | ty_infer(..) | ty_err => None
3971+
}.unwrap_or_else(|| !type_impls_bound(Some(param_env),
3972+
param_env.tcx,
3973+
ty,
3974+
ty::BoundCopy,
3975+
span));
3976+
3977+
if !type_has_params(ty) && !type_has_self(ty) {
3978+
ty.flags.set(ty.flags.get() | if result {
3979+
TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT
3980+
} else {
3981+
TypeFlags::MOVENESS_CACHED
3982+
});
3983+
}
3984+
3985+
result
39603986
}
39613987

3962-
pub fn type_is_sized<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
3988+
#[inline]
3989+
pub fn type_is_sized<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
3990+
tcx: &ty::ctxt<'tcx>,
39633991
span: Span,
39643992
ty: Ty<'tcx>)
39653993
-> bool
39663994
{
3967-
let tcx = param_env.tcx;
3968-
type_impls_bound(param_env, &tcx.type_impls_sized_cache, ty, ty::BoundSized, span)
3995+
if ty.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) {
3996+
let result = ty.flags.get().intersects(TypeFlags::IS_SIZED);
3997+
return result;
3998+
}
3999+
4000+
type_is_sized_uncached(param_env, tcx, span, ty)
4001+
}
4002+
4003+
fn type_is_sized_uncached<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
4004+
tcx: &ty::ctxt<'tcx>,
4005+
span: Span,
4006+
ty: Ty<'tcx>) -> bool {
4007+
assert!(!ty::type_needs_infer(ty));
4008+
4009+
// Fast-path for primitive types
4010+
let result = match ty.sty {
4011+
ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
4012+
ty_uniq(..) | ty_ptr(..) | ty_rptr(..) | ty_bare_fn(..) |
4013+
ty_vec(_, Some(..)) | ty_tup(..) | ty_closure(..) => Some(true),
4014+
4015+
ty_str | ty_trait(..) | ty_vec(_, None) => Some(false),
4016+
4017+
ty_enum(..) | ty_struct(..) | ty_projection(..) | ty_param(..) |
4018+
ty_infer(..) | ty_err => None
4019+
}.unwrap_or_else(|| type_impls_bound(param_env, tcx, ty, ty::BoundSized, span));
4020+
4021+
if !type_has_params(ty) && !type_has_self(ty) {
4022+
ty.flags.set(ty.flags.get() | if result {
4023+
TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED
4024+
} else {
4025+
TypeFlags::SIZEDNESS_CACHED
4026+
});
4027+
}
4028+
4029+
result
39694030
}
39704031

39714032
pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {

src/librustc_trans/trans/common.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -118,19 +118,9 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
118118
}
119119
}
120120

121-
// Is the type's representation size known at compile time?
121+
/// Is the type's representation size known at compile time?
122122
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
123-
let param_env = ty::empty_parameter_environment(tcx);
124-
// FIXME(#4287) This can cause errors due to polymorphic recursion,
125-
// a better span should be provided, if available.
126-
let err_count = tcx.sess.err_count();
127-
let is_sized = ty::type_is_sized(&param_env, DUMMY_SP, ty);
128-
// Those errors aren't fatal, but an incorrect result can later
129-
// trip over asserts in both rustc's trans and LLVM.
130-
if err_count < tcx.sess.err_count() {
131-
tcx.sess.abort_if_errors();
132-
}
133-
is_sized
123+
ty::type_is_sized(None, tcx, DUMMY_SP, ty)
134124
}
135125

136126
pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {

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

+3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
#[lang = "sized"]
1717
trait Sized { }
1818

19+
struct S;
20+
1921
#[start]
2022
fn main(_: isize, _: *const *const u8) -> isize {
23+
let _ = S;
2124
0
2225
}

0 commit comments

Comments
 (0)