Skip to content

Commit f271893

Browse files
committed
Don't evaluate predicates twice to check for impossible predicates
1 parent 9e69204 commit f271893

File tree

4 files changed

+45
-41
lines changed

4 files changed

+45
-41
lines changed

compiler/rustc_middle/src/query/erase.rs

+1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ trivial! {
241241
Option<rustc_target::spec::PanicStrategy>,
242242
Option<usize>,
243243
Result<(), rustc_errors::ErrorGuaranteed>,
244+
Result<(), traits::util::HasImpossiblePredicates>,
244245
Result<(), rustc_middle::traits::query::NoSolution>,
245246
Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
246247
rustc_ast::expand::allocator::AllocatorKind,

compiler/rustc_middle/src/query/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use crate::traits::query::{
3939
OutlivesBound,
4040
};
4141
use crate::traits::specialization_graph;
42+
use crate::traits::util::HasImpossiblePredicates;
4243
use crate::traits::{
4344
CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause,
4445
OverflowError, WellFormedLoc,
@@ -1019,7 +1020,7 @@ rustc_queries! {
10191020
}
10201021

10211022
/// Run the const prop lints on the `mir_promoted` of an item.
1022-
query const_prop_lint(key: LocalDefId) {
1023+
query const_prop_lint(key: LocalDefId) -> Result<(), HasImpossiblePredicates> {
10231024
desc { |tcx| "checking const prop lints for `{}`", tcx.def_path_str(key) }
10241025
cache_on_disk_if { true }
10251026
}

compiler/rustc_middle/src/traits/util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,9 @@ impl<'tcx> Iterator for Elaborator<'tcx> {
4646
}
4747
}
4848
}
49+
50+
/// Used as an error type to signal that an item may have an invalid body, because its
51+
/// where bounds are trivially not satisfyable.
52+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
53+
#[derive(HashStable, Encodable, Decodable)]
54+
pub struct HasImpossiblePredicates;

compiler/rustc_mir_transform/src/lib.rs

+36-40
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use rustc_middle::mir::{
4040
SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK,
4141
};
4242
use rustc_middle::query::Providers;
43+
use rustc_middle::traits::util::HasImpossiblePredicates;
4344
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
4445
use rustc_span::{source_map::Spanned, sym, DUMMY_SP};
4546
use rustc_trait_selection::traits;
@@ -399,51 +400,12 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
399400
body
400401
}
401402

402-
fn const_prop_lint(tcx: TyCtxt<'_>, def: LocalDefId) {
403+
fn const_prop_lint(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), HasImpossiblePredicates> {
403404
let (body, _) = tcx.mir_promoted(def);
404405
let body = body.borrow();
405406

406407
let mir_borrowck = tcx.mir_borrowck(def);
407408

408-
// If there are impossible bounds on the body being const prop linted,
409-
// the const eval logic used in const prop may ICE unexpectedly.
410-
let predicates = tcx
411-
.predicates_of(body.source.def_id())
412-
.predicates
413-
.iter()
414-
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
415-
if !traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect())
416-
&& mir_borrowck.tainted_by_errors.is_none()
417-
&& body.tainted_by_errors.is_none()
418-
{
419-
const_prop_lint::ConstPropLint.run_lint(tcx, &body);
420-
}
421-
}
422-
423-
/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
424-
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
425-
/// end up missing the source MIR due to stealing happening.
426-
fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
427-
if tcx.is_coroutine(def.to_def_id()) {
428-
tcx.ensure_with_value().mir_coroutine_witnesses(def);
429-
}
430-
let mir_borrowck = tcx.mir_borrowck(def);
431-
tcx.ensure().const_prop_lint(def);
432-
433-
let is_fn_like = tcx.def_kind(def).is_fn_like();
434-
if is_fn_like {
435-
// Do not compute the mir call graph without said call graph actually being used.
436-
if pm::should_run_pass(tcx, &inline::Inline) {
437-
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id()));
438-
}
439-
}
440-
441-
let (body, _) = tcx.mir_promoted(def);
442-
let mut body = body.steal();
443-
if let Some(error_reported) = mir_borrowck.tainted_by_errors {
444-
body.tainted_by_errors = Some(error_reported);
445-
}
446-
447409
// Check if it's even possible to satisfy the 'where' clauses
448410
// for this item.
449411
//
@@ -478,6 +440,40 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
478440
.iter()
479441
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
480442
if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) {
443+
Err(HasImpossiblePredicates)
444+
} else {
445+
if mir_borrowck.tainted_by_errors.is_none() && body.tainted_by_errors.is_none() {
446+
const_prop_lint::ConstPropLint.run_lint(tcx, &body);
447+
}
448+
Ok(())
449+
}
450+
}
451+
452+
/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
453+
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
454+
/// end up missing the source MIR due to stealing happening.
455+
fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
456+
if tcx.is_coroutine(def.to_def_id()) {
457+
tcx.ensure_with_value().mir_coroutine_witnesses(def);
458+
}
459+
let mir_borrowck = tcx.mir_borrowck(def);
460+
let has_impossible_predicates = tcx.const_prop_lint(def);
461+
462+
let is_fn_like = tcx.def_kind(def).is_fn_like();
463+
if is_fn_like {
464+
// Do not compute the mir call graph without said call graph actually being used.
465+
if pm::should_run_pass(tcx, &inline::Inline) {
466+
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id()));
467+
}
468+
}
469+
470+
let (body, _) = tcx.mir_promoted(def);
471+
let mut body = body.steal();
472+
if let Some(error_reported) = mir_borrowck.tainted_by_errors {
473+
body.tainted_by_errors = Some(error_reported);
474+
}
475+
476+
if let Err(HasImpossiblePredicates) = has_impossible_predicates {
481477
trace!("found unsatisfiable predicates for {:?}", body.source);
482478
// Clear the body to only contain a single `unreachable` statement.
483479
let bbs = body.basic_blocks.as_mut();

0 commit comments

Comments
 (0)