Skip to content

Commit e8d357f

Browse files
committed
Decide signdedness on the layout instead of the type
1 parent 889a4eb commit e8d357f

File tree

7 files changed

+77
-69
lines changed

7 files changed

+77
-69
lines changed

src/librustc/ty/layout.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,17 @@ impl Abi {
794794
Abi::Aggregate { sized } => !sized
795795
}
796796
}
797+
798+
/// Returns true if this is a single signed integer scalar
799+
pub fn is_signed(&self) -> bool {
800+
match *self {
801+
Abi::Scalar(ref scal) => match scal.value {
802+
Primitive::Int(_, signed) => signed,
803+
_ => false,
804+
},
805+
_ => false,
806+
}
807+
}
797808
}
798809

799810
#[derive(PartialEq, Eq, Hash, Debug)]

src/librustc/ty/mod.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,7 +1824,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
18241824
}
18251825

18261826
#[inline]
1827-
fn eval_explicit_discr(
1827+
pub fn eval_explicit_discr(
18281828
&self,
18291829
tcx: TyCtxt<'a, 'gcx, 'tcx>,
18301830
expr_did: DefId,
@@ -1871,15 +1871,29 @@ impl<'a, 'gcx, 'tcx> AdtDef {
18711871
ty,
18721872
})
18731873
}
1874+
},
1875+
Ok(&ty::Const {
1876+
val: ConstVal::Value(other),
1877+
..
1878+
}) => {
1879+
info!("invalid enum discriminant: {:#?}", other);
1880+
::middle::const_val::struct_error(
1881+
tcx,
1882+
tcx.def_span(expr_did),
1883+
"constant evaluation of enum discriminant resulted in non-integer",
1884+
).emit();
1885+
None
18741886
}
1875-
_ => {
1887+
Err(err) => {
1888+
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
18761889
if !expr_did.is_local() {
18771890
span_bug!(tcx.def_span(expr_did),
18781891
"variant discriminant evaluation succeeded \
18791892
in its crate but failed locally");
18801893
}
18811894
None
18821895
}
1896+
_ => span_bug!(tcx.def_span(expr_did), "const eval "),
18831897
}
18841898
}
18851899

src/librustc_mir/interpret/cast.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc::ty::Ty;
2+
use rustc::ty::layout::LayoutOf;
23
use syntax::ast::{FloatTy, IntTy, UintTy};
34

45
use rustc_const_math::ConstFloat;
@@ -35,23 +36,30 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
3536
src_ty: Ty<'tcx>,
3637
dest_ty: Ty<'tcx>,
3738
) -> EvalResult<'tcx, PrimVal> {
39+
let signed = self.layout_of(src_ty)?.abi.is_signed();
40+
let v = if signed {
41+
self.sign_extend(v, src_ty)?
42+
} else {
43+
v
44+
};
3845
trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
3946
use rustc::ty::TypeVariants::*;
4047
match dest_ty.sty {
4148
TyInt(_) | TyUint(_) => {
42-
let v = self.sign_extend(v, src_ty)?;
4349
let v = self.truncate(v, dest_ty)?;
4450
Ok(PrimVal::Bytes(v))
4551
}
4652

47-
TyFloat(fty) if src_ty.is_signed() => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
53+
TyFloat(fty) if signed => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
4854
TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),
4955

5056
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
5157
TyChar => err!(InvalidChar(v)),
5258

5359
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
54-
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
60+
TyRawPtr(_) => {
61+
Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
62+
},
5563

5664
// Casts to bool are not permitted by rustc, no need to handle them here.
5765
_ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),

src/librustc_mir/interpret/eval_context.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,20 +1128,22 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
11281128
dest_align: Align,
11291129
dest_ty: Ty<'tcx>,
11301130
) -> EvalResult<'tcx> {
1131-
trace!("write_value_to_ptr: {:#?}", value);
11321131
let layout = self.layout_of(dest_ty)?;
1132+
trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
11331133
match value {
11341134
Value::ByRef(ptr, align) => {
11351135
self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
11361136
}
11371137
Value::ByVal(primval) => {
1138-
match layout.abi {
1139-
layout::Abi::Scalar(_) => {}
1140-
_ if primval.is_undef() => {}
1138+
let signed = match layout.abi {
1139+
layout::Abi::Scalar(ref scal) => match scal.value {
1140+
layout::Primitive::Int(_, signed) => signed,
1141+
_ => false,
1142+
},
1143+
_ if primval.is_undef() => false,
11411144
_ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
1142-
}
1143-
// TODO: Do we need signedness?
1144-
self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), false)
1145+
};
1146+
self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed)
11451147
}
11461148
Value::ByValPair(a_val, b_val) => {
11471149
let ptr = dest.to_ptr()?;
@@ -1679,7 +1681,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
16791681
}
16801682

16811683
pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
1682-
let size = self.layout_of(ty)?.size.bits();
1684+
let layout = self.layout_of(ty)?;
1685+
let size = layout.size.bits();
1686+
assert!(layout.abi.is_signed());
16831687
// sign extend
16841688
let amt = 128 - size;
16851689
// shift the unsigned value to the left

src/librustc_mir/interpret/memory.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -702,19 +702,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
702702
val.offset as u128
703703
}
704704

705-
PrimVal::Bytes(bytes) => {
706-
// We need to mask here, or the byteorder crate can die when given a u64 larger
707-
// than fits in an integer of the requested size.
708-
let mask = match size {
709-
1 => !0u8 as u128,
710-
2 => !0u16 as u128,
711-
4 => !0u32 as u128,
712-
8 => !0u64 as u128,
713-
16 => !0,
714-
n => bug!("unexpected PrimVal::Bytes size: {}", n),
715-
};
716-
bytes & mask
717-
}
705+
PrimVal::Bytes(bytes) => bytes,
718706

719707
PrimVal::Undef => {
720708
self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?;

src/librustc_mir/interpret/operator.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,21 +83,34 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
8383
let l = left.to_bytes()?;
8484
let r = right.to_bytes()?;
8585

86+
let left_layout = self.layout_of(left_ty)?;
87+
8688
// These ops can have an RHS with a different numeric type.
8789
if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
88-
let op: fn(u128, u32) -> (u128, bool) = match bin_op {
89-
Shl => u128::overflowing_shl,
90-
Shr => u128::overflowing_shr,
91-
_ => bug!("it has already been checked that this is a shift op"),
92-
};
93-
let l = if left_ty.is_signed() {
94-
self.sign_extend(l, left_ty)?
90+
let signed = left_layout.abi.is_signed();
91+
let mut r = r as u32;
92+
let size = left_layout.size.bits() as u32;
93+
let oflo = r > size;
94+
if oflo {
95+
r %= size;
96+
}
97+
let result = if signed {
98+
let l = self.sign_extend(l, left_ty)? as i128;
99+
let result = match bin_op {
100+
Shl => l << r,
101+
Shr => l >> r,
102+
_ => bug!("it has already been checked that this is a shift op"),
103+
};
104+
result as u128
95105
} else {
96-
l
106+
match bin_op {
107+
Shl => l << r,
108+
Shr => l >> r,
109+
_ => bug!("it has already been checked that this is a shift op"),
110+
}
97111
};
98-
let (result, oflo) = op(l, r as u32);
99112
let truncated = self.truncate(result, left_ty)?;
100-
return Ok((PrimVal::Bytes(truncated), oflo || truncated != result));
113+
return Ok((PrimVal::Bytes(truncated), oflo));
101114
}
102115

103116
if left_kind != right_kind {
@@ -137,7 +150,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
137150
}
138151
};
139152

140-
if left_ty.is_signed() {
153+
if left_layout.abi.is_signed() {
141154
let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
142155
Lt => Some(i128::lt),
143156
Le => Some(i128::le),
@@ -162,7 +175,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
162175
if let Some(op) = op {
163176
let l128 = self.sign_extend(l, left_ty)? as i128;
164177
let r = self.sign_extend(r, right_ty)? as i128;
165-
let size = self.layout_of(left_ty)?.size.bits();
178+
let size = left_layout.size.bits();
166179
match bin_op {
167180
Rem | Div => {
168181
// int_min / -1

src/librustc_typeck/collect.rs

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,14 @@ use astconv::{AstConv, Bounds};
2828
use lint;
2929
use constrained_type_params as ctp;
3030
use middle::lang_items::SizedTraitLangItem;
31-
use middle::const_val::ConstVal;
3231
use middle::resolve_lifetime as rl;
3332
use rustc::mir::mono::Linkage;
34-
use rustc::traits::Reveal;
3533
use rustc::ty::subst::Substs;
3634
use rustc::ty::{ToPredicate, ReprOptions};
3735
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
3836
use rustc::ty::maps::Providers;
3937
use rustc::ty::util::IntTypeExt;
4038
use rustc::util::nodemap::{FxHashSet, FxHashMap};
41-
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
4239
use rustc::ty::util::Discr;
4340

4441
use syntax::{abi, ast};
@@ -511,7 +508,6 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
511508
fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
512509
def_id: DefId,
513510
variants: &[hir::Variant]) {
514-
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
515511
let def = tcx.adt_def(def_id);
516512
let repr_type = def.repr.discr_type();
517513
let initial = repr_type.initial_discriminant(tcx);
@@ -522,33 +518,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
522518
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
523519
prev_discr = Some(if let Some(e) = variant.node.disr_expr {
524520
let expr_did = tcx.hir.local_def_id(e.node_id);
525-
let substs = Substs::identity_for_item(tcx, expr_did);
526-
let instance = ty::Instance::new(expr_did, substs);
527-
let global_id = GlobalId {
528-
instance,
529-
promoted: None
530-
};
531-
let result = tcx.at(variant.span).const_eval(param_env.and(global_id));
532-
533-
// enum variant evaluation happens before the global constant check
534-
// so we need to report the real error
535-
if let Err(ref err) = result {
536-
err.report(tcx, variant.span, "enum discriminant");
537-
}
538-
539-
match result {
540-
// FIXME: just use `to_raw_bits` here?
541-
Ok(&ty::Const {
542-
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
543-
..
544-
}) => {
545-
Some(Discr {
546-
val: b,
547-
ty: initial.ty,
548-
})
549-
}
550-
_ => None
551-
}
521+
def.eval_explicit_discr(tcx, expr_did)
552522
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
553523
Some(discr)
554524
} else {

0 commit comments

Comments
 (0)