Skip to content

Commit 214548b

Browse files
committed
Auto merge of #67631 - oli-obk:polymorphic_promotion, r=wesleywiser
Work around a resolve bug in const prop r? @wesleywiser @anp This isn't exposed right now, but further changes to rustc may start causing bugs without this.
2 parents 2ba0d2a + 5fd8abd commit 214548b

File tree

10 files changed

+223
-33
lines changed

10 files changed

+223
-33
lines changed

src/librustc/mir/interpret/queries.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl<'tcx> TyCtxt<'tcx> {
1818
let substs = InternalSubsts::identity_for_item(self, def_id);
1919
let instance = ty::Instance::new(def_id, substs);
2020
let cid = GlobalId { instance, promoted: None };
21-
let param_env = self.param_env(def_id);
21+
let param_env = self.param_env(def_id).with_reveal_all();
2222
self.const_eval_validated(param_env.and(cid))
2323
}
2424

src/librustc/traits/project.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
10281028
// In either case, we handle this by not adding a
10291029
// candidate for an impl if it contains a `default`
10301030
// type.
1031+
//
1032+
// NOTE: This should be kept in sync with the similar code in
1033+
// `rustc::ty::instance::resolve_associated_item()`.
10311034
let node_item =
10321035
assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id);
10331036

src/librustc/ty/instance.rs

+19
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,25 @@ fn resolve_associated_item<'tcx>(
346346
traits::VtableImpl(impl_data) => {
347347
let (def_id, substs) =
348348
traits::find_associated_item(tcx, param_env, trait_item, rcvr_substs, &impl_data);
349+
350+
let resolved_item = tcx.associated_item(def_id);
351+
352+
// Since this is a trait item, we need to see if the item is either a trait default item
353+
// or a specialization because we can't resolve those unless we can `Reveal::All`.
354+
// NOTE: This should be kept in sync with the similar code in
355+
// `rustc::traits::project::assemble_candidates_from_impls()`.
356+
let eligible = if !resolved_item.defaultness.is_default() {
357+
true
358+
} else if param_env.reveal == traits::Reveal::All {
359+
!trait_ref.needs_subst()
360+
} else {
361+
false
362+
};
363+
364+
if !eligible {
365+
return None;
366+
}
367+
349368
let substs = tcx.erase_regions(&substs);
350369
Some(ty::Instance::new(def_id, substs))
351370
}

src/librustc_mir/const_eval/eval_queries.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,7 @@ pub fn const_eval_validated_provider<'tcx>(
212212
key.param_env.reveal = Reveal::UserFacing;
213213
match tcx.const_eval_validated(key) {
214214
// try again with reveal all as requested
215-
Err(ErrorHandled::TooGeneric) => {
216-
// Promoteds should never be "too generic" when getting evaluated.
217-
// They either don't get evaluated, or we are in a monomorphic context
218-
assert!(key.value.promoted.is_none());
219-
}
215+
Err(ErrorHandled::TooGeneric) => {}
220216
// dedupliate calls
221217
other => return other,
222218
}
@@ -301,10 +297,18 @@ pub fn const_eval_raw_provider<'tcx>(
301297
// Ensure that if the above error was either `TooGeneric` or `Reported`
302298
// an error must be reported.
303299
let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer");
304-
tcx.sess.delay_span_bug(
305-
err.span,
306-
&format!("static eval failure did not emit an error: {:#?}", v),
307-
);
300+
301+
// If this is `Reveal:All`, then we need to make sure an error is reported but if
302+
// this is `Reveal::UserFacing`, then it's expected that we could get a
303+
// `TooGeneric` error. When we fall back to `Reveal::All`, then it will either
304+
// succeed or we'll report this error then.
305+
if key.param_env.reveal == Reveal::All {
306+
tcx.sess.delay_span_bug(
307+
err.span,
308+
&format!("static eval failure did not emit an error: {:#?}", v),
309+
);
310+
}
311+
308312
v
309313
} else if def_id.is_local() {
310314
// constant defined in this crate, we can figure out a lint level!

src/librustc_mir/hair/pattern/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
742742
let kind = match res {
743743
Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
744744
let substs = self.tables.node_substs(id);
745-
match self.tcx.const_eval_resolve(self.param_env, def_id, substs, Some(span)) {
745+
// Use `Reveal::All` here because patterns are always monomorphic even if their function isn't.
746+
match self.tcx.const_eval_resolve(
747+
self.param_env.with_reveal_all(),
748+
def_id,
749+
substs,
750+
Some(span),
751+
) {
746752
Ok(value) => {
747753
let pattern = self.const_to_pat(value, id, span);
748754
if !is_associated_const {

src/librustc_mir/transform/const_prop.rs

+52-19
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::cell::Cell;
66

77
use rustc::hir::def::DefKind;
88
use rustc::hir::def_id::DefId;
9+
use rustc::hir::HirId;
910
use rustc::mir::interpret::{InterpResult, PanicInfo, Scalar};
1011
use rustc::mir::visit::{
1112
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
@@ -20,7 +21,7 @@ use rustc::ty::layout::{
2021
HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
2122
};
2223
use rustc::ty::subst::InternalSubsts;
23-
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
24+
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
2425
use rustc_data_structures::fx::FxHashMap;
2526
use rustc_index::vec::IndexVec;
2627
use syntax::ast::Mutability;
@@ -260,6 +261,9 @@ struct ConstPropagator<'mir, 'tcx> {
260261
source_scopes: IndexVec<SourceScope, SourceScopeData>,
261262
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
262263
ret: Option<OpTy<'tcx, ()>>,
264+
// Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
265+
// the last known `SourceInfo` here and just keep revisiting it.
266+
source_info: Option<SourceInfo>,
263267
}
264268

265269
impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
@@ -293,13 +297,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
293297
source: MirSource<'tcx>,
294298
) -> ConstPropagator<'mir, 'tcx> {
295299
let def_id = source.def_id();
296-
let param_env = tcx.param_env(def_id);
300+
let substs = &InternalSubsts::identity_for_item(tcx, def_id);
301+
let mut param_env = tcx.param_env(def_id);
302+
303+
// If we're evaluating inside a monomorphic function, then use `Reveal::All` because
304+
// we want to see the same instances that codegen will see. This allows us to `resolve()`
305+
// specializations.
306+
if !substs.needs_subst() {
307+
param_env = param_env.with_reveal_all();
308+
}
309+
297310
let span = tcx.def_span(def_id);
298311
let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine, ());
299312
let can_const_prop = CanConstProp::check(body);
300313

301-
let substs = &InternalSubsts::identity_for_item(tcx, def_id);
302-
303314
let ret = ecx
304315
.layout_of(body.return_ty().subst(tcx, substs))
305316
.ok()
@@ -331,6 +342,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
331342
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
332343
local_decls: body.local_decls.clone(),
333344
ret: ret.map(Into::into),
345+
source_info: None,
334346
}
335347
}
336348

@@ -352,6 +364,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
352364
LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
353365
}
354366

367+
fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
368+
match &self.source_scopes[source_info.scope].local_data {
369+
ClearCrossCrate::Set(data) => Some(data.lint_root),
370+
ClearCrossCrate::Clear => None,
371+
}
372+
}
373+
355374
fn use_ecx<F, T>(&mut self, source_info: SourceInfo, f: F) -> Option<T>
356375
where
357376
F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
@@ -360,10 +379,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
360379
// FIXME(eddyb) move this to the `Panic(_)` error case, so that
361380
// `f(self)` is always called, and that the only difference when the
362381
// scope's `local_data` is missing, is that the lint isn't emitted.
363-
let lint_root = match &self.source_scopes[source_info.scope].local_data {
364-
ClearCrossCrate::Set(data) => data.lint_root,
365-
ClearCrossCrate::Clear => return None,
366-
};
382+
let lint_root = self.lint_root(source_info)?;
367383
let r = match f(self) {
368384
Ok(val) => Some(val),
369385
Err(error) => {
@@ -409,13 +425,31 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
409425
r
410426
}
411427

412-
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
428+
fn eval_constant(
429+
&mut self,
430+
c: &Constant<'tcx>,
431+
source_info: SourceInfo,
432+
) -> Option<Const<'tcx>> {
413433
self.ecx.tcx.span = c.span;
414434
match self.ecx.eval_const_to_op(c.literal, None) {
415435
Ok(op) => Some(op),
416436
Err(error) => {
417437
let err = error_to_const_error(&self.ecx, error);
418-
err.report_as_error(self.ecx.tcx, "erroneous constant used");
438+
match self.lint_root(source_info) {
439+
Some(lint_root) if c.literal.needs_subst() => {
440+
// Out of backwards compatibility we cannot report hard errors in unused
441+
// generic functions using associated constants of the generic parameters.
442+
err.report_as_lint(
443+
self.ecx.tcx,
444+
"erroneous constant used",
445+
lint_root,
446+
Some(c.span),
447+
);
448+
}
449+
_ => {
450+
err.report_as_error(self.ecx.tcx, "erroneous constant used");
451+
}
452+
}
419453
None
420454
}
421455
}
@@ -428,7 +462,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
428462

429463
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
430464
match *op {
431-
Operand::Constant(ref c) => self.eval_constant(c),
465+
Operand::Constant(ref c) => self.eval_constant(c, source_info),
432466
Operand::Move(ref place) | Operand::Copy(ref place) => {
433467
self.eval_place(place, source_info)
434468
}
@@ -495,10 +529,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
495529
let right_size = r.layout.size;
496530
let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
497531
if r_bits.map_or(false, |b| b >= left_bits as u128) {
498-
let lint_root = match &self.source_scopes[source_info.scope].local_data {
499-
ClearCrossCrate::Set(data) => data.lint_root,
500-
ClearCrossCrate::Clear => return None,
501-
};
532+
let lint_root = self.lint_root(source_info)?;
502533
let dir = if *op == BinOp::Shr { "right" } else { "left" };
503534
self.tcx.lint_hir(
504535
::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
@@ -748,18 +779,19 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
748779
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
749780
trace!("visit_constant: {:?}", constant);
750781
self.super_constant(constant, location);
751-
self.eval_constant(constant);
782+
self.eval_constant(constant, self.source_info.unwrap());
752783
}
753784

754785
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
755786
trace!("visit_statement: {:?}", statement);
787+
let source_info = statement.source_info;
788+
self.source_info = Some(source_info);
756789
if let StatementKind::Assign(box (ref place, ref mut rval)) = statement.kind {
757790
let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
758791
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
759792
if let Some(local) = place.as_local() {
760-
let source = statement.source_info;
761793
let can_const_prop = self.can_const_prop[local];
762-
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
794+
if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
763795
if can_const_prop == ConstPropMode::FullConstProp
764796
|| can_const_prop == ConstPropMode::OnlyPropagateInto
765797
{
@@ -802,8 +834,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
802834
}
803835

804836
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
805-
self.super_terminator(terminator, location);
806837
let source_info = terminator.source_info;
838+
self.source_info = Some(source_info);
839+
self.super_terminator(terminator, location);
807840
match &mut terminator.kind {
808841
TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
809842
if let Some(value) = self.eval_operand(&cond, source_info) {

src/librustc_mir/transform/inline.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use rustc_index::vec::{Idx, IndexVec};
88

99
use rustc::mir::visit::*;
1010
use rustc::mir::*;
11-
use rustc::ty::subst::{Subst, SubstsRef};
12-
use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
11+
use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
12+
use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
1313

1414
use super::simplify::{remove_dead_blocks, CfgSimplifier};
1515
use crate::transform::{MirPass, MirSource};
@@ -66,7 +66,14 @@ impl Inliner<'tcx> {
6666

6767
let mut callsites = VecDeque::new();
6868

69-
let param_env = self.tcx.param_env(self.source.def_id());
69+
let mut param_env = self.tcx.param_env(self.source.def_id());
70+
71+
let substs = &InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
72+
73+
// For monomorphic functions, we can use `Reveal::All` to resolve specialized instances.
74+
if !substs.needs_subst() {
75+
param_env = param_env.with_reveal_all();
76+
}
7077

7178
// Only do inlining into fn bodies.
7279
let id = self.tcx.hir().as_local_hir_id(self.source.def_id()).unwrap();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#![feature(specialization)]
2+
3+
fn main() {
4+
let x = <Vec::<()> as Foo>::bar();
5+
}
6+
7+
trait Foo {
8+
fn bar() -> u32;
9+
}
10+
11+
impl<T> Foo for Vec<T> {
12+
#[inline(always)]
13+
default fn bar() -> u32 { 123 }
14+
}
15+
16+
// END RUST SOURCE
17+
// START rustc.main.Inline.before.mir
18+
// let mut _0: ();
19+
// let _1: u32;
20+
// scope 1 {
21+
// debug x => _1;
22+
// }
23+
// bb0: {
24+
// StorageLive(_1);
25+
// _1 = const <std::vec::Vec<()> as Foo>::bar() -> bb1;
26+
// }
27+
// bb1: {
28+
// _0 = ();
29+
// StorageDead(_1);
30+
// return;
31+
// }
32+
// END rustc.main.Inline.before.mir
33+
// START rustc.main.Inline.after.mir
34+
// let mut _0: ();
35+
// let _1: u32;
36+
// scope 1 {
37+
// debug x => _1;
38+
// }
39+
// scope 2 {
40+
// }
41+
// bb0: {
42+
// StorageLive(_1);
43+
// _1 = const 123u32;
44+
// _0 = ();
45+
// StorageDead(_1);
46+
// return;
47+
// }
48+
// END rustc.main.Inline.after.mir

0 commit comments

Comments
 (0)