Skip to content

Commit e390b91

Browse files
committed
Use TraitQueryMode::Canonical when testing predicates in const prop
1 parent 6a0bb18 commit e390b91

File tree

6 files changed

+65
-13
lines changed

6 files changed

+65
-13
lines changed

src/librustc/mir/mono.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId};
22
use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext};
33
use crate::session::config::OptLevel;
4+
use crate::traits::TraitQueryMode;
45
use crate::ty::print::obsolete::DefPathBasedNames;
56
use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
67
use rustc_data_structures::base_n;
@@ -167,7 +168,9 @@ impl<'tcx> MonoItem<'tcx> {
167168
MonoItem::GlobalAsm(..) => return true,
168169
};
169170

170-
tcx.substitute_normalize_and_test_predicates((def_id, &substs))
171+
// We shouldn't encounter any overflow here, so we use TraitQueryMode::Standard\
172+
// to report an error if overflow somehow occurs.
173+
tcx.substitute_normalize_and_test_predicates((def_id, &substs, TraitQueryMode::Standard))
171174
}
172175

173176
pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {

src/librustc/query/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1141,11 +1141,11 @@ rustc_queries! {
11411141
desc { "normalizing `{:?}`", goal }
11421142
}
11431143

1144-
query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
1144+
query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>, traits::TraitQueryMode)) -> bool {
11451145
no_force
11461146
desc { |tcx|
1147-
"testing substituted normalized predicates:`{}`",
1148-
tcx.def_path_str(key.0)
1147+
"testing substituted normalized predicates in mode {:?}:`{}`",
1148+
key.2, tcx.def_path_str(key.0)
11491149
}
11501150
}
11511151

src/librustc/traits/fulfill.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use super::CodeSelectionError;
1616
use super::{ConstEvalFailure, Unimplemented};
1717
use super::{FulfillmentError, FulfillmentErrorCode};
1818
use super::{ObligationCause, PredicateObligation};
19+
use crate::traits::TraitQueryMode;
1920

2021
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
2122
type Predicate = ty::Predicate<'tcx>;
@@ -62,6 +63,9 @@ pub struct FulfillmentContext<'tcx> {
6263
// a snapshot (they don't *straddle* a snapshot, so there
6364
// is no trouble there).
6465
usable_in_snapshot: bool,
66+
67+
// The `TraitQueryMode` used when constructing a `SelectionContext`
68+
query_mode: TraitQueryMode,
6569
}
6670

6771
#[derive(Clone, Debug)]
@@ -75,12 +79,26 @@ pub struct PendingPredicateObligation<'tcx> {
7579
static_assert_size!(PendingPredicateObligation<'_>, 136);
7680

7781
impl<'a, 'tcx> FulfillmentContext<'tcx> {
78-
/// Creates a new fulfillment context.
82+
/// Creates a new fulfillment context with `TraitQueryMode::Standard`
83+
/// You almost always want to use this instead of `with_query_mode`
7984
pub fn new() -> FulfillmentContext<'tcx> {
8085
FulfillmentContext {
8186
predicates: ObligationForest::new(),
8287
register_region_obligations: true,
8388
usable_in_snapshot: false,
89+
query_mode: TraitQueryMode::Standard,
90+
}
91+
}
92+
93+
/// Creates a new fulfillment context with the specified query mode.
94+
/// This should only be used when you want to ignore overflow,
95+
/// rather than reporting it as an error.
96+
pub fn with_query_mode(query_mode: TraitQueryMode) -> FulfillmentContext<'tcx> {
97+
FulfillmentContext {
98+
predicates: ObligationForest::new(),
99+
register_region_obligations: true,
100+
usable_in_snapshot: false,
101+
query_mode,
84102
}
85103
}
86104

@@ -89,6 +107,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
89107
predicates: ObligationForest::new(),
90108
register_region_obligations: true,
91109
usable_in_snapshot: true,
110+
query_mode: TraitQueryMode::Standard,
92111
}
93112
}
94113

@@ -97,6 +116,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
97116
predicates: ObligationForest::new(),
98117
register_region_obligations: false,
99118
usable_in_snapshot: false,
119+
query_mode: TraitQueryMode::Standard,
100120
}
101121
}
102122

@@ -217,7 +237,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
217237
&mut self,
218238
infcx: &InferCtxt<'_, 'tcx>,
219239
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
220-
let mut selcx = SelectionContext::new(infcx);
240+
let mut selcx = SelectionContext::with_query_mode(infcx, self.query_mode);
221241
self.select(&mut selcx)
222242
}
223243

src/librustc/traits/mod.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub enum IntercrateMode {
9595
}
9696

9797
/// The mode that trait queries run in.
98-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
98+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable)]
9999
pub enum TraitQueryMode {
100100
// Standard/un-canonicalized queries get accurate
101101
// spans etc. passed in and hence can do reasonable
@@ -1017,13 +1017,14 @@ where
10171017
fn normalize_and_test_predicates<'tcx>(
10181018
tcx: TyCtxt<'tcx>,
10191019
predicates: Vec<ty::Predicate<'tcx>>,
1020+
mode: TraitQueryMode,
10201021
) -> bool {
1021-
debug!("normalize_and_test_predicates(predicates={:?})", predicates);
1022+
debug!("normalize_and_test_predicates(predicates={:?}, mode={:?})", predicates, mode);
10221023

10231024
let result = tcx.infer_ctxt().enter(|infcx| {
10241025
let param_env = ty::ParamEnv::reveal_all();
1025-
let mut selcx = SelectionContext::new(&infcx);
1026-
let mut fulfill_cx = FulfillmentContext::new();
1026+
let mut selcx = SelectionContext::with_query_mode(&infcx, mode);
1027+
let mut fulfill_cx = FulfillmentContext::with_query_mode(mode);
10271028
let cause = ObligationCause::dummy();
10281029
let Normalized { value: predicates, obligations } =
10291030
normalize(&mut selcx, param_env, cause.clone(), &predicates);
@@ -1043,12 +1044,12 @@ fn normalize_and_test_predicates<'tcx>(
10431044

10441045
fn substitute_normalize_and_test_predicates<'tcx>(
10451046
tcx: TyCtxt<'tcx>,
1046-
key: (DefId, SubstsRef<'tcx>),
1047+
key: (DefId, SubstsRef<'tcx>, TraitQueryMode),
10471048
) -> bool {
10481049
debug!("substitute_normalize_and_test_predicates(key={:?})", key);
10491050

10501051
let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
1051-
let result = normalize_and_test_predicates(tcx, predicates);
1052+
let result = normalize_and_test_predicates(tcx, predicates, key.2);
10521053

10531054
debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
10541055
result
@@ -1101,7 +1102,10 @@ fn vtable_methods<'tcx>(
11011102
// Note that this method could then never be called, so we
11021103
// do not want to try and codegen it, in that case (see #23435).
11031104
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
1104-
if !normalize_and_test_predicates(tcx, predicates.predicates) {
1105+
// We don't expect overflow here, so report an error if it somehow ends
1106+
// up happening.
1107+
if !normalize_and_test_predicates(tcx, predicates.predicates, TraitQueryMode::Standard)
1108+
{
11051109
debug!("vtable_methods: predicates do not hold");
11061110
return None;
11071111
}

src/librustc/ty/query/keys.rs

+9
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,15 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
115115
}
116116
}
117117

118+
impl<'tcx> Key for (DefId, SubstsRef<'tcx>, traits::TraitQueryMode) {
119+
fn query_crate(&self) -> CrateNum {
120+
self.0.krate
121+
}
122+
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
123+
self.0.default_span(tcx)
124+
}
125+
}
126+
118127
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
119128
fn query_crate(&self) -> CrateNum {
120129
self.1.def_id().krate

src/librustc_mir/transform/const_prop.rs

+16
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc::mir::{
1414
SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
1515
UnOp, RETURN_PLACE,
1616
};
17+
use rustc::traits::TraitQueryMode;
1718
use rustc::ty::layout::{
1819
HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
1920
};
@@ -88,9 +89,24 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
8889
// sure that it even makes sense to try to evaluate the body.
8990
// If there are unsatisfiable where clauses, then all bets are
9091
// off, and we just give up.
92+
//
93+
// Note that we use TraitQueryMode::Canonical here, which causes
94+
// us to treat overflow like any other error. This is because we
95+
// are "speculatively" evaluating this item with the default substs.
96+
// While this usually succeeds, it may fail with tricky impls
97+
// (e.g. the typenum crate). Const-propagation is fundamentally
98+
// "best-effort", and does not affect correctness in any way.
99+
// Therefore, it's perfectly fine to just "give up" if we're
100+
// unable to check the bounds with the default substs.
101+
//
102+
// False negatives (failing to run const-prop on something when we actually
103+
// could) are fine. However, false positives (running const-prop on
104+
// an item with unsatisfiable bounds) can lead to us generating invalid
105+
// MIR.
91106
if !tcx.substitute_normalize_and_test_predicates((
92107
source.def_id(),
93108
InternalSubsts::identity_for_item(tcx, source.def_id()),
109+
TraitQueryMode::Canonical,
94110
)) {
95111
trace!(
96112
"ConstProp skipped for item with unsatisfiable predicates: {:?}",

0 commit comments

Comments
 (0)