Skip to content

Commit 9377041

Browse files
oli-obkRalfJung
authored andcommitted
Sanity-check all constants
1 parent 75af9df commit 9377041

35 files changed

+1050
-171
lines changed

src/librustc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#![feature(in_band_lifetimes)]
7474
#![feature(macro_at_most_once_rep)]
7575
#![feature(inclusive_range_methods)]
76+
#![feature(crate_in_paths)]
7677

7778
#![recursion_limit="512"]
7879

src/librustc/mir/interpret/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
4747
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
4848
message: &str
4949
) {
50-
let err = self.struct_generic(tcx, message, None);
50+
let err = self.struct_error(tcx, message);
5151
if let Some(mut err) = err {
5252
err.emit();
5353
}

src/librustc/ty/layout.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
15991599
// Potentially-fat pointers.
16001600
ty::TyRef(_, pointee, _) |
16011601
ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
1602-
assert!(i < 2);
1602+
assert!(i < this.fields.count());
16031603

16041604
// Reuse the fat *T type as its own thin pointer data field.
16051605
// This provides information about e.g. DST struct pointees
@@ -1621,10 +1621,25 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
16211621
match tcx.struct_tail(pointee).sty {
16221622
ty::TySlice(_) |
16231623
ty::TyStr => tcx.types.usize,
1624-
ty::TyDynamic(..) => {
1625-
// FIXME(eddyb) use an usize/fn() array with
1626-
// the correct number of vtables slots.
1627-
tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil())
1624+
ty::TyDynamic(data, _) => {
1625+
let trait_def_id = data.principal().unwrap().def_id();
1626+
let num_fns: u64 = crate::traits::supertrait_def_ids(tcx, trait_def_id)
1627+
.map(|trait_def_id| {
1628+
tcx.associated_items(trait_def_id)
1629+
.filter(|item| item.kind == ty::AssociatedKind::Method)
1630+
.count() as u64
1631+
})
1632+
.sum();
1633+
tcx.mk_imm_ref(
1634+
tcx.types.re_static,
1635+
tcx.mk_array(tcx.types.usize, 3 + num_fns),
1636+
)
1637+
/* FIXME use actual fn pointers
1638+
tcx.mk_tup(&[
1639+
tcx.mk_array(tcx.types.usize, 3),
1640+
tcx.mk_array(Option<fn()>),
1641+
])
1642+
*/
16281643
}
16291644
_ => bug!("TyLayout::field_type({:?}): not applicable", this)
16301645
}

src/librustc_lint/builtin.rs

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use lint::{LateContext, LintContext, LintArray};
4040
use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
4141

4242
use std::collections::HashSet;
43+
use rustc::util::nodemap::FxHashSet;
4344

4445
use syntax::tokenstream::{TokenTree, TokenStream};
4546
use syntax::ast;
@@ -1576,20 +1577,77 @@ impl LintPass for UnusedBrokenConst {
15761577
}
15771578
}
15781579

1580+
fn validate_const<'a, 'tcx>(
1581+
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
1582+
constant: &ty::Const<'tcx>,
1583+
param_env: ty::ParamEnv<'tcx>,
1584+
gid: ::rustc::mir::interpret::GlobalId<'tcx>,
1585+
what: &str,
1586+
) {
1587+
let mut ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
1588+
let result = (|| {
1589+
let val = ecx.const_to_value(constant.val)?;
1590+
use rustc_target::abi::LayoutOf;
1591+
let layout = ecx.layout_of(constant.ty)?;
1592+
let place = ecx.allocate_place_for_value(val, layout, None)?;
1593+
let ptr = place.to_ptr()?;
1594+
let mut todo = vec![(ptr, layout.ty, String::new())];
1595+
let mut seen = FxHashSet();
1596+
seen.insert((ptr, layout.ty));
1597+
while let Some((ptr, ty, path)) = todo.pop() {
1598+
let layout = ecx.layout_of(ty)?;
1599+
ecx.validate_ptr_target(
1600+
ptr,
1601+
layout.align,
1602+
layout,
1603+
path,
1604+
&mut seen,
1605+
&mut todo,
1606+
)?;
1607+
}
1608+
Ok(())
1609+
})();
1610+
if let Err(err) = result {
1611+
let (trace, span) = ecx.generate_stacktrace(None);
1612+
let err = ::rustc::mir::interpret::ConstEvalErr {
1613+
error: err,
1614+
stacktrace: trace,
1615+
span,
1616+
};
1617+
let err = err.struct_error(
1618+
tcx.at(span),
1619+
&format!("this {} likely exhibits undefined behavior", what),
1620+
);
1621+
if let Some(mut err) = err {
1622+
err.note("The rules on what exactly is undefined behavior aren't clear, \
1623+
so this check might be overzealous. Please open an issue on the rust compiler \
1624+
repository if you believe it should not be considered undefined behavior",
1625+
);
1626+
err.emit();
1627+
}
1628+
}
1629+
}
1630+
15791631
fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) {
15801632
let def_id = cx.tcx.hir.body_owner_def_id(body_id);
15811633
let param_env = cx.tcx.param_env(def_id);
15821634
let cid = ::rustc::mir::interpret::GlobalId {
15831635
instance: ty::Instance::mono(cx.tcx, def_id),
15841636
promoted: None
15851637
};
1586-
if let Err(err) = cx.tcx.const_eval(param_env.and(cid)) {
1587-
let span = cx.tcx.def_span(def_id);
1588-
err.report_as_lint(
1589-
cx.tcx.at(span),
1590-
&format!("this {} cannot be used", what),
1591-
cx.current_lint_root(),
1592-
);
1638+
match cx.tcx.const_eval(param_env.and(cid)) {
1639+
Ok(val) => validate_const(cx.tcx, val, param_env, cid, what),
1640+
Err(err) => {
1641+
// errors for statics are already reported directly in the query
1642+
if cx.tcx.is_static(def_id).is_none() {
1643+
let span = cx.tcx.def_span(def_id);
1644+
err.report_as_lint(
1645+
cx.tcx.at(span),
1646+
&format!("this {} cannot be used", what),
1647+
cx.current_lint_root(),
1648+
);
1649+
}
1650+
},
15931651
}
15941652
}
15951653

@@ -1610,6 +1668,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst {
16101668
hir::ItemKind::Const(_, body_id) => {
16111669
check_const(cx, body_id, "constant");
16121670
},
1671+
hir::ItemKind::Static(_, _, body_id) => {
1672+
check_const(cx, body_id, "static");
1673+
},
16131674
hir::ItemKind::Ty(ref ty, _) => hir::intravisit::walk_ty(
16141675
&mut UnusedBrokenConstVisitor(cx),
16151676
ty

src/librustc_mir/interpret/const_eval.rs

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc::hir;
55
use rustc::mir::interpret::{ConstEvalErr};
66
use rustc::mir;
77
use rustc::ty::{self, TyCtxt, Ty, Instance};
8-
use rustc::ty::layout::{self, LayoutOf, Primitive};
8+
use rustc::ty::layout::{self, LayoutOf, Primitive, TyLayout};
99
use rustc::ty::subst::Subst;
1010

1111
use syntax::ast::Mutability;
@@ -16,7 +16,7 @@ use rustc::mir::interpret::{
1616
EvalResult, EvalError, EvalErrorKind, GlobalId,
1717
Value, Scalar, AllocId, Allocation, ConstValue,
1818
};
19-
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};
19+
use super::{Place, EvalContext, StackPopCleanup, ValTy, Memory, MemoryKind};
2020

2121
pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
2222
tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -63,7 +63,7 @@ pub fn eval_promoted<'a, 'mir, 'tcx>(
6363
cid: GlobalId<'tcx>,
6464
mir: &'mir mir::Mir<'tcx>,
6565
param_env: ty::ParamEnv<'tcx>,
66-
) -> EvalResult<'tcx, (Value, Scalar, Ty<'tcx>)> {
66+
) -> EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)> {
6767
ecx.with_fresh_body(|ecx| {
6868
eval_body_using_ecx(ecx, cid, Some(mir), param_env)
6969
})
@@ -121,7 +121,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
121121
cid: GlobalId<'tcx>,
122122
mir: Option<&'mir mir::Mir<'tcx>>,
123123
param_env: ty::ParamEnv<'tcx>,
124-
) -> (EvalResult<'tcx, (Value, Scalar, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
124+
) -> (EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
125125
debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
126126
// we start out with the best span we have
127127
// and try improving it down the road when more information is available
@@ -137,7 +137,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
137137
cid: GlobalId<'tcx>,
138138
mir: Option<&'mir mir::Mir<'tcx>>,
139139
param_env: ty::ParamEnv<'tcx>,
140-
) -> EvalResult<'tcx, (Value, Scalar, Ty<'tcx>)> {
140+
) -> EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)> {
141141
debug!("eval_body: {:?}, {:?}", cid, param_env);
142142
let tcx = ecx.tcx.tcx;
143143
let mut mir = match mir {
@@ -182,7 +182,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
182182
// point at the allocation
183183
_ => Value::ByRef(ptr, layout.align),
184184
};
185-
Ok((value, ptr, layout.ty))
185+
Ok((value, ptr, layout))
186186
}
187187

188188
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
@@ -434,19 +434,7 @@ pub fn const_val_field<'a, 'tcx>(
434434
let ty = value.ty;
435435
let value = ecx.const_to_value(value.val)?;
436436
let layout = ecx.layout_of(ty)?;
437-
let (ptr, align) = match value {
438-
Value::ByRef(ptr, align) => (ptr, align),
439-
Value::ScalarPair(..) | Value::Scalar(_) => {
440-
let ptr = ecx.alloc_ptr(ty)?.into();
441-
ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
442-
(ptr, layout.align)
443-
},
444-
};
445-
let place = Place::Ptr {
446-
ptr,
447-
align,
448-
extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
449-
};
437+
let place = ecx.allocate_place_for_value(value, layout, variant)?;
450438
let (place, layout) = ecx.place_field(place, field, layout)?;
451439
let (ptr, align) = place.to_ptr_align();
452440
let mut new_value = Value::ByRef(ptr, align);
@@ -484,17 +472,17 @@ pub fn const_variant_index<'a, 'tcx>(
484472
trace!("const_variant_index: {:?}, {:?}", instance, val);
485473
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
486474
let value = ecx.const_to_value(val.val)?;
475+
let layout = ecx.layout_of(val.ty)?;
487476
let (ptr, align) = match value {
488477
Value::ScalarPair(..) | Value::Scalar(_) => {
489-
let layout = ecx.layout_of(val.ty)?;
490478
let ptr = ecx.memory.allocate(layout.size, layout.align, MemoryKind::Stack)?.into();
491479
ecx.write_value_to_ptr(value, ptr, layout.align, val.ty)?;
492480
(ptr, layout.align)
493481
},
494482
Value::ByRef(ptr, align) => (ptr, align),
495483
};
496484
let place = Place::from_scalar_ptr(ptr, align);
497-
ecx.read_discriminant_as_variant_index(place, val.ty)
485+
ecx.read_discriminant_as_variant_index(place, layout)
498486
}
499487

500488
pub fn const_value_to_allocation_provider<'a, 'tcx>(
@@ -560,11 +548,11 @@ pub fn const_eval_provider<'a, 'tcx>(
560548
};
561549

562550
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
563-
res.and_then(|(mut val, _, miri_ty)| {
551+
res.and_then(|(mut val, _, layout)| {
564552
if tcx.is_static(def_id).is_none() && cid.promoted.is_none() {
565-
val = ecx.try_read_by_ref(val, miri_ty)?;
553+
val = ecx.try_read_by_ref(val, layout.ty)?;
566554
}
567-
Ok(value_to_const_value(&ecx, val, miri_ty))
555+
Ok(value_to_const_value(&ecx, val, layout.ty))
568556
}).map_err(|err| {
569557
let (trace, span) = ecx.generate_stacktrace(None);
570558
let err = ConstEvalErr {

0 commit comments

Comments
 (0)