Skip to content

Commit c990243

Browse files
Run new validator in compare mode
1 parent fc92d3b commit c990243

File tree

1 file changed

+97
-28
lines changed

1 file changed

+97
-28
lines changed

src/librustc_mir/transform/qualify_consts.rs

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use std::usize;
3434
use rustc::hir::HirId;
3535
use crate::transform::{MirPass, MirSource};
3636
use super::promote_consts::{self, Candidate, TempState};
37+
use crate::transform::check_consts::validation::{ops, NonConstOp};
3738

3839
/// What kind of item we are in.
3940
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -673,12 +674,14 @@ struct Checker<'a, 'tcx> {
673674

674675
temp_promotion_state: IndexVec<Local, TempState>,
675676
promotion_candidates: Vec<Candidate>,
677+
errors: Vec<(Span, String)>,
678+
suppress_errors: bool,
676679
}
677680

678681
macro_rules! unleash_miri {
679682
($this:expr) => {{
680683
if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
681-
if $this.mode.requires_const_checking() {
684+
if $this.mode.requires_const_checking() && !$this.suppress_errors {
682685
$this.tcx.sess.span_warn($this.span, "skipping const checks");
683686
}
684687
return;
@@ -736,16 +739,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
736739
def_id,
737740
rpo,
738741
temp_promotion_state: temps,
739-
promotion_candidates: vec![]
742+
promotion_candidates: vec![],
743+
errors: vec![],
744+
suppress_errors: false,
740745
}
741746
}
742747

743748
// FIXME(eddyb) we could split the errors into meaningful
744749
// categories, but enabling full miri would make that
745750
// slightly pointless (even with feature-gating).
746-
fn not_const(&mut self) {
751+
fn not_const(&mut self, op: impl NonConstOp + fmt::Debug) {
747752
unleash_miri!(self);
748-
if self.mode.requires_const_checking() {
753+
if self.mode.requires_const_checking() && !self.suppress_errors {
754+
self.record_error(op);
749755
let mut err = struct_span_err!(
750756
self.tcx.sess,
751757
self.span,
@@ -763,6 +769,14 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
763769
}
764770
}
765771

772+
fn record_error(&mut self, op: impl NonConstOp + fmt::Debug) {
773+
self.record_error_spanned(op, self.span);
774+
}
775+
776+
fn record_error_spanned(&mut self, op: impl NonConstOp + fmt::Debug, span: Span) {
777+
self.errors.push((span, format!("{:?}", op)));
778+
}
779+
766780
/// Assigns an rvalue/call qualification to the given destination.
767781
fn assign(&mut self, dest: &Place<'tcx>, source: ValueSource<'_, 'tcx>, location: Location) {
768782
trace!("assign: {:?} <- {:?}", dest, source);
@@ -781,8 +795,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
781795
qualifs[HasMutInterior] = false;
782796
qualifs[IsNotPromotable] = true;
783797

784-
if self.mode.requires_const_checking() {
798+
debug!("suppress_errors: {}", self.suppress_errors);
799+
if self.mode.requires_const_checking() && !self.suppress_errors {
785800
if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
801+
self.record_error(ops::MutBorrow(kind));
786802
if let BorrowKind::Mut { .. } = kind {
787803
let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
788804
"references in {}s may only refer \
@@ -927,8 +943,23 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
927943

928944
/// Check a whole const, static initializer or const fn.
929945
fn check_const(&mut self) -> (u8, &'tcx BitSet<Local>) {
946+
use crate::transform::check_consts as new_checker;
947+
930948
debug!("const-checking {} {:?}", self.mode, self.def_id);
931949

950+
// FIXME: Also use the new validator when features that require it (e.g. `const_if`) are
951+
// enabled.
952+
let use_new_validator = self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
953+
if use_new_validator {
954+
debug!("Using dataflow-based const validator");
955+
}
956+
957+
let item = new_checker::Item::new(self.tcx, self.def_id, self.body);
958+
let mut validator = new_checker::validation::Validator::new(&item);
959+
960+
validator.suppress_errors = !use_new_validator;
961+
self.suppress_errors = use_new_validator;
962+
932963
let body = self.body;
933964

934965
let mut seen_blocks = BitSet::new_empty(body.basic_blocks().len());
@@ -937,6 +968,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
937968
seen_blocks.insert(bb.index());
938969

939970
self.visit_basic_block_data(bb, &body[bb]);
971+
validator.visit_basic_block_data(bb, &body[bb]);
940972

941973
let target = match body[bb].terminator().kind {
942974
TerminatorKind::Goto { target } |
@@ -972,12 +1004,27 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
9721004
bb = target;
9731005
}
9741006
_ => {
975-
self.not_const();
1007+
self.not_const(ops::Loop);
1008+
validator.check_op(ops::Loop);
9761009
break;
9771010
}
9781011
}
9791012
}
9801013

1014+
// The new validation pass should agree with the old when running on simple const bodies
1015+
// (e.g. no `if` or `loop`).
1016+
if !use_new_validator {
1017+
let mut new_errors = validator.take_errors();
1018+
1019+
// FIXME: each checker sometimes emits the same error with the same span twice in a row.
1020+
self.errors.dedup();
1021+
new_errors.dedup();
1022+
if self.errors != new_errors {
1023+
error!("old validator: {:?}", self.errors);
1024+
error!("new validator: {:?}", new_errors);
1025+
panic!("disagreement between validators:");
1026+
}
1027+
}
9811028

9821029
// Collect all the temps we need to promote.
9831030
let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len());
@@ -1043,7 +1090,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
10431090
.get_attrs(*def_id)
10441091
.iter()
10451092
.any(|attr| attr.check_name(sym::thread_local)) {
1046-
if self.mode.requires_const_checking() {
1093+
if self.mode.requires_const_checking() && !self.suppress_errors {
1094+
self.record_error(ops::ThreadLocalAccess);
10471095
span_err!(self.tcx.sess, self.span, E0625,
10481096
"thread-local statics cannot be \
10491097
accessed at compile-time");
@@ -1053,7 +1101,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
10531101

10541102
// Only allow statics (not consts) to refer to other statics.
10551103
if self.mode == Mode::Static || self.mode == Mode::StaticMut {
1056-
if self.mode == Mode::Static && context.is_mutating_use() {
1104+
if self.mode == Mode::Static
1105+
&& context.is_mutating_use()
1106+
&& !self.suppress_errors
1107+
{
10571108
// this is not strictly necessary as miri will also bail out
10581109
// For interior mutability we can't really catch this statically as that
10591110
// goes through raw pointers and intermediate temporaries, so miri has
@@ -1067,7 +1118,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
10671118
}
10681119
unleash_miri!(self);
10691120

1070-
if self.mode.requires_const_checking() {
1121+
if self.mode.requires_const_checking() && !self.suppress_errors {
1122+
self.record_error(ops::StaticAccess);
10711123
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
10721124
"{}s cannot refer to statics, use \
10731125
a constant instead", self.mode);
@@ -1104,14 +1156,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
11041156
ProjectionElem::Deref => {
11051157
if context.is_mutating_use() {
11061158
// `not_const` errors out in const contexts
1107-
self.not_const()
1159+
self.not_const(ops::MutDeref)
11081160
}
11091161
let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
11101162
match self.mode {
1111-
Mode::NonConstFn => {},
1163+
Mode::NonConstFn => {}
1164+
_ if self.suppress_errors => {}
11121165
_ => {
11131166
if let ty::RawPtr(_) = base_ty.kind {
11141167
if !self.tcx.features().const_raw_ptr_deref {
1168+
self.record_error(ops::RawPtrDeref);
11151169
emit_feature_err(
11161170
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
11171171
self.span, GateIssue::Language,
@@ -1135,7 +1189,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
11351189
if def.is_union() {
11361190
match self.mode {
11371191
Mode::ConstFn => {
1138-
if !self.tcx.features().const_fn_union {
1192+
if !self.tcx.features().const_fn_union
1193+
&& !self.suppress_errors
1194+
{
1195+
self.record_error(ops::UnionAccess);
11391196
emit_feature_err(
11401197
&self.tcx.sess.parse_sess, sym::const_fn_union,
11411198
self.span, GateIssue::Language,
@@ -1155,7 +1212,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
11551212
}
11561213

11571214
ProjectionElem::Downcast(..) => {
1158-
self.not_const()
1215+
self.not_const(ops::Downcast)
11591216
}
11601217
}
11611218
}
@@ -1241,9 +1298,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
12411298
(CastTy::Ptr(_), CastTy::Int(_)) |
12421299
(CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::NonConstFn => {
12431300
unleash_miri!(self);
1244-
if !self.tcx.features().const_raw_ptr_to_usize_cast {
1301+
if !self.tcx.features().const_raw_ptr_to_usize_cast
1302+
&& !self.suppress_errors
1303+
{
12451304
// in const fn and constants require the feature gate
12461305
// FIXME: make it unsafe inside const fn and constants
1306+
self.record_error(ops::RawPtrToIntCast);
12471307
emit_feature_err(
12481308
&self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
12491309
self.span, GateIssue::Language,
@@ -1267,8 +1327,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
12671327

12681328
unleash_miri!(self);
12691329
if self.mode.requires_const_checking() &&
1270-
!self.tcx.features().const_compare_raw_pointers
1330+
!self.tcx.features().const_compare_raw_pointers &&
1331+
!self.suppress_errors
12711332
{
1333+
self.record_error(ops::RawPtrComparison);
12721334
// require the feature gate inside constants and const fn
12731335
// FIXME: make it unsafe to use these operations
12741336
emit_feature_err(
@@ -1284,7 +1346,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
12841346

12851347
Rvalue::NullaryOp(NullOp::Box, _) => {
12861348
unleash_miri!(self);
1287-
if self.mode.requires_const_checking() {
1349+
if self.mode.requires_const_checking() && !self.suppress_errors {
1350+
self.record_error(ops::HeapAllocation);
12881351
let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
12891352
"allocations are not allowed in {}s", self.mode);
12901353
err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
@@ -1329,9 +1392,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
13291392
// special intrinsic that can be called diretly without an intrinsic
13301393
// feature gate needs a language feature gate
13311394
"transmute" => {
1332-
if self.mode.requires_const_checking() {
1395+
if self.mode.requires_const_checking()
1396+
&& !self.suppress_errors
1397+
{
13331398
// const eval transmute calls only with the feature gate
13341399
if !self.tcx.features().const_transmute {
1400+
self.record_error(ops::Transmute);
13351401
emit_feature_err(
13361402
&self.tcx.sess.parse_sess, sym::const_transmute,
13371403
self.span, GateIssue::Language,
@@ -1359,7 +1425,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
13591425
.opts
13601426
.debugging_opts
13611427
.unleash_the_miri_inside_of_you;
1362-
if self.tcx.is_const_fn(def_id) || unleash_miri {
1428+
if self.tcx.is_const_fn(def_id)
1429+
|| unleash_miri
1430+
|| self.suppress_errors
1431+
{
13631432
// stable const fns or unstable const fns
13641433
// with their feature gate active
13651434
// FIXME(eddyb) move stability checks from `is_const_fn` here.
@@ -1370,6 +1439,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
13701439
// since the macro is marked with the attribute.
13711440
if !self.tcx.features().const_panic {
13721441
// Don't allow panics in constants without the feature gate.
1442+
self.record_error(ops::Panic);
13731443
emit_feature_err(
13741444
&self.tcx.sess.parse_sess,
13751445
sym::const_panic,
@@ -1384,6 +1454,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
13841454
// functions without the feature gate active in this crate in
13851455
// order to report a better error message than the one below.
13861456
if !self.span.allows_unstable(feature) {
1457+
self.record_error(ops::FnCallUnstable(def_id, feature));
13871458
let mut err = self.tcx.sess.struct_span_err(self.span,
13881459
&format!("`{}` is not yet stable as a const fn",
13891460
self.tcx.def_path_str(def_id)));
@@ -1396,6 +1467,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
13961467
err.emit();
13971468
}
13981469
} else {
1470+
self.record_error(ops::FnCallNonConst(def_id));
13991471
let mut err = struct_span_err!(
14001472
self.tcx.sess,
14011473
self.span,
@@ -1411,13 +1483,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
14111483
}
14121484
}
14131485
ty::FnPtr(_) => {
1414-
let unleash_miri = self
1415-
.tcx
1416-
.sess
1417-
.opts
1418-
.debugging_opts
1419-
.unleash_the_miri_inside_of_you;
1420-
if self.mode.requires_const_checking() && !unleash_miri {
1486+
unleash_miri!(self);
1487+
if self.mode.requires_const_checking() && !self.suppress_errors {
1488+
self.record_error(ops::FnCallIndirect);
14211489
let mut err = self.tcx.sess.struct_span_err(
14221490
self.span,
14231491
"function pointers are not allowed in const fn"
@@ -1426,7 +1494,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
14261494
}
14271495
}
14281496
_ => {
1429-
self.not_const();
1497+
self.not_const(ops::FnCallOther);
14301498
}
14311499
}
14321500

@@ -1484,7 +1552,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
14841552
}
14851553

14861554
// Deny *any* live drops anywhere other than functions.
1487-
if self.mode.requires_const_checking() {
1555+
if self.mode.requires_const_checking() && !self.suppress_errors {
14881556
unleash_miri!(self);
14891557
// HACK(eddyb): emulate a bit of dataflow analysis,
14901558
// conservatively, that drop elaboration will do.
@@ -1505,6 +1573,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
15051573
// Double-check the type being dropped, to minimize false positives.
15061574
let ty = place.ty(self.body, self.tcx).ty;
15071575
if ty.needs_drop(self.tcx, self.param_env) {
1576+
self.record_error_spanned(ops::LiveDrop, span);
15081577
struct_span_err!(self.tcx.sess, span, E0493,
15091578
"destructors cannot be evaluated at compile-time")
15101579
.span_label(span, format!("{}s cannot evaluate destructors",
@@ -1549,7 +1618,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
15491618
self.super_statement(statement, location);
15501619
}
15511620
StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
1552-
self.not_const();
1621+
self.not_const(ops::IfOrMatch);
15531622
}
15541623
// FIXME(eddyb) should these really do nothing?
15551624
StatementKind::FakeRead(..) |

0 commit comments

Comments
 (0)