diff options
| author | bors <bors@rust-lang.org> | 2016-08-14 06:42:16 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-08-14 06:42:16 -0700 |
| commit | 2e29b126b60a19f491e7f1845dd98df50700e37a (patch) | |
| tree | 9ecd0f7505d4fd68ee8bedbf86633c4ad67ad93a | |
| parent | d927fa48567ea9ebb2128a2271459c1257639292 (diff) | |
| parent | 09e73a5b0315f507e0659e62a56a34bba03c2581 (diff) | |
| download | rust-2e29b126b60a19f491e7f1845dd98df50700e37a.tar.gz rust-2e29b126b60a19f491e7f1845dd98df50700e37a.zip | |
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.
| -rw-r--r-- | src/librustc_trans/collector.rs | 64 | ||||
| -rw-r--r-- | src/test/codegen-units/partitioning/vtable-through-const.rs | 93 |
2 files changed, 142 insertions, 15 deletions
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 4a6dbb2bdae..794da0d1473 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -202,10 +202,11 @@ use rustc::mir::repr as mir; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; +use rustc_const_eval as const_eval; + use syntax::abi::Abi; use errors; use syntax_pos::DUMMY_SP; -use syntax::ast::NodeId; use base::custom_coerce_unsize_info; use context::SharedCrateContext; 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); let callee = match *operand { - mir::Operand::Constant(mir::Constant { ty: &ty::TyS { - sty: ty::TyFnDef(def_id, substs, _), .. - }, .. }) => Some((def_id, substs)), + mir::Operand::Constant(ref constant) => { + if let ty::TyFnDef(def_id, substs, _) = constant.ty.sty { + // 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 }; @@ -1117,10 +1155,8 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { self.output.push(TransItem::Static(item.id)); } hir::ItemConst(..) => { - debug!("RootCollector: ItemConst({})", - def_id_to_string(self.scx.tcx(), - self.scx.tcx().map.local_def_id(item.id))); - add_roots_for_const_item(self.scx, item.id, self.output); + // const items only generate translation items if they are + // actually used somewhere. Just declaring them is insufficient. } hir::ItemFn(_, _, _, _, ref generics, _) => { 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 // initializers might still contain something that produces translation items, // such as cast that introduce a new vtable. -fn add_roots_for_const_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - const_item_node_id: NodeId, - output: &mut Vec<TransItem<'tcx>>) +fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + def_id: DefId, + 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 // drop-glue let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(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 { scx: scx, mir: &mir, output: output, - param_substs: empty_substs + param_substs: substs }; visit_mir_and_promoted(visitor, &mir); diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs new file mode 100644 index 00000000000..b40bb7f6097 --- /dev/null +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -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 |
