Skip to content

Commit 707004c

Browse files
authoredApr 22, 2020
Rollup merge of rust-lang#70970 - eddyb:trait-vs-impl-mismatch, r=oli-obk
Detect mistyped associated consts in `Instance::resolve`. *Based on rust-lang#71049 to prevent redundant/misleading downstream errors.* Fixes rust-lang#70942 by refusing to resolve an associated `const` if it doesn't have the same type in the `impl` that it does in the `trait` (which we assume had errored, and `delay_span_bug` guards against bugs).
2 parents 2dc5b60 + 289f46a commit 707004c

File tree

21 files changed

+157
-67
lines changed

21 files changed

+157
-67
lines changed
 

‎Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4295,6 +4295,7 @@ version = "0.0.0"
42954295
dependencies = [
42964296
"log",
42974297
"rustc_data_structures",
4298+
"rustc_errors",
42984299
"rustc_hir",
42994300
"rustc_infer",
43004301
"rustc_middle",

‎src/librustc_codegen_llvm/context.rs

+1
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
376376
def_id,
377377
tcx.intern_substs(&[]),
378378
)
379+
.unwrap()
379380
.unwrap(),
380381
),
381382
_ => {

‎src/librustc_codegen_ssa/base.rs

+1
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
465465
start_def_id,
466466
cx.tcx().intern_substs(&[main_ret_ty.into()]),
467467
)
468+
.unwrap()
468469
.unwrap(),
469470
);
470471
(

‎src/librustc_codegen_ssa/mir/block.rs

+1
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
537537
ty::FnDef(def_id, substs) => (
538538
Some(
539539
ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs)
540+
.unwrap()
540541
.unwrap(),
541542
),
542543
None,

‎src/librustc_middle/mir/interpret/queries.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ impl<'tcx> TyCtxt<'tcx> {
3939
promoted: Option<mir::Promoted>,
4040
span: Option<Span>,
4141
) -> ConstEvalResult<'tcx> {
42-
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
43-
if let Some(instance) = instance {
44-
let cid = GlobalId { instance, promoted };
45-
self.const_eval_global_id(param_env, cid, span)
46-
} else {
47-
Err(ErrorHandled::TooGeneric)
42+
match ty::Instance::resolve(self, param_env, def_id, substs) {
43+
Ok(Some(instance)) => {
44+
let cid = GlobalId { instance, promoted };
45+
self.const_eval_global_id(param_env, cid, span)
46+
}
47+
Ok(None) => Err(ErrorHandled::TooGeneric),
48+
Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
4849
}
4950
}
5051

‎src/librustc_middle/query/mod.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ rustc_queries! {
679679
Codegen {
680680
query codegen_fulfill_obligation(
681681
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
682-
) -> Option<Vtable<'tcx, ()>> {
682+
) -> Result<Vtable<'tcx, ()>, ErrorReported> {
683683
cache_on_disk_if { true }
684684
desc { |tcx|
685685
"checking if `{}` fulfills its obligations",
@@ -1258,8 +1258,19 @@ rustc_queries! {
12581258
desc { "looking up enabled feature gates" }
12591259
}
12601260

1261-
query resolve_instance(key: (ty::ParamEnv<'tcx>, DefId, SubstsRef<'tcx>)) -> Option<ty::Instance<'tcx>> {
1262-
desc { "resolving instance `{:?}` `{:?}` with {:?}", key.1, key.2, key.0 }
1261+
/// Attempt to resolve the given `DefId` to an `Instance`, for the
1262+
/// given generics args (`SubstsRef`), returning one of:
1263+
/// * `Ok(Some(instance))` on success
1264+
/// * `Ok(None)` when the `SubstsRef` are still too generic,
1265+
/// and therefore don't allow finding the final `Instance`
1266+
/// * `Err(ErrorReported)` when the `Instance` resolution process
1267+
/// couldn't complete due to errors elsewhere - this is distinct
1268+
/// from `Ok(None)` to avoid misleading diagnostics when an error
1269+
/// has already been/will be emitted, for the original cause
1270+
query resolve_instance(
1271+
key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
1272+
) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
1273+
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
12631274
}
12641275
}
12651276
}

‎src/librustc_middle/ty/instance.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
22
use crate::ty::print::{FmtPrinter, Printer};
33
use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
4+
use rustc_errors::ErrorReported;
45
use rustc_hir::def::Namespace;
56
use rustc_hir::def_id::{CrateNum, DefId};
67
use rustc_hir::lang_items::DropInPlaceFnLangItem;
@@ -268,29 +269,41 @@ impl<'tcx> Instance<'tcx> {
268269
/// this is used to find the precise code that will run for a trait method invocation,
269270
/// if known.
270271
///
271-
/// Returns `None` if we cannot resolve `Instance` to a specific instance.
272+
/// Returns `Ok(None)` if we cannot resolve `Instance` to a specific instance.
272273
/// For example, in a context like this,
273274
///
274275
/// ```
275276
/// fn foo<T: Debug>(t: T) { ... }
276277
/// ```
277278
///
278-
/// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not
279+
/// trying to resolve `Debug::fmt` applied to `T` will yield `Ok(None)`, because we do not
279280
/// know what code ought to run. (Note that this setting is also affected by the
280281
/// `RevealMode` in the parameter environment.)
281282
///
282283
/// Presuming that coherence and type-check have succeeded, if this method is invoked
283284
/// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
284-
/// `Some`.
285+
/// `Ok(Some(instance))`.
286+
///
287+
/// Returns `Err(ErrorReported)` when the `Instance` resolution process
288+
/// couldn't complete due to errors elsewhere - this is distinct
289+
/// from `Ok(None)` to avoid misleading diagnostics when an error
290+
/// has already been/will be emitted, for the original cause
285291
pub fn resolve(
286292
tcx: TyCtxt<'tcx>,
287293
param_env: ty::ParamEnv<'tcx>,
288294
def_id: DefId,
289295
substs: SubstsRef<'tcx>,
290-
) -> Option<Instance<'tcx>> {
296+
) -> Result<Option<Instance<'tcx>>, ErrorReported> {
291297
// All regions in the result of this query are erased, so it's
292298
// fine to erase all of the input regions.
293-
tcx.resolve_instance((tcx.erase_regions(&param_env), def_id, tcx.erase_regions(&substs)))
299+
300+
// HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)`
301+
// below is more likely to ignore the bounds in scope (e.g. if the only
302+
// generic parameters mentioned by `substs` were lifetime ones).
303+
let substs = tcx.erase_regions(&substs);
304+
305+
// FIXME(eddyb) should this always use `param_env.with_reveal_all()`?
306+
tcx.resolve_instance(tcx.erase_regions(&param_env.and((def_id, substs))))
294307
}
295308

296309
pub fn resolve_for_fn_ptr(
@@ -300,7 +313,7 @@ impl<'tcx> Instance<'tcx> {
300313
substs: SubstsRef<'tcx>,
301314
) -> Option<Instance<'tcx>> {
302315
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
303-
Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| {
316+
Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| {
304317
match resolved.def {
305318
InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => {
306319
debug!(" => fn pointer created for function with #[track_caller]");
@@ -332,7 +345,7 @@ impl<'tcx> Instance<'tcx> {
332345
debug!(" => associated item with unsizeable self: Self");
333346
Some(Instance { def: InstanceDef::VtableShim(def_id), substs })
334347
} else {
335-
Instance::resolve(tcx, param_env, def_id, substs)
348+
Instance::resolve(tcx, param_env, def_id, substs).ok().flatten()
336349
}
337350
}
338351

@@ -353,7 +366,7 @@ impl<'tcx> Instance<'tcx> {
353366
pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
354367
let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None);
355368
let substs = tcx.intern_substs(&[ty.into()]);
356-
Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap()
369+
Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap()
357370
}
358371

359372
pub fn fn_once_adapter_instance(

‎src/librustc_middle/ty/query/keys.rs

-11
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,3 @@ impl Key for (Symbol, u32, u32) {
296296
DUMMY_SP
297297
}
298298
}
299-
300-
impl<'tcx> Key for (ty::ParamEnv<'tcx>, DefId, SubstsRef<'tcx>) {
301-
type CacheSelector = DefaultCacheSelector;
302-
303-
fn query_crate(&self) -> CrateNum {
304-
self.1.krate
305-
}
306-
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
307-
tcx.def_span(self.1)
308-
}
309-
}

‎src/librustc_mir/interpret/eval_context.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
461461
trace!("resolve: {:?}, {:#?}", def_id, substs);
462462
trace!("param_env: {:#?}", self.param_env);
463463
trace!("substs: {:#?}", substs);
464-
ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs)
465-
.ok_or_else(|| err_inval!(TooGeneric).into())
464+
match ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs) {
465+
Ok(Some(instance)) => Ok(instance),
466+
Ok(None) => throw_inval!(TooGeneric),
467+
468+
// FIXME(eddyb) this could be a bit more specific than `TypeckError`.
469+
Err(error_reported) => throw_inval!(TypeckError(error_reported)),
470+
}
466471
}
467472

468473
pub fn layout_of_local(

‎src/librustc_mir/monomorphize/collector.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -674,9 +674,12 @@ fn visit_fn_use<'tcx>(
674674
output: &mut Vec<MonoItem<'tcx>>,
675675
) {
676676
if let ty::FnDef(def_id, substs) = ty.kind {
677-
let resolver =
678-
if is_direct_call { ty::Instance::resolve } else { ty::Instance::resolve_for_fn_ptr };
679-
let instance = resolver(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap();
677+
let instance = if is_direct_call {
678+
ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap()
679+
} else {
680+
ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs)
681+
.unwrap()
682+
};
680683
visit_instance_use(tcx, instance, is_direct_call, output);
681684
}
682685
}
@@ -1056,6 +1059,7 @@ impl RootCollector<'_, 'v> {
10561059
start_def_id,
10571060
self.tcx.intern_substs(&[main_ret_ty.into()]),
10581061
)
1062+
.unwrap()
10591063
.unwrap();
10601064

10611065
self.output.push(create_fn_mono_item(start_instance));
@@ -1111,8 +1115,9 @@ fn create_mono_items_for_default_impls<'tcx>(
11111115
trait_ref.substs[param.index as usize]
11121116
}
11131117
});
1114-
let instance =
1115-
ty::Instance::resolve(tcx, param_env, method.def_id, substs).unwrap();
1118+
let instance = ty::Instance::resolve(tcx, param_env, method.def_id, substs)
1119+
.unwrap()
1120+
.unwrap();
11161121

11171122
let mono_item = create_fn_mono_item(instance);
11181123
if mono_item.is_instantiable(tcx) && should_monomorphize_locally(tcx, &instance)

‎src/librustc_mir/monomorphize/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn custom_coerce_unsize_info<'tcx>(
1818
});
1919

2020
match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) {
21-
Some(traits::VtableImpl(traits::VtableImplData { impl_def_id, .. })) => {
21+
Ok(traits::VtableImpl(traits::VtableImplData { impl_def_id, .. })) => {
2222
tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
2323
}
2424
vtable => {

‎src/librustc_mir/transform/check_consts/validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
522522
if self.tcx.features().const_trait_impl {
523523
let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs);
524524
debug!("Resolving ({:?}) -> {:?}", def_id, instance);
525-
if let Some(func) = instance {
525+
if let Ok(Some(func)) = instance {
526526
if let InstanceDef::Item(def_id) = func.def {
527527
if is_const_fn(self.tcx, def_id) {
528528
return;

‎src/librustc_mir/transform/inline.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ impl Inliner<'tcx> {
176176
let terminator = bb_data.terminator();
177177
if let TerminatorKind::Call { func: ref op, .. } = terminator.kind {
178178
if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).kind {
179-
let instance = Instance::resolve(self.tcx, param_env, callee_def_id, substs)?;
179+
let instance =
180+
Instance::resolve(self.tcx, param_env, callee_def_id, substs).ok().flatten()?;
180181

181182
if let InstanceDef::Virtual(..) = instance.def {
182183
return None;

‎src/librustc_mir_build/lints.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> {
7272
let func_ty = func.ty(body, tcx);
7373
if let ty::FnDef(fn_def_id, substs) = func_ty.kind {
7474
let (call_fn_id, call_substs) =
75-
if let Some(instance) = Instance::resolve(tcx, param_env, fn_def_id, substs) {
75+
if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, fn_def_id, substs) {
7676
(instance.def_id(), instance.substs)
7777
} else {
7878
(fn_def_id, substs)

‎src/librustc_trait_selection/traits/codegen/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt};
77
use crate::traits::{
88
FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable,
99
};
10+
use rustc_errors::ErrorReported;
1011
use rustc_middle::ty::fold::TypeFoldable;
1112
use rustc_middle::ty::{self, TyCtxt};
1213

@@ -19,7 +20,7 @@ use rustc_middle::ty::{self, TyCtxt};
1920
pub fn codegen_fulfill_obligation<'tcx>(
2021
ty: TyCtxt<'tcx>,
2122
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
22-
) -> Option<Vtable<'tcx, ()>> {
23+
) -> Result<Vtable<'tcx, ()>, ErrorReported> {
2324
// Remove any references to regions; this helps improve caching.
2425
let trait_ref = ty.erase_regions(&trait_ref);
2526

@@ -55,7 +56,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
5556
trait_ref
5657
),
5758
);
58-
return None;
59+
return Err(ErrorReported);
5960
}
6061
Err(e) => {
6162
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
@@ -75,7 +76,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
7576
let vtable = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &vtable);
7677

7778
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
78-
Some(vtable)
79+
Ok(vtable)
7980
})
8081
}
8182

‎src/librustc_ty/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ path = "lib.rs"
1212
log = "0.4"
1313
rustc_middle = { path = "../librustc_middle" }
1414
rustc_data_structures = { path = "../librustc_data_structures" }
15+
rustc_errors = { path = "../librustc_errors" }
1516
rustc_hir = { path = "../librustc_hir" }
1617
rustc_infer = { path = "../librustc_infer" }
1718
rustc_span = { path = "../librustc_span" }

0 commit comments

Comments
 (0)
Please sign in to comment.