mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Auto merge of #35534 - michaelwoerister:fix-const-collection2, r=nikomatsakis
Make the translation item collector handle *uses* of 'const' items instead of declarations. This should fix issue #34754.
This commit is contained in:
commit
2e29b126b6
@ -202,10 +202,11 @@ use rustc::mir::repr as mir;
|
|||||||
use rustc::mir::visit as mir_visit;
|
use rustc::mir::visit as mir_visit;
|
||||||
use rustc::mir::visit::Visitor as MirVisitor;
|
use rustc::mir::visit::Visitor as MirVisitor;
|
||||||
|
|
||||||
|
use rustc_const_eval as const_eval;
|
||||||
|
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use errors;
|
use errors;
|
||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
use syntax::ast::NodeId;
|
|
||||||
use base::custom_coerce_unsize_info;
|
use base::custom_coerce_unsize_info;
|
||||||
use context::SharedCrateContext;
|
use context::SharedCrateContext;
|
||||||
use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
|
use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
|
||||||
@ -543,9 +544,46 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||||||
debug!("visiting operand {:?}", *operand);
|
debug!("visiting operand {:?}", *operand);
|
||||||
|
|
||||||
let callee = match *operand {
|
let callee = match *operand {
|
||||||
mir::Operand::Constant(mir::Constant { ty: &ty::TyS {
|
mir::Operand::Constant(ref constant) => {
|
||||||
sty: ty::TyFnDef(def_id, substs, _), ..
|
if let ty::TyFnDef(def_id, substs, _) = constant.ty.sty {
|
||||||
}, .. }) => Some((def_id, substs)),
|
// This is something that can act as a callee, proceed
|
||||||
|
Some((def_id, substs))
|
||||||
|
} else {
|
||||||
|
// This is not a callee, but we still have to look for
|
||||||
|
// references to `const` items
|
||||||
|
if let mir::Literal::Item { def_id, substs } = constant.literal {
|
||||||
|
let tcx = self.scx.tcx();
|
||||||
|
let substs = monomorphize::apply_param_substs(tcx,
|
||||||
|
self.param_substs,
|
||||||
|
&substs);
|
||||||
|
|
||||||
|
// If the constant referred to here is an associated
|
||||||
|
// item of a trait, we need to resolve it to the actual
|
||||||
|
// constant in the corresponding impl. Luckily
|
||||||
|
// const_eval::lookup_const_by_id() does that for us.
|
||||||
|
if let Some((expr, _)) = const_eval::lookup_const_by_id(tcx,
|
||||||
|
def_id,
|
||||||
|
Some(substs)) {
|
||||||
|
// The hir::Expr we get here is the initializer of
|
||||||
|
// the constant, what we really want is the item
|
||||||
|
// DefId.
|
||||||
|
let const_node_id = tcx.map.get_parent(expr.id);
|
||||||
|
let def_id = if tcx.map.is_inlined_node_id(const_node_id) {
|
||||||
|
tcx.sess.cstore.defid_for_inlined_node(const_node_id).unwrap()
|
||||||
|
} else {
|
||||||
|
tcx.map.local_def_id(const_node_id)
|
||||||
|
};
|
||||||
|
|
||||||
|
collect_const_item_neighbours(self.scx,
|
||||||
|
def_id,
|
||||||
|
substs,
|
||||||
|
self.output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1117,10 +1155,8 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
|
|||||||
self.output.push(TransItem::Static(item.id));
|
self.output.push(TransItem::Static(item.id));
|
||||||
}
|
}
|
||||||
hir::ItemConst(..) => {
|
hir::ItemConst(..) => {
|
||||||
debug!("RootCollector: ItemConst({})",
|
// const items only generate translation items if they are
|
||||||
def_id_to_string(self.scx.tcx(),
|
// actually used somewhere. Just declaring them is insufficient.
|
||||||
self.scx.tcx().map.local_def_id(item.id)));
|
|
||||||
add_roots_for_const_item(self.scx, item.id, self.output);
|
|
||||||
}
|
}
|
||||||
hir::ItemFn(_, _, _, _, ref generics, _) => {
|
hir::ItemFn(_, _, _, _, ref generics, _) => {
|
||||||
if !generics.is_type_parameterized() {
|
if !generics.is_type_parameterized() {
|
||||||
@ -1244,23 +1280,21 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
// There are no translation items for constants themselves but their
|
// There are no translation items for constants themselves but their
|
||||||
// initializers might still contain something that produces translation items,
|
// initializers might still contain something that produces translation items,
|
||||||
// such as cast that introduce a new vtable.
|
// such as cast that introduce a new vtable.
|
||||||
fn add_roots_for_const_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
||||||
const_item_node_id: NodeId,
|
def_id: DefId,
|
||||||
output: &mut Vec<TransItem<'tcx>>)
|
substs: &'tcx Substs<'tcx>,
|
||||||
|
output: &mut Vec<TransItem<'tcx>>)
|
||||||
{
|
{
|
||||||
let def_id = scx.tcx().map.local_def_id(const_item_node_id);
|
|
||||||
|
|
||||||
// Scan the MIR in order to find function calls, closures, and
|
// Scan the MIR in order to find function calls, closures, and
|
||||||
// drop-glue
|
// drop-glue
|
||||||
let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(def_id),
|
let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(def_id),
|
||||||
|| format!("Could not find MIR for const: {:?}", def_id));
|
|| format!("Could not find MIR for const: {:?}", def_id));
|
||||||
|
|
||||||
let empty_substs = scx.empty_substs_for_def_id(def_id);
|
|
||||||
let visitor = MirNeighborCollector {
|
let visitor = MirNeighborCollector {
|
||||||
scx: scx,
|
scx: scx,
|
||||||
mir: &mir,
|
mir: &mir,
|
||||||
output: output,
|
output: output,
|
||||||
param_substs: empty_substs
|
param_substs: substs
|
||||||
};
|
};
|
||||||
|
|
||||||
visit_mir_and_promoted(visitor, &mir);
|
visit_mir_and_promoted(visitor, &mir);
|
||||||
|
93
src/test/codegen-units/partitioning/vtable-through-const.rs
Normal file
93
src/test/codegen-units/partitioning/vtable-through-const.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
// We specify -Z incremental here because we want to test the partitioning for
|
||||||
|
// incremental compilation
|
||||||
|
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const
|
||||||
|
|
||||||
|
// This test case makes sure, that references made through constants are
|
||||||
|
// recorded properly in the InliningMap.
|
||||||
|
|
||||||
|
mod mod1 {
|
||||||
|
pub trait Trait1 {
|
||||||
|
fn do_something(&self) {}
|
||||||
|
fn do_something_else(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait1 for u32 {}
|
||||||
|
|
||||||
|
pub trait Trait1Gen<T> {
|
||||||
|
fn do_something(&self, x: T) -> T;
|
||||||
|
fn do_something_else(&self, x: T) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Trait1Gen<T> for u32 {
|
||||||
|
fn do_something(&self, x: T) -> T { x }
|
||||||
|
fn do_something_else(&self, x: T) -> T { x }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id<T>(x: T) -> T { x }
|
||||||
|
|
||||||
|
// These are referenced, so they produce trans-items (see main())
|
||||||
|
pub const TRAIT1_REF: &'static Trait1 = &0u32 as &Trait1;
|
||||||
|
pub const TRAIT1_GEN_REF: &'static Trait1Gen<u8> = &0u32 as &Trait1Gen<u8>;
|
||||||
|
pub const ID_CHAR: fn(char) -> char = id::<char>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub trait Trait2 {
|
||||||
|
fn do_something(&self) {}
|
||||||
|
fn do_something_else(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait2 for u32 {}
|
||||||
|
|
||||||
|
pub trait Trait2Gen<T> {
|
||||||
|
fn do_something(&self, x: T) -> T;
|
||||||
|
fn do_something_else(&self, x: T) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Trait2Gen<T> for u32 {
|
||||||
|
fn do_something(&self, x: T) -> T { x }
|
||||||
|
fn do_something_else(&self, x: T) -> T { x }
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are not referenced, so they do not produce trans-items
|
||||||
|
pub const TRAIT2_REF: &'static Trait2 = &0u32 as &Trait2;
|
||||||
|
pub const TRAIT2_GEN_REF: &'static Trait2Gen<u8> = &0u32 as &Trait2Gen<u8>;
|
||||||
|
pub const ID_I64: fn(i64) -> i64 = id::<i64>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ TRANS_ITEM fn vtable_through_const::main[0] @@ vtable_through_const[External]
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
// Since Trait1::do_something() is instantiated via its default implementation,
|
||||||
|
// it is considered a generic and is instantiated here only because it is
|
||||||
|
// referenced in this module.
|
||||||
|
//~ TRANS_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0]<u32> @@ vtable_through_const[Internal]
|
||||||
|
|
||||||
|
// Although it is never used, Trait1::do_something_else() has to be
|
||||||
|
// instantiated locally here too, otherwise the <&u32 as &Trait1> vtable
|
||||||
|
// could not be fully constructed.
|
||||||
|
//~ TRANS_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0]<u32> @@ vtable_through_const[Internal]
|
||||||
|
mod1::TRAIT1_REF.do_something();
|
||||||
|
|
||||||
|
// Same as above
|
||||||
|
//~ TRANS_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0]<u8> @@ vtable_through_const[Internal]
|
||||||
|
//~ TRANS_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0]<u8> @@ vtable_through_const[Internal]
|
||||||
|
mod1::TRAIT1_GEN_REF.do_something(0u8);
|
||||||
|
|
||||||
|
//~ TRANS_ITEM fn vtable_through_const::mod1[0]::id[0]<char> @@ vtable_through_const[Internal]
|
||||||
|
mod1::ID_CHAR('x');
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ TRANS_ITEM drop-glue i8
|
Loading…
Reference in New Issue
Block a user