1
Fork 0

Auto merge of #30900 - michaelwoerister:trans_item_collect, r=nikomatsakis

The purpose of the translation item collector is to find all monomorphic instances of functions, methods and statics that need to be translated into LLVM IR in order to compile the current crate.

So far these instances have been discovered lazily during the trans path. For incremental compilation we want to know the set of these instances in advance, and that is what the trans::collect module provides.
In the future, incremental and regular translation will be driven by the collector implemented here.

r? @nikomatsakis
cc @rust-lang/compiler

Translation Item Collection
===========================

This module is responsible for discovering all items that will contribute to
to code generation of the crate. The important part here is that it not only
needs to find syntax-level items (functions, structs, etc) but also all
their monomorphized instantiations. Every non-generic, non-const function
maps to one LLVM artifact. Every generic function can produce
from zero to N artifacts, depending on the sets of type arguments it
is instantiated with.
This also applies to generic items from other crates: A generic definition
in crate X might produce monomorphizations that are compiled into crate Y.
We also have to collect these here.

The following kinds of "translation items" are handled here:

 - Functions
 - Methods
 - Closures
 - Statics
 - Drop glue

The following things also result in LLVM artifacts, but are not collected
here, since we instantiate them locally on demand when needed in a given
codegen unit:

 - Constants
 - Vtables
 - Object Shims

General Algorithm
-----------------
Let's define some terms first:

 - A "translation item" is something that results in a function or global in
   the LLVM IR of a codegen unit. Translation items do not stand on their
   own, they can reference other translation items. For example, if function
   `foo()` calls function `bar()` then the translation item for `foo()`
   references the translation item for function `bar()`. In general, the
   definition for translation item A referencing a translation item B is that
   the LLVM artifact produced for A references the LLVM artifact produced
   for B.

 - Translation items and the references between them for a directed graph,
   where the translation items are the nodes and references form the edges.
   Let's call this graph the "translation item graph".

 - The translation item graph for a program contains all translation items
   that are needed in order to produce the complete LLVM IR of the program.

The purpose of the algorithm implemented in this module is to build the
translation item graph for the current crate. It runs in two phases:

 1. Discover the roots of the graph by traversing the HIR of the crate.
 2. Starting from the roots, find neighboring nodes by inspecting the MIR
    representation of the item corresponding to a given node, until no more
    new nodes are found.

The roots of the translation item graph correspond to the non-generic
syntactic items in the source code. We find them by walking the HIR of the
crate, and whenever we hit upon a function, method, or static item, we
create a translation item consisting of the items DefId and, since we only
consider non-generic items, an empty type-substitution set.

Given a translation item node, we can discover neighbors by inspecting its
MIR. We walk the MIR and any time we hit upon something that signifies a
reference to another translation item, we have found a neighbor. Since the
translation item we are currently at is always monomorphic, we also know the
concrete type arguments of its neighbors, and so all neighbors again will be
monomorphic. The specific forms a reference to a neighboring node can take
in MIR are quite diverse. Here is an overview:

The most obvious form of one translation item referencing another is a
function or method call (represented by a CALL terminator in MIR). But
calls are not the only thing that might introduce a reference between two
function translation items, and as we will see below, they are just a
specialized of the form described next, and consequently will don't get any
special treatment in the algorithm.

A function does not need to actually be called in order to be a neighbor of
another function. It suffices to just take a reference in order to introduce
an edge. Consider the following example:

```rust
fn print_val<T: Display>(x: T) {
    println!("{}", x);
}

fn call_fn(f: &Fn(i32), x: i32) {
    f(x);
}

fn main() {
    let print_i32 = print_val::<i32>;
    call_fn(&print_i32, 0);
}
```
The MIR of none of these functions will contain an explicit call to
`print_val::<i32>`. Nonetheless, in order to translate this program, we need
an instance of this function. Thus, whenever we encounter a function or
method in operand position, we treat it as a neighbor of the current
translation item. Calls are just a special case of that.

In a way, closures are a simple case. Since every closure object needs to be
constructed somewhere, we can reliably discover them by observing
`RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also
true for closures inlined from other crates.

Drop glue translation items are introduced by MIR drop-statements. The
generated translation item will again have drop-glue item neighbors if the
type to be dropped contains nested values that also need to be dropped. It
might also have a function item neighbor for the explicit `Drop::drop`
implementation of its type.

A subtle way of introducing neighbor edges is by casting to a trait object.
Since the resulting fat-pointer contains a reference to a vtable, we need to
instantiate all object-save methods of the trait, as we need to store
pointers to these functions even if they never get called anywhere. This can
be seen as a special case of taking a function reference.

Since `Box` expression have special compiler support, no explicit calls to
`exchange_malloc()` and `exchange_free()` may show up in MIR, even if the
compiler will generate them. We have to observe `Rvalue::Box` expressions
and Box-typed drop-statements for that purpose.

Interaction with Cross-Crate Inlining
-------------------------------------
The binary of a crate will not only contain machine code for the items
defined in the source code of that crate. It will also contain monomorphic
instantiations of any extern generic functions and of functions marked with
The collection algorithm handles this more or less transparently. When
constructing a neighbor node for an item, the algorithm will always call
`inline::get_local_instance()` before proceeding. If no local instance can
be acquired (e.g. for a function that is just linked to) no node is created;
which is exactly what we want, since no machine code should be generated in
the current crate for such an item. On the other hand, if we can
successfully inline the function, we subsequently can just treat it like a
local item, walking it's MIR et cetera.

Eager and Lazy Collection Mode
------------------------------
Translation item collection can be performed in one of two modes:

 - Lazy mode means that items will only be instantiated when actually
   referenced. The goal is to produce the least amount of machine code
   possible.

 - Eager mode is meant to be used in conjunction with incremental compilation
   where a stable set of translation items is more important than a minimal
   one. Thus, eager mode will instantiate drop-glue for every drop-able type
   in the crate, even of no drop call for that type exists (yet). It will
   also instantiate default implementations of trait methods, something that
   otherwise is only done on demand.

Open Issues
-----------
Some things are not yet fully implemented in the current version of this
module.

Since no MIR is constructed yet for initializer expressions of constants and
statics we cannot inspect these properly.

Ideally, no translation item should be generated for const fns unless there
is a call to them that cannot be evaluated at compile time. At the moment
this is not implemented however: a translation item will be produced
regardless of whether it is actually needed or not.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/rust-lang/rust/30900)
<!-- Reviewable:end -->
This commit is contained in:
bors 2016-01-29 03:41:44 +00:00
commit 53c2933d44
46 changed files with 3342 additions and 74 deletions

1
configure vendored
View file

@ -1409,6 +1409,7 @@ do
make_dir $h/test/debuginfo-gdb
make_dir $h/test/debuginfo-lldb
make_dir $h/test/codegen
make_dir $h/test/codegen-units
make_dir $h/test/rustdoc
done

View file

@ -310,6 +310,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-gdb-exec \
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-lldb-exec \
check-stage$(1)-T-$(2)-H-$(3)-codegen-exec \
check-stage$(1)-T-$(2)-H-$(3)-codegen-units-exec \
check-stage$(1)-T-$(2)-H-$(3)-doc-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-exec
@ -473,6 +474,7 @@ DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs)
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
CODEGEN_UNITS_RS := $(wildcard $(S)src/test/codegen-units/*.rs)
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
RPASS_TESTS := $(RPASS_RS)
@ -488,6 +490,7 @@ PRETTY_TESTS := $(PRETTY_RS)
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS)
RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
CTEST_SRC_BASE_rpass = run-pass
@ -550,6 +553,11 @@ CTEST_BUILD_BASE_codegen = codegen
CTEST_MODE_codegen = codegen
CTEST_RUNTOOL_codegen = $(CTEST_RUNTOOL)
CTEST_SRC_BASE_codegen-units = codegen-units
CTEST_BUILD_BASE_codegen-units = codegen-units
CTEST_MODE_codegen-units = codegen-units
CTEST_RUNTOOL_codegen-units = $(CTEST_RUNTOOL)
CTEST_SRC_BASE_rustdocck = rustdoc
CTEST_BUILD_BASE_rustdocck = rustdoc
CTEST_MODE_rustdocck = rustdoc
@ -673,6 +681,7 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
$(S)src/etc/lldb_batchmode.py \
$(S)src/etc/lldb_rust_formatters.py
CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
CTEST_DEPS_codegen-units_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_UNITS_TESTS)
CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
$(S)src/etc/htmldocck.py
@ -739,7 +748,7 @@ endif
endef
CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
bench debuginfo-gdb debuginfo-lldb codegen rustdocck
bench debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck
$(foreach host,$(CFG_HOST), \
$(eval $(foreach target,$(CFG_TARGET), \
@ -917,6 +926,7 @@ TEST_GROUPS = \
debuginfo-gdb \
debuginfo-lldb \
codegen \
codegen-units \
doc \
$(foreach docname,$(DOC_NAMES),doc-$(docname)) \
pretty \

View file

@ -25,6 +25,7 @@ pub enum Mode {
DebugInfoLldb,
Codegen,
Rustdoc,
CodegenUnits
}
impl FromStr for Mode {
@ -41,6 +42,7 @@ impl FromStr for Mode {
"debuginfo-gdb" => Ok(DebugInfoGdb),
"codegen" => Ok(Codegen),
"rustdoc" => Ok(Rustdoc),
"codegen-units" => Ok(CodegenUnits),
_ => Err(()),
}
}
@ -59,6 +61,7 @@ impl fmt::Display for Mode {
DebugInfoLldb => "debuginfo-lldb",
Codegen => "codegen",
Rustdoc => "rustdoc",
CodegenUnits => "codegen-units",
}, f)
}
}

View file

@ -10,7 +10,7 @@
use common::Config;
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc};
use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
use errors;
use header::TestProps;
use header;
@ -18,6 +18,7 @@ use procsrv;
use util::logv;
use std::env;
use std::collections::HashSet;
use std::fmt;
use std::fs::{self, File};
use std::io::BufReader;
@ -56,6 +57,7 @@ pub fn run(config: Config, testfile: &Path) {
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
Codegen => run_codegen_test(&config, &props, &testfile),
Rustdoc => run_rustdoc_test(&config, &props, &testfile),
CodegenUnits => run_codegen_units_test(&config, &props, &testfile),
}
}
@ -1747,3 +1749,44 @@ fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) {
fatal_proc_rec("htmldocck failed!", &res);
}
}
fn run_codegen_units_test(config: &Config, props: &TestProps, testfile: &Path) {
let proc_res = compile_test(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
}
check_no_compiler_crash(&proc_res);
let prefix = "TRANS_ITEM ";
let actual: HashSet<String> = proc_res
.stdout
.lines()
.filter(|line| line.starts_with(prefix))
.map(|s| (&s[prefix.len()..]).to_string())
.collect();
let expected: HashSet<String> = errors::load_errors(testfile)
.iter()
.map(|e| e.msg.trim().to_string())
.collect();
if actual != expected {
let mut missing: Vec<_> = expected.difference(&actual).collect();
missing.sort();
let mut too_much: Vec<_> = actual.difference(&expected).collect();
too_much.sort();
println!("Expected and actual sets of codegen-items differ.\n\
These items should have been contained but were not:\n\n\
{}\n\n\
These items were contained but should not have been:\n\n\
{}\n\n",
missing.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2),
too_much.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2));
panic!();
}
}

View file

@ -196,33 +196,33 @@ impl DefPathData {
PositionalField |
Field(hir::StructFieldKind::UnnamedField(_)) => {
InternedString::new("<field>")
InternedString::new("{{field}}")
}
// note that this does not show up in user printouts
CrateRoot => {
InternedString::new("<root>")
InternedString::new("{{root}}")
}
// note that this does not show up in user printouts
InlinedRoot(_) => {
InternedString::new("<inlined-root>")
InternedString::new("{{inlined-root}}")
}
Misc => {
InternedString::new("?")
InternedString::new("{{?}}")
}
ClosureExpr => {
InternedString::new("<closure>")
InternedString::new("{{closure}}")
}
StructCtor => {
InternedString::new("<constructor>")
InternedString::new("{{constructor}}")
}
Initializer => {
InternedString::new("<initializer>")
InternedString::new("{{initializer}}")
}
}
}

View file

@ -223,6 +223,8 @@ pub trait CrateStore<'tcx> : Any {
-> FoundAst<'tcx>;
fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId)
-> Option<Mir<'tcx>>;
fn is_item_mir_available(&self, def: DefId) -> bool;
// This is basically a 1-based range of ints, which is a little
// silly - I may fix that.
fn crates(&self) -> Vec<ast::CrateNum>;
@ -401,6 +403,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
-> FoundAst<'tcx> { unimplemented!() }
fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId)
-> Option<Mir<'tcx>> { unimplemented!() }
fn is_item_mir_available(&self, def: DefId) -> bool {
unimplemented!()
}
// This is basically a 1-based range of ints, which is a little
// silly - I may fix that.

View file

@ -563,7 +563,7 @@ impl<'tcx> ctxt<'tcx> {
const_qualif_map: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap()),
fragment_infos: RefCell::new(DefIdMap())
}, f)
}
}

View file

@ -13,7 +13,7 @@ use middle::def_id::DefId;
use middle::ty;
use std::marker::PhantomData;
use std::rc::Rc;
use syntax::attr;
use syntax::{attr, ast};
macro_rules! dep_map_ty {
($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
@ -42,3 +42,4 @@ dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc<Vec<DefId>> }
dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec<ty::ImplOrTraitItemId> }
dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> }
dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId }

View file

@ -25,7 +25,7 @@ use std::{iter, u32};
use std::ops::{Index, IndexMut};
/// Lowered representation of a single function.
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Mir<'tcx> {
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
/// that indexes into this vector.
@ -146,7 +146,7 @@ pub enum BorrowKind {
// A "variable" is a binding declared by the user as part of the fn
// decl, a let, etc.
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct VarDecl<'tcx> {
pub mutability: Mutability,
pub name: Name,
@ -155,7 +155,7 @@ pub struct VarDecl<'tcx> {
// A "temp" is a temporary that we place on the stack. They are
// anonymous, always mutable, and have only a type.
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct TempDecl<'tcx> {
pub ty: Ty<'tcx>,
}
@ -171,7 +171,7 @@ pub struct TempDecl<'tcx> {
//
// there is only one argument, of type `(i32, u32)`, but two bindings
// (`x` and `y`).
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct ArgDecl<'tcx> {
pub ty: Ty<'tcx>,
}
@ -207,14 +207,14 @@ impl Debug for BasicBlock {
///////////////////////////////////////////////////////////////////////////
// BasicBlock and Terminator
#[derive(Debug, RustcEncodable, RustcDecodable)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> {
pub statements: Vec<Statement<'tcx>>,
pub terminator: Option<Terminator<'tcx>>,
pub is_cleanup: bool,
}
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum Terminator<'tcx> {
/// block should have one successor in the graph; we jump there
Goto {
@ -481,13 +481,13 @@ impl<'tcx> Terminator<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Statements
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Statement<'tcx> {
pub span: Span,
pub kind: StatementKind<'tcx>,
}
#[derive(Debug, RustcEncodable, RustcDecodable)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum StatementKind<'tcx> {
Assign(Lvalue<'tcx>, Rvalue<'tcx>),
Drop(DropKind, Lvalue<'tcx>),
@ -721,7 +721,7 @@ pub enum Rvalue<'tcx> {
InlineAsm(InlineAsm),
}
#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum CastKind {
Misc,

View file

@ -643,6 +643,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"keep the AST after lowering it to HIR"),
show_span: Option<String> = (None, parse_opt_string,
"show spans for compiler debugging (expr|pat|ty)"),
print_trans_items: Option<String> = (None, parse_opt_string,
"print the result of the translation item collection pass"),
}
pub fn default_lib_output() -> CrateType {

View file

@ -177,6 +177,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
}
_ => { }
}
Ok(ii)
}
}

View file

@ -445,6 +445,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::maybe_get_item_mir(&*cdata, tcx, def.index)
}
fn is_item_mir_available(&self, def: DefId) -> bool {
let cdata = self.get_crate_data(def.krate);
decoder::is_item_mir_available(&*cdata, def.index)
}
fn crates(&self) -> Vec<ast::CrateNum>
{
let mut result = vec![];

View file

@ -830,6 +830,14 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd,
}
}
pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool {
if let Some(item_doc) = cdata.get_item(id) {
return reader::maybe_get_doc(item_doc, tag_mir as usize).is_some();
}
false
}
pub fn maybe_get_item_mir<'tcx>(cdata: Cmd,
tcx: &ty::ctxt<'tcx>,
id: DefIndex)
@ -849,6 +857,8 @@ pub fn maybe_get_item_mir<'tcx>(cdata: Cmd,
})
}).unwrap();
assert!(decoder.position() == mir_doc.end);
let mut def_id_and_span_translator = MirDefIdAndSpanTranslator {
crate_metadata: cdata,
codemap: tcx.sess.codemap(),

View file

@ -41,8 +41,10 @@ use middle::infer;
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
use middle::weak_lang_items;
use middle::pat_util::simple_name;
use middle::subst::Substs;
use middle::subst::{self, Substs};
use middle::traits;
use middle::ty::{self, Ty, TypeFoldable};
use middle::ty::adjustment::CustomCoerceUnsized;
use rustc::dep_graph::DepNode;
use rustc::front::map as hir_map;
use rustc::util::common::time;
@ -59,10 +61,11 @@ use trans::callee;
use trans::cleanup::{self, CleanupMethods, DropHint};
use trans::closure;
use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral};
use trans::collector::{self, TransItem, TransItemState, TransItemCollectionMode};
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
use trans::common::{CrateContext, DropFlagHintsMap, Field, FunctionContext};
use trans::common::{Result, NodeIdAndSpan, VariantInfo};
use trans::common::{node_id_type, return_type_is_void};
use trans::common::{node_id_type, return_type_is_void, fulfill_obligation};
use trans::common::{type_is_immediate, type_is_zero_size, val_ty};
use trans::common;
use trans::consts;
@ -98,7 +101,7 @@ use std::collections::{HashMap, HashSet};
use std::str;
use std::{i8, i16, i32, i64};
use syntax::abi::{Rust, RustCall, RustIntrinsic, PlatformIntrinsic, Abi};
use syntax::codemap::Span;
use syntax::codemap::{Span, DUMMY_SP};
use syntax::parse::token::InternedString;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
@ -736,6 +739,29 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}
pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>)
-> CustomCoerceUnsized {
let trait_substs = Substs::erased(subst::VecPerParamSpace::new(vec![target_ty],
vec![source_ty],
Vec::new()));
let trait_ref = ty::Binder(ty::TraitRef {
def_id: ccx.tcx().lang_items.coerce_unsized_trait().unwrap(),
substs: ccx.tcx().mk_substs(trait_substs)
});
match fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
ccx.tcx().custom_coerce_unsized_kind(impl_def_id)
}
vtable => {
ccx.sess().bug(&format!("invalid CoerceUnsized vtable: {:?}",
vtable));
}
}
}
pub fn cast_shift_expr_rhs(cx: Block, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
cast_shift_rhs(op, lhs, rhs, |a, b| Trunc(cx, a, b), |a, b| ZExt(cx, a, b))
}
@ -1965,6 +1991,8 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
closure_env: closure::ClosureEnv<'b>) {
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
record_translation_item_as_generated(ccx, fn_ast_id, param_substs);
let _icx = push_ctxt("trans_closure");
attributes::emit_uwtable(llfndecl, true);
@ -2078,6 +2106,28 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Insert the mandatory first few basic blocks before lltop.
finish_fn(&fcx, bcx, output_type, ret_debug_loc);
fn record_translation_item_as_generated<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
node_id: ast::NodeId,
param_substs: &'tcx Substs<'tcx>) {
if !collector::collecting_debug_information(ccx) {
return;
}
let def_id = match ccx.tcx().node_id_to_type(node_id).sty {
ty::TyClosure(def_id, _) => def_id,
_ => ccx.external_srcs()
.borrow()
.get(&node_id)
.map(|did| *did)
.unwrap_or_else(|| ccx.tcx().map.local_def_id(node_id)),
};
ccx.record_translation_item_as_generated(TransItem::Fn{
def_id: def_id,
substs: ccx.tcx().mk_substs(ccx.tcx().erase_regions(param_substs)),
});
}
}
/// Creates an LLVM function corresponding to a source language function.
@ -3161,6 +3211,8 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
// First, verify intrinsics.
intrinsic::check_intrinsics(&ccx);
collect_translation_items(&ccx);
// Next, translate all items. See `TransModVisitor` for
// details on why we walk in this particular way.
{
@ -3168,6 +3220,8 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
intravisit::walk_mod(&mut TransItemsWithinModVisitor { ccx: &ccx }, &krate.module);
krate.visit_all_items(&mut TransModVisitor { ccx: &ccx });
}
collector::print_collection_results(&ccx);
}
for ccx in shared_ccx.iter() {
@ -3339,3 +3393,48 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TransItemsWithinModVisitor<'a, 'tcx> {
}
}
}
fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
let time_passes = ccx.sess().time_passes();
let collection_mode = match ccx.sess().opts.debugging_opts.print_trans_items {
Some(ref s) => {
let mode_string = s.to_lowercase();
let mode_string = mode_string.trim();
if mode_string == "eager" {
TransItemCollectionMode::Eager
} else {
if mode_string != "lazy" {
let message = format!("Unknown codegen-item collection mode '{}'. \
Falling back to 'lazy' mode.",
mode_string);
ccx.sess().warn(&message);
}
TransItemCollectionMode::Lazy
}
}
None => TransItemCollectionMode::Lazy
};
let items = time(time_passes, "translation item collection", || {
collector::collect_crate_translation_items(&ccx, collection_mode)
});
if ccx.sess().opts.debugging_opts.print_trans_items.is_some() {
let mut item_keys: Vec<_> = items.iter()
.map(|i| i.to_string(ccx))
.collect();
item_keys.sort();
for item in item_keys {
println!("TRANS_ITEM {}", item);
}
let mut ccx_map = ccx.translation_items().borrow_mut();
for cgi in items {
ccx_map.insert(cgi, TransItemState::PredictedButNotGenerated);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -30,6 +30,7 @@ use middle::def::Def;
use middle::def_id::DefId;
use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
use trans::collector::{self, TransItem};
use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
use trans::common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint};
@ -1016,6 +1017,11 @@ pub fn trans_static(ccx: &CrateContext,
id: ast::NodeId,
attrs: &[ast::Attribute])
-> Result<ValueRef, ConstEvalErr> {
if collector::collecting_debug_information(ccx) {
ccx.record_translation_item_as_generated(TransItem::Static(id));
}
unsafe {
let _icx = push_ctxt("trans_static");
let g = base::get_item_val(ccx, id);

View file

@ -10,6 +10,7 @@
use llvm;
use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef};
use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig};
use middle::cstore::LinkMeta;
use middle::def::ExportMap;
use middle::def_id::DefId;
@ -23,6 +24,7 @@ use trans::debuginfo;
use trans::declare;
use trans::glue::DropGlueKind;
use trans::monomorphize::MonoId;
use trans::collector::{TransItem, TransItemState};
use trans::type_::{Type, TypeNames};
use middle::subst::Substs;
use middle::ty::{self, Ty};
@ -33,6 +35,7 @@ use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
use std::ffi::CString;
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::ptr;
use std::rc::Rc;
use syntax::ast;
@ -75,6 +78,8 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
use_dll_storage_attrs: bool,
translation_items: RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>>,
}
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@ -161,8 +166,23 @@ pub struct LocalCrateContext<'tcx> {
/// Depth of the current type-of computation - used to bail out
type_of_depth: Cell<usize>,
trait_cache: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>,
traits::Vtable<'tcx, ()>>>,
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
}
// Implement DepTrackingMapConfig for `trait_cache`
pub struct TraitSelectionCache<'tcx> {
data: PhantomData<&'tcx ()>
}
impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
type Key = ty::PolyTraitRef<'tcx>;
type Value = traits::Vtable<'tcx, ()>;
fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode {
ty::tls::with(|tcx| {
let lifted_key = tcx.lift(key).unwrap();
lifted_key.to_poly_trait_predicate().dep_node()
})
}
}
pub struct CrateContext<'a, 'tcx: 'a> {
@ -228,7 +248,6 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> {
}
}
unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
let llcx = llvm::LLVMContextCreate();
let mod_name = CString::new(mod_name).unwrap();
@ -337,6 +356,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
check_drop_flag_for_sanity: check_drop_flag_for_sanity,
available_drop_glues: RefCell::new(FnvHashMap()),
use_dll_storage_attrs: use_dll_storage_attrs,
translation_items: RefCell::new(FnvHashMap()),
};
for i in 0..local_count {
@ -478,7 +498,9 @@ impl<'tcx> LocalCrateContext<'tcx> {
intrinsics: RefCell::new(FnvHashMap()),
n_llvm_insns: Cell::new(0),
type_of_depth: Cell::new(0),
trait_cache: RefCell::new(FnvHashMap()),
trait_cache: RefCell::new(DepTrackingMap::new(shared.tcx
.dep_graph
.clone())),
};
local_ccx.int_type = Type::int(&local_ccx.dummy_ccx(shared));
@ -752,8 +774,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1);
}
pub fn trait_cache(&self) -> &RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>,
traits::Vtable<'tcx, ()>>> {
pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
&self.local.trait_cache
}
@ -811,6 +832,24 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
pub fn mir_map(&self) -> &'b MirMap<'tcx> {
self.shared.mir_map
}
pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> {
&self.shared.translation_items
}
pub fn record_translation_item_as_generated(&self, cgi: TransItem<'tcx>) {
if self.sess().opts.debugging_opts.print_trans_items.is_none() {
return;
}
let mut codegen_items = self.translation_items().borrow_mut();
if codegen_items.contains_key(&cgi) {
codegen_items.insert(cgi, TransItemState::PredictedAndGenerated);
} else {
codegen_items.insert(cgi, TransItemState::NotPredictedButGenerated);
}
}
}
pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);

View file

@ -55,9 +55,7 @@ use back::abi;
use llvm::{self, ValueRef, TypeKind};
use middle::const_qualif::ConstQualif;
use middle::def::Def;
use middle::lang_items::CoerceUnsizedTraitLangItem;
use middle::subst::{Substs, VecPerParamSpace};
use middle::traits;
use middle::subst::Substs;
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
use trans::base::*;
use trans::build::*;
@ -500,24 +498,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let source = unpack_datum!(bcx, source.to_ref_datum(bcx));
assert!(target.kind.is_by_ref());
let trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty],
vec![source.ty],
Vec::new()));
let trait_ref = ty::Binder(ty::TraitRef {
def_id: langcall(bcx, Some(span), "coercion",
CoerceUnsizedTraitLangItem),
substs: bcx.tcx().mk_substs(trait_substs)
});
let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) {
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
bcx.tcx().custom_coerce_unsized_kind(impl_def_id)
}
vtable => {
bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {:?}",
vtable));
}
};
let kind = custom_coerce_unsize_info(bcx.ccx(), source.ty, target.ty);
let repr_source = adt::represent_type(bcx.ccx(), source.ty);
let src_fields = match &*repr_source {

View file

@ -28,6 +28,7 @@ use trans::build::*;
use trans::callee;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::collector::{self, TransItem};
use trans::common::*;
use trans::debuginfo::DebugLoc;
use trans::declare;
@ -88,7 +89,7 @@ pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}
fn type_needs_drop<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
pub fn type_needs_drop<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
tcx.type_needs_drop_given_env(ty, &tcx.empty_parameter_environment())
}
@ -496,6 +497,13 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>)
-> Block<'blk, 'tcx> {
let t = g.ty();
if collector::collecting_debug_information(bcx.ccx()) {
bcx.ccx()
.record_translation_item_as_generated(TransItem::DropGlue(bcx.tcx()
.erase_regions(&t)));
}
let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true };
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue");

View file

@ -495,7 +495,23 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
impl_def_id: id,
substs,
nested: _ }) => {
emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
let nullptr = C_null(Type::nil(ccx).ptr_to());
get_vtable_methods(ccx, id, substs)
.into_iter()
.map(|opt_mth| {
match opt_mth {
Some(mth) => {
trans_fn_ref_with_substs(ccx,
mth.method.def_id,
ExprId(0),
param_substs,
mth.substs).val
}
None => nullptr
}
})
.collect::<Vec<_>>()
.into_iter()
}
traits::VtableClosure(
traits::VtableClosureData {
@ -549,18 +565,14 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
vtable
}
fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
impl_id: DefId,
substs: subst::Substs<'tcx>,
param_substs: &'tcx subst::Substs<'tcx>)
-> Vec<ValueRef>
pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
impl_id: DefId,
substs: subst::Substs<'tcx>)
-> Vec<Option<ty::util::ImplMethod<'tcx>>>
{
let tcx = ccx.tcx();
debug!("emit_vtable_methods(impl_id={:?}, substs={:?}, param_substs={:?})",
impl_id,
substs,
param_substs);
debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs);
let trt_id = match tcx.impl_trait_ref(impl_id) {
Some(t_id) => t_id.def_id,
@ -570,7 +582,6 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
tcx.populate_implementations_for_trait_if_necessary(trt_id);
let nullptr = C_null(Type::nil(ccx).ptr_to());
let trait_item_def_ids = tcx.trait_item_def_ids(trt_id);
trait_item_def_ids
.iter()
@ -587,7 +598,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// method could never be called from this object, just supply
// null.
.map(|trait_method_def_id| {
debug!("emit_vtable_methods: trait_method_def_id={:?}",
debug!("get_vtable_methods: trait_method_def_id={:?}",
trait_method_def_id);
let trait_method_type = match tcx.impl_or_trait_item(trait_method_def_id) {
@ -598,18 +609,18 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Some methods cannot be called on an object; skip those.
if !traits::is_vtable_safe_method(tcx, trt_id, &trait_method_type) {
debug!("emit_vtable_methods: not vtable safe");
return nullptr;
debug!("get_vtable_methods: not vtable safe");
return None;
}
debug!("emit_vtable_methods: trait_method_type={:?}",
debug!("get_vtable_methods: trait_method_type={:?}",
trait_method_type);
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
let mth = tcx.get_impl_method(impl_id, substs.clone(), name);
debug!("emit_vtable_methods: mth={:?}", mth);
debug!("get_vtable_methods: mth={:?}", mth);
// If this is a default method, it's possible that it
// relies on where clauses that do not hold for this
@ -619,16 +630,12 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
if mth.is_provided {
let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
debug!("emit_vtable_methods: predicates do not hold");
return nullptr;
debug!("get_vtable_methods: predicates do not hold");
return None;
}
}
trans_fn_ref_with_substs(ccx,
mth.method.def_id,
ExprId(0),
param_substs,
mth.substs).val
Some(mth)
})
.collect()
}

View file

@ -58,6 +58,7 @@ mod _match;
mod meth;
mod mir;
mod monomorphize;
mod collector;
mod tvec;
mod type_;
mod type_of;

View file

@ -0,0 +1,34 @@
// Copyright 2012-2015 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.
#![crate_type = "lib"]
pub trait Trait : Sized {
fn without_self() -> u32;
fn without_self_default() -> u32 { 0 }
fn with_default_impl(self) -> Self { self }
fn with_default_impl_generic<T>(self, x: T) -> (Self, T) { (self, x) }
fn without_default_impl(x: u32) -> (Self, u32);
fn without_default_impl_generic<T>(x: T) -> (Self, T);
}
impl Trait for char {
fn without_self() -> u32 { 2 }
fn without_default_impl(x: u32) -> (Self, u32) { ('c', x) }
fn without_default_impl_generic<T>(x: T) -> (Self, T) { ('c', x) }
}
impl Trait for u32 {
fn without_self() -> u32 { 1 }
fn without_default_impl(x: u32) -> (Self, u32) { (0, x) }
fn without_default_impl_generic<T>(x: T) -> (Self, T) { (0, x) }
}

View file

@ -0,0 +1,33 @@
// Copyright 2012-2015 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.
#![crate_type = "lib"]
#[inline]
pub fn inlined_fn(x: i32, y: i32) -> i32 {
let closure = |a, b| { a + b };
closure(x, y)
}
pub fn inlined_fn_generic<T>(x: i32, y: i32, z: T) -> (i32, T) {
let closure = |a, b| { a + b };
(closure(x, y), z)
}
pub fn non_inlined_fn(x: i32, y: i32) -> i32 {
let closure = |a, b| { a + b };
closure(x, y)
}

View file

@ -0,0 +1,36 @@
// Copyright 2012-2015 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.
#![crate_type = "lib"]
struct Struct(u32);
pub fn foo<T>(x: T) -> (T, u32, i8) {
let (x, Struct(y)) = bar(x);
(x, y, 2)
}
fn bar<T>(x: T) -> (T, Struct) {
let _ = not_exported_and_not_generic(0);
(x, Struct(1))
}
// These should not contribute to the codegen items of other crates.
#[inline(never)]
pub fn exported_but_not_generic(x: i32) -> i64 {
x as i64
}
#[inline(never)]
fn not_exported_and_not_generic(x: u32) -> u64 {
x as u64
}

View file

@ -0,0 +1,35 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
// aux-build:cgu_extern_closures.rs
extern crate cgu_extern_closures;
//~ TRANS_ITEM fn cross_crate_closures::main[0]
fn main() {
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0]
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0]::{{closure}}[0]
let _ = cgu_extern_closures::inlined_fn(1, 2);
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0]<i32>
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0]::{{closure}}[0]<i32>
let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32);
// Nothing should be generated for this call, we just link to the instance instance
// in the extern crate.
let _ = cgu_extern_closures::non_inlined_fn(6, 7);
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,34 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
// aux-build:cgu_generic_function.rs
extern crate cgu_generic_function;
//~ TRANS_ITEM fn cross_crate_generic_functions::main[0]
fn main()
{
//~ TRANS_ITEM fn cgu_generic_function[0]::bar[0]<u32>
//~ TRANS_ITEM fn cgu_generic_function[0]::foo[0]<u32>
let _ = cgu_generic_function::foo(1u32);
//~ TRANS_ITEM fn cgu_generic_function[0]::bar[0]<u64>
//~ TRANS_ITEM fn cgu_generic_function[0]::foo[0]<u64>
let _ = cgu_generic_function::foo(2u64);
// This should not introduce a codegen item
let _ = cgu_generic_function::exported_but_not_generic(3);
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,60 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
// aux-build:cgu_export_trait_method.rs
extern crate cgu_export_trait_method;
use cgu_export_trait_method::Trait;
//~ TRANS_ITEM fn cross_crate_trait_method::main[0]
fn main()
{
// The object code of these methods is contained in the external crate, so
// calling them should *not* introduce codegen items in the current crate.
let _: (u32, u32) = Trait::without_default_impl(0);
let _: (char, u32) = Trait::without_default_impl(0);
// Currently, no object code is generated for trait methods with default
// implemenations, unless they are actually called from somewhere. Therefore
// we cannot import the implementations and have to create our own inline.
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0]<u32>
let _ = Trait::with_default_impl(0u32);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0]<char>
let _ = Trait::with_default_impl('c');
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<u32, &str>
let _ = Trait::with_default_impl_generic(0u32, "abc");
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<u32, bool>
let _ = Trait::with_default_impl_generic(0u32, false);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<char, i16>
let _ = Trait::with_default_impl_generic('x', 1i16);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<char, i32>
let _ = Trait::with_default_impl_generic('y', 0i32);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0]<char>
let _: (u32, char) = Trait::without_default_impl_generic('c');
//~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0]<bool>
let _: (u32, bool) = Trait::without_default_impl_generic(false);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0]<char>
let _: (char, char) = Trait::without_default_impl_generic('c');
//~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0]<bool>
let _: (char, bool) = Trait::without_default_impl_generic(false);
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,46 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
fn take_fn_once<T1, T2, F: FnOnce(T1, T2)>(f: F, x: T1, y: T2) {
(f)(x, y)
}
fn function<T1, T2>(_: T1, _: T2) {}
fn take_fn_pointer<T1, T2>(f: fn(T1, T2), x: T1, y: T2) {
(f)(x, y)
}
//~ TRANS_ITEM fn function_as_argument::main[0]
fn main() {
//~ TRANS_ITEM fn function_as_argument::take_fn_once[0]<u32, &str, fn(u32, &str)>
//~ TRANS_ITEM fn function_as_argument::function[0]<u32, &str>
take_fn_once(function, 0u32, "abc");
//~ TRANS_ITEM fn function_as_argument::take_fn_once[0]<char, f64, fn(char, f64)>
//~ TRANS_ITEM fn function_as_argument::function[0]<char, f64>
take_fn_once(function, 'c', 0f64);
//~ TRANS_ITEM fn function_as_argument::take_fn_pointer[0]<i32, ()>
//~ TRANS_ITEM fn function_as_argument::function[0]<i32, ()>
take_fn_pointer(function, 0i32, ());
//~ TRANS_ITEM fn function_as_argument::take_fn_pointer[0]<f32, i64>
//~ TRANS_ITEM fn function_as_argument::function[0]<f32, i64>
take_fn_pointer(function, 0f32, 0i64);
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,98 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
struct StructWithDrop<T1, T2> {
x: T1,
y: T2,
}
impl<T1, T2> Drop for StructWithDrop<T1, T2> {
fn drop(&mut self) {}
}
struct StructNoDrop<T1, T2> {
x: T1,
y: T2,
}
enum EnumWithDrop<T1, T2> {
A(T1),
B(T2)
}
impl<T1, T2> Drop for EnumWithDrop<T1, T2> {
fn drop(&mut self) {}
}
enum EnumNoDrop<T1, T2> {
A(T1),
B(T2)
}
struct NonGenericNoDrop(i32);
struct NonGenericWithDrop(i32);
//~ TRANS_ITEM drop-glue generic_drop_glue::NonGenericWithDrop[0]
impl Drop for NonGenericWithDrop {
fn drop(&mut self) {}
//~ TRANS_ITEM fn generic_drop_glue::NonGenericWithDrop.Drop[0]::drop[0]
}
//~ TRANS_ITEM fn generic_drop_glue::main[0]
fn main() {
//~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<i8, char>
//~ TRANS_ITEM fn generic_drop_glue::StructWithDrop<T1, T2>.Drop[0]::drop[0]<i8, char>
let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
//~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
//~ TRANS_ITEM fn generic_drop_glue::StructWithDrop<T1, T2>.Drop[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y;
// Should produce no drop glue
let _ = StructNoDrop { x: 'a', y: 0u32 }.x;
// This is supposed to generate drop-glue because it contains a field that
// needs to be dropped.
//~ TRANS_ITEM drop-glue generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>
let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y;
//~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0]<i32, i64>
//~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop<T1, T2>.Drop[0]::drop[0]<i32, i64>
let _ = match EnumWithDrop::A::<i32, i64>(0) {
EnumWithDrop::A(x) => x,
EnumWithDrop::B(x) => x as i32
};
//~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0]<f64, f32>
//~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop<T1, T2>.Drop[0]::drop[0]<f64, f32>
let _ = match EnumWithDrop::B::<f64, f32>(1.0) {
EnumWithDrop::A(x) => x,
EnumWithDrop::B(x) => x as f64
};
let _ = match EnumNoDrop::A::<i32, i64>(0) {
EnumNoDrop::A(x) => x,
EnumNoDrop::B(x) => x as i32
};
let _ = match EnumNoDrop::B::<f64, f32>(1.0) {
EnumNoDrop::A(x) => x,
EnumNoDrop::B(x) => x as f64
};
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,64 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
fn foo1<T1>(a: T1) -> (T1, u32) {
(a, 1)
}
fn foo2<T1, T2>(a: T1, b: T2) -> (T1, T2) {
(a, b)
}
fn foo3<T1, T2, T3>(a: T1, b: T2, c: T3) -> (T1, T2, T3) {
(a, b, c)
}
// This function should be instantiated even if no used
//~ TRANS_ITEM fn generic_functions::lifetime_only[0]
pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 {
a
}
//~ TRANS_ITEM fn generic_functions::main[0]
fn main() {
//~ TRANS_ITEM fn generic_functions::foo1[0]<i32>
let _ = foo1(2i32);
//~ TRANS_ITEM fn generic_functions::foo1[0]<i64>
let _ = foo1(2i64);
//~ TRANS_ITEM fn generic_functions::foo1[0]<&str>
let _ = foo1("abc");
//~ TRANS_ITEM fn generic_functions::foo1[0]<char>
let _ = foo1('v');
//~ TRANS_ITEM fn generic_functions::foo2[0]<i32, i32>
let _ = foo2(2i32, 2i32);
//~ TRANS_ITEM fn generic_functions::foo2[0]<i64, &str>
let _ = foo2(2i64, "abc");
//~ TRANS_ITEM fn generic_functions::foo2[0]<&str, usize>
let _ = foo2("a", 2usize);
//~ TRANS_ITEM fn generic_functions::foo2[0]<char, ()>
let _ = foo2('v', ());
//~ TRANS_ITEM fn generic_functions::foo3[0]<i32, i32, i32>
let _ = foo3(2i32, 2i32, 2i32);
//~ TRANS_ITEM fn generic_functions::foo3[0]<i64, &str, char>
let _ = foo3(2i64, "abc", 'c');
//~ TRANS_ITEM fn generic_functions::foo3[0]<i16, &str, usize>
let _ = foo3(0i16, "a", 2usize);
//~ TRANS_ITEM fn generic_functions::foo3[0]<char, (), ()>
let _ = foo3('v', (), ());
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,81 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
struct Struct<T> {
x: T,
f: fn(x: T) -> T,
}
fn id<T>(x: T) -> T { x }
impl<T> Struct<T> {
fn new(x: T) -> Struct<T> {
Struct {
x: x,
f: id
}
}
fn get<T2>(self, x: T2) -> (T, T2) {
(self.x, x)
}
}
pub struct LifeTimeOnly<'a> {
_a: &'a u32
}
impl<'a> LifeTimeOnly<'a> {
//~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::foo[0]
pub fn foo(&self) {}
//~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::bar[0]
pub fn bar(&'a self) {}
//~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::baz[0]
pub fn baz<'b>(&'b self) {}
pub fn non_instantiated<T>(&self) {}
}
//~ TRANS_ITEM fn generic_impl::main[0]
fn main() {
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<i32>
//~ TRANS_ITEM fn generic_impl::id[0]<i32>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<i32, i16>
let _ = Struct::new(0i32).get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<i64>
//~ TRANS_ITEM fn generic_impl::id[0]<i64>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<i64, i16>
let _ = Struct::new(0i64).get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<char>
//~ TRANS_ITEM fn generic_impl::id[0]<char>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<char, i16>
let _ = Struct::new('c').get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<&str>
//~ TRANS_ITEM fn generic_impl::id[0]<&str>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<generic_impl::Struct[0]<&str>, i16>
let _ = Struct::new(Struct::new("str")).get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<generic_impl::Struct[0]<&str>>
//~ TRANS_ITEM fn generic_impl::id[0]<generic_impl::Struct[0]<&str>>
let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str"));
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,36 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
trait SomeTrait {
fn foo(&self);
}
// This function is never instantiated but the contained impl must still be
// discovered.
pub fn generic_function<T>(x: T) -> (T, i32) {
impl SomeTrait for i64 {
//~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::i64.SomeTrait[0]::foo[0]
fn foo(&self) {}
}
(x, 0)
}
//~ TRANS_ITEM fn impl_in_non_instantiated_generic::main[0]
fn main() {
0i64.foo();
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,42 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
trait Trait {
fn foo(&self) -> u32;
fn bar(&self);
}
struct Struct<T> {
_a: T
}
impl<T> Trait for Struct<T> {
fn foo(&self) -> u32 { 0 }
fn bar(&self) {}
}
//~ TRANS_ITEM fn instantiation_through_vtable::main[0]
fn main() {
let s1 = Struct { _a: 0u32 };
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::foo[0]<u32>
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::bar[0]<u32>
let _ = &s1 as &Trait;
let s1 = Struct { _a: 0u64 };
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::foo[0]<u64>
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::bar[0]<u64>
let _ = &s1 as &Trait;
}

View file

@ -0,0 +1,44 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
fn generic_fn<T>(a: T) -> (T, i32) {
//~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[0]
fn nested_fn(a: i32) -> i32 {
a + 1
}
let x = {
//~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[1]
fn nested_fn(a: i32) -> i32 {
a + 2
}
1 + nested_fn(1)
};
return (a, x + nested_fn(0));
}
//~ TRANS_ITEM fn items_within_generic_items::main[0]
fn main() {
//~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]<i64>
let _ = generic_fn(0i64);
//~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]<u16>
let _ = generic_fn(0u16);
//~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]<i8>
let _ = generic_fn(0i8);
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,63 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
//~ TRANS_ITEM fn non_generic_closures::temporary[0]
fn temporary() {
//~ TRANS_ITEM fn non_generic_closures::temporary[0]::{{closure}}[0]
(|a: u32| {
let _ = a;
})(4);
}
//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0]
fn assigned_to_variable_but_not_executed() {
//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0]::{{closure}}[0]
let _x = |a: i16| {
let _ = a + 1;
};
}
//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0]
fn assigned_to_variable_executed_indirectly() {
//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0]::{{closure}}[0]
let f = |a: i32| {
let _ = a + 2;
};
run_closure(&f);
}
//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0]
fn assigned_to_variable_executed_directly() {
//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0]::{{closure}}[0]
let f = |a: i64| {
let _ = a + 3;
};
f(4);
}
//~ TRANS_ITEM fn non_generic_closures::main[0]
fn main() {
temporary();
assigned_to_variable_but_not_executed();
assigned_to_variable_executed_directly();
assigned_to_variable_executed_indirectly();
}
//~ TRANS_ITEM fn non_generic_closures::run_closure[0]
fn run_closure(f: &Fn(i32)) {
f(3);
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,56 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
//~ TRANS_ITEM drop-glue non_generic_drop_glue::StructWithDrop[0]
struct StructWithDrop {
x: i32
}
impl Drop for StructWithDrop {
//~ TRANS_ITEM fn non_generic_drop_glue::StructWithDrop.Drop[0]::drop[0]
fn drop(&mut self) {}
}
struct StructNoDrop {
x: i32
}
//~ TRANS_ITEM drop-glue non_generic_drop_glue::EnumWithDrop[0]
enum EnumWithDrop {
A(i32)
}
impl Drop for EnumWithDrop {
//~ TRANS_ITEM fn non_generic_drop_glue::EnumWithDrop.Drop[0]::drop[0]
fn drop(&mut self) {}
}
enum EnumNoDrop {
A(i32)
}
//~ TRANS_ITEM fn non_generic_drop_glue::main[0]
fn main() {
let _ = StructWithDrop { x: 0 }.x;
let _ = StructNoDrop { x: 0 }.x;
let _ = match EnumWithDrop::A(0) {
EnumWithDrop::A(x) => x
};
let _ = match EnumNoDrop::A(0) {
EnumNoDrop::A(x) => x
};
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,81 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
//~ TRANS_ITEM fn non_generic_functions::foo[0]
fn foo() {
{
//~ TRANS_ITEM fn non_generic_functions::foo[0]::foo[0]
fn foo() {}
foo();
}
{
//~ TRANS_ITEM fn non_generic_functions::foo[0]::foo[1]
fn foo() {}
foo();
}
}
//~ TRANS_ITEM fn non_generic_functions::bar[0]
fn bar() {
//~ TRANS_ITEM fn non_generic_functions::bar[0]::baz[0]
fn baz() {}
baz();
}
struct Struct { _x: i32 }
impl Struct {
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]
fn foo() {
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[0]
fn foo() {}
foo();
}
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[1]
fn foo() {}
foo();
}
}
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]
fn bar(&self) {
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[0]
fn foo() {}
foo();
}
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[1]
fn foo() {}
foo();
}
}
}
//~ TRANS_ITEM fn non_generic_functions::main[0]
fn main() {
foo();
bar();
Struct::foo();
let x = Struct { _x: 0 };
x.bar();
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,72 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
#![crate_type="lib"]
use std::ops::{Index, IndexMut, Add, Deref};
pub struct Indexable {
data: [u8; 3]
}
impl Index<usize> for Indexable {
type Output = u8;
//~ TRANS_ITEM fn overloaded_operators::Indexable.Index<usize>[0]::index[0]
fn index(&self, index: usize) -> &Self::Output {
if index >= 3 {
&self.data[0]
} else {
&self.data[index]
}
}
}
impl IndexMut<usize> for Indexable {
//~ TRANS_ITEM fn overloaded_operators::Indexable.IndexMut<usize>[0]::index_mut[0]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index >= 3 {
&mut self.data[0]
} else {
&mut self.data[index]
}
}
}
//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::eq[0]
//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::ne[0]
#[derive(PartialEq)]
pub struct Equatable(u32);
impl Add<u32> for Equatable {
type Output = u32;
//~ TRANS_ITEM fn overloaded_operators::Equatable.Add<u32>[0]::add[0]
fn add(self, rhs: u32) -> u32 {
self.0 + rhs
}
}
impl Deref for Equatable {
type Target = u32;
//~ TRANS_ITEM fn overloaded_operators::Equatable.Deref[0]::deref[0]
fn deref(&self) -> &Self::Target {
&self.0
}
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,64 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
static STATIC1: i64 = {
const STATIC1_CONST1: i64 = 2;
1 + CONST1 as i64 + STATIC1_CONST1
};
const CONST1: i64 = {
const CONST1_1: i64 = {
const CONST1_1_1: i64 = 2;
CONST1_1_1 + 1
};
1 + CONST1_1 as i64
};
fn foo() {
let _ = {
const CONST2: i64 = 0;
static STATIC2: i64 = CONST2;
let x = {
const CONST2: i64 = 1;
static STATIC2: i64 = CONST2;
STATIC2
};
x + STATIC2
};
let _ = {
const CONST2: i64 = 0;
static STATIC2: i64 = CONST2;
STATIC2
};
}
fn main() {
foo();
let _ = STATIC1;
}
//~ TRANS_ITEM static statics_and_consts::STATIC1[0]
//~ TRANS_ITEM fn statics_and_consts::foo[0]
//~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[0]
//~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[1]
//~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[2]
//~ TRANS_ITEM fn statics_and_consts::main[0]
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,82 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
pub trait SomeTrait {
fn foo(&self);
fn bar<T>(&self, x: T);
}
impl SomeTrait for i64 {
//~ TRANS_ITEM fn trait_implementations::i64.SomeTrait[0]::foo[0]
fn foo(&self) {}
fn bar<T>(&self, _: T) {}
}
impl SomeTrait for i32 {
//~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::foo[0]
fn foo(&self) {}
fn bar<T>(&self, _: T) {}
}
pub trait SomeGenericTrait<T> {
fn foo(&self, x: T);
fn bar<T2>(&self, x: T, y: T2);
}
// Concrete impl of generic trait
impl SomeGenericTrait<u32> for f64 {
//~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait<u32>[0]::foo[0]
fn foo(&self, _: u32) {}
fn bar<T2>(&self, _: u32, _: T2) {}
}
// Generic impl of generic trait
impl<T> SomeGenericTrait<T> for f32 {
fn foo(&self, _: T) {}
fn bar<T2>(&self, _: T, _: T2) {}
}
//~ TRANS_ITEM fn trait_implementations::main[0]
fn main() {
//~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::bar[0]<char>
0i32.bar('x');
//~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait<u32>[0]::bar[0]<&str>
0f64.bar(0u32, "&str");
//~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait<u32>[0]::bar[0]<()>
0f64.bar(0u32, ());
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::foo[0]<char>
0f32.foo('x');
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::foo[0]<i64>
0f32.foo(-1i64);
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::bar[0]<u32, ()>
0f32.bar(0u32, ());
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::bar[0]<&str, &str>
0f32.bar("&str", "&str");
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,62 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
trait Trait : Sized {
fn foo(self) -> Self { self }
}
impl Trait for u32 {
fn foo(self) -> u32 { self }
}
impl Trait for char {
}
fn take_foo_once<T, F: FnOnce(T) -> T>(f: F, arg: T) -> T {
(f)(arg)
}
fn take_foo<T, F: Fn(T) -> T>(f: F, arg: T) -> T {
(f)(arg)
}
fn take_foo_mut<T, F: FnMut(T) -> T>(mut f: F, arg: T) -> T {
(f)(arg)
}
//~ TRANS_ITEM fn trait_method_as_argument::main[0]
fn main() {
//~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0]<u32, fn(u32) -> u32>
//~ TRANS_ITEM fn trait_method_as_argument::u32.Trait[0]::foo[0]
take_foo_once(Trait::foo, 0u32);
//~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0]<char, fn(char) -> char>
//~ TRANS_ITEM fn trait_method_as_argument::Trait[0]::foo[0]<char>
take_foo_once(Trait::foo, 'c');
//~ TRANS_ITEM fn trait_method_as_argument::take_foo[0]<u32, fn(u32) -> u32>
take_foo(Trait::foo, 0u32);
//~ TRANS_ITEM fn trait_method_as_argument::take_foo[0]<char, fn(char) -> char>
take_foo(Trait::foo, 'c');
//~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0]<u32, fn(u32) -> u32>
take_foo_mut(Trait::foo, 0u32);
//~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0]<char, fn(char) -> char>
take_foo_mut(Trait::foo, 'c');
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,70 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
trait SomeTrait {
fn foo(&self) { }
fn bar<T>(&self, x: T) -> T { x }
}
impl SomeTrait for i8 {
// take the default implementations
// For the non-generic foo(), we should generate a codegen-item even if it
// is not called anywhere
//~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::foo[0]<i8>
}
trait SomeGenericTrait<T1> {
fn foo(&self) { }
fn bar<T2>(&self, x: T1, y: T2) {}
}
// Non-generic impl of generic trait
impl SomeGenericTrait<u64> for i32 {
// take the default implementations
// For the non-generic foo(), we should generate a codegen-item even if it
// is not called anywhere
//~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0]<u64, i32>
}
// Non-generic impl of generic trait
impl<T1> SomeGenericTrait<T1> for u32 {
// take the default implementations
// since nothing is monomorphic here, nothing should be generated unless used somewhere.
}
//~ TRANS_ITEM fn trait_method_default_impl::main[0]
fn main() {
//~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0]<i8, char>
let _ = 1i8.bar('c');
//~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0]<i8, &str>
let _ = 2i8.bar("&str");
//~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0]<u64, i32, char>
0i32.bar(0u64, 'c');
//~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0]<u64, i32, &str>
0i32.bar(0u64, "&str");
//~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0]<i8, u32, &[char; 1]>
0u32.bar(0i8, &['c']);
//~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0]<i16, u32, ()>
0u32.bar(0i16, ());
}
//~ TRANS_ITEM drop-glue i8

View file

@ -0,0 +1,55 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0]
struct Root(Intermediate);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Intermediate[0]
struct Intermediate(Leaf);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Leaf[0]
struct Leaf;
impl Drop for Leaf {
//~ TRANS_ITEM fn transitive_drop_glue::Leaf.Drop[0]::drop[0]
fn drop(&mut self) {}
}
//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0]
struct RootGen<T>(IntermediateGen<T>);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0]
struct IntermediateGen<T>(LeafGen<T>);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0]
struct LeafGen<T>(T);
impl<T> Drop for LeafGen<T> {
fn drop(&mut self) {}
}
//~ TRANS_ITEM fn transitive_drop_glue::main[0]
fn main() {
let _ = Root(Intermediate(Leaf));
//~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0]<u32>
//~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0]<u32>
//~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0]<u32>
//~ TRANS_ITEM fn transitive_drop_glue::LeafGen<T>.Drop[0]::drop[0]<u32>
let _ = RootGen(IntermediateGen(LeafGen(0u32)));
//~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0]<i16>
//~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0]<i16>
//~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0]<i16>
//~ TRANS_ITEM fn transitive_drop_glue::LeafGen<T>.Drop[0]::drop[0]<i16>
let _ = RootGen(IntermediateGen(LeafGen(0i16)));
}

View file

@ -0,0 +1,32 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
//~ TRANS_ITEM drop-glue tuple_drop_glue::Dropped[0]
struct Dropped;
impl Drop for Dropped {
//~ TRANS_ITEM fn tuple_drop_glue::Dropped.Drop[0]::drop[0]
fn drop(&mut self) {}
}
//~ TRANS_ITEM fn tuple_drop_glue::main[0]
fn main() {
//~ TRANS_ITEM drop-glue (u32, tuple_drop_glue::Dropped[0])
let x = (0u32, Dropped);
//~ TRANS_ITEM drop-glue (i16, (tuple_drop_glue::Dropped[0], bool))
//~ TRANS_ITEM drop-glue (tuple_drop_glue::Dropped[0], bool)
let x = (0i16, (Dropped, true));
}

View file

@ -0,0 +1,80 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![deny(dead_code)]
#![feature(coerce_unsized)]
#![feature(unsize)]
use std::marker::Unsize;
use std::ops::CoerceUnsized;
trait Trait {
fn foo(&self);
}
// Simple Case
impl Trait for bool {
fn foo(&self) {}
}
impl Trait for char {
fn foo(&self) {}
}
// Struct Field Case
struct Struct<T: ?Sized> {
_a: u32,
_b: i32,
_c: T
}
impl Trait for f64 {
fn foo(&self) {}
}
// Custom Coercion Case
impl Trait for u32 {
fn foo(&self) {}
}
#[derive(Clone, Copy)]
struct Wrapper<T: ?Sized>(*const T);
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
//~ TRANS_ITEM fn unsizing::main[0]
fn main()
{
// simple case
let bool_sized = &true;
//~ TRANS_ITEM fn unsizing::bool.Trait[0]::foo[0]
let _bool_unsized = bool_sized as &Trait;
let char_sized = &true;
//~ TRANS_ITEM fn unsizing::char.Trait[0]::foo[0]
let _char_unsized = char_sized as &Trait;
// struct field
let struct_sized = &Struct {
_a: 1,
_b: 2,
_c: 3.0f64
};
//~ TRANS_ITEM fn unsizing::f64.Trait[0]::foo[0]
let _struct_unsized = struct_sized as &Struct<Trait>;
// custom coercion
let wrapper_sized = Wrapper(&0u32);
//~ TRANS_ITEM fn unsizing::u32.Trait[0]::foo[0]
let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
}

View file

@ -0,0 +1,89 @@
// Copyright 2012-2015 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
// compile-flags:-Zprint-trans-items=eager
#![crate_type="lib"]
#![deny(dead_code)]
// This test asserts that no codegen items are generated for generic items that
// are never instantiated in the local crate.
pub trait Trait {
fn foo() {}
fn bar(&self) {}
}
pub fn foo<T: Copy>(x: T) -> (T, T) {
(x, x)
}
pub struct Struct<T> {
x: T
}
impl<T> Struct<T> {
pub fn foo(self) -> T {
self.x
}
pub fn bar() {}
}
pub enum Enum<T> {
A(T),
B { x: T }
}
impl<T> Enum<T> {
pub fn foo(self) -> T {
match self {
Enum::A(x) => x,
Enum::B { x } => x,
}
}
pub fn bar() {}
}
pub struct TupleStruct<T>(T);
impl<T> TupleStruct<T> {
pub fn foo(self) -> T {
self.0
}
pub fn bar() {}
}
pub type Pair<T> = (T, T);
pub struct NonGeneric {
x: i32
}
impl NonGeneric {
pub fn foo(self) -> i32 {
self.x
}
pub fn generic_foo<T>(&self, x: T) -> (T, i32) {
(x, self.x)
}
pub fn generic_bar<T: Copy>(x: T) -> (T, T) {
(x, x)
}
}
// Only the non-generic methods should be instantiated:
//~ TRANS_ITEM fn unused_traits_and_generics::NonGeneric[0]::foo[0]
//~ TRANS_ITEM drop-glue i8