]> git.lizzy.rs Git - rust.git/commitdiff
Make the translation item collector handle *uses* of 'const' items instead of declara...
authorMichael Woerister <michaelwoerister@posteo.net>
Fri, 22 Jul 2016 16:14:26 +0000 (12:14 -0400)
committerMichael Woerister <michaelwoerister@posteo.net>
Fri, 12 Aug 2016 16:07:51 +0000 (12:07 -0400)
src/librustc_trans/collector.rs
src/test/codegen-units/partitioning/vtable-through-const.rs [new file with mode: 0644]

index 4a6dbb2bdae56d746926987e2a7921357e1eadbb..794da0d1473bd12b900d0aad7d842074f52c2dc8 100644 (file)
 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 @@ fn visit_operand(&mut self, operand: &mir::Operand<'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 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                 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 (file)
index 0000000..b40bb7f
--- /dev/null
@@ -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