From f030b5dbc29b20b964f2cc448d893998080b1a46 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 May 2016 06:11:20 -0400 Subject: [PATCH 01/23] degrade gracefully with empty spans --- src/libsyntax/errors/snippet/mod.rs | 12 ++++++++- src/libsyntax/errors/snippet/test.rs | 38 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index e213f623ab85d..237e6823e0f87 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -376,11 +376,21 @@ impl FileInfo { // Basically, although this loses information, multi-line spans just // never look good. - let (line, start_col, end_col) = if lines.len() == 1 { + let (line, start_col, mut end_col) = if lines.len() == 1 { (lines[0].line_index, lines[0].start_col, lines[0].end_col) } else { (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1)) }; + + // Watch out for "empty spans". If we get a span like 6..6, we + // want to just display a `^` at 6, so convert that to + // 6..7. This is degenerate input, but it's best to degrade + // gracefully -- and the parser likes to suply a span like + // that for EOF, in particular. + if start_col == end_col { + end_col.0 += 1; + } + let index = self.ensure_source_line(line); self.lines[index].push_annotation(start_col, end_col, diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 569d11199190c..5a888b488191b 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -519,3 +519,41 @@ fn span_overlap_label3() { |> ----- bar "#[1..]); } + +#[test] +fn span_empty() { + // In one of the unit tests, we found that the parser sometimes + // gives empty spans, and in particular it supplied an EOF span + // like this one, which points at the very end. We want to + // fallback gracefully in this case. + + let file_text = r#" +fn main() { + struct Foo; + + impl !Sync for Foo {} + + unsafe impl Send for &'static Foo { + // error: cross-crate traits with a default impl, like `core::marker::Send`, + // can only be implemented for a struct/enum type, not + // `&'static Foo` +}"#; + + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1); + rbrace_span.lo = rbrace_span.hi; + + let mut snippet = SnippetData::new(cm.clone(), Some(rbrace_span)); + snippet.push(rbrace_span, false, None); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" + --> foo.rs:11:2 +11 |> } + |> - +"#[1..]); +} From 421e6fc24d2e5bfc59746d2662531fb22f7e0720 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 3 May 2016 14:02:32 +0200 Subject: [PATCH 02/23] rustdoc: use btree map for where clauses to get more reproducible output. Fixes: #32555 --- src/librustdoc/clean/simplify.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 4ba412cdc851b..c0faa04323e47 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -27,7 +27,7 @@ //! bounds by special casing scenarios such as these. Fun! use std::mem; -use std::collections::HashMap; +use std::collections::BTreeMap; use rustc::hir::def_id::DefId; use rustc::ty::subst; @@ -39,7 +39,7 @@ use core::DocContext; pub fn where_clauses(cx: &DocContext, clauses: Vec) -> Vec { // First, partition the where clause into its separate components - let mut params = HashMap::new(); + let mut params = BTreeMap::new(); let mut lifetimes = Vec::new(); let mut equalities = Vec::new(); let mut tybounds = Vec::new(); @@ -62,7 +62,7 @@ pub fn where_clauses(cx: &DocContext, clauses: Vec) -> Vec { // Simplify the type parameter bounds on all the generics let mut params = params.into_iter().map(|(k, v)| { (k, ty_bounds(v)) - }).collect::>(); + }).collect::>(); // Look for equality predicates on associated types that can be merged into // general bound predicates From b3de04214646a33fa5a14fbb2e8ba55e7ee5a707 Mon Sep 17 00:00:00 2001 From: Garrett Squire Date: Wed, 4 May 2016 10:25:17 -0700 Subject: [PATCH 03/23] add a check to make tidy to ensure cargo lock file is updated --- src/rustc/Cargo.lock | 33 +++++------------------- src/tools/tidy/src/cargo_lock.rs | 43 ++++++++++++++++++++++++++++++++ src/tools/tidy/src/main.rs | 2 ++ 3 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 src/tools/tidy/src/cargo_lock.rs diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 1fa4d5398f489..b4c2e21651edb 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -7,15 +7,6 @@ dependencies = [ "rustdoc 0.0.0", ] -[[package]] -name = "advapi32-sys" -version = "0.1.2" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.2 (registry+/~https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+/~https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "arena" version = "0.0.0" @@ -29,7 +20,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.17 (registry+/~https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.28 (registry+/~https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -38,12 +29,8 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.17" +version = "0.3.28" source = "registry+/~https://github.com/rust-lang/crates.io-index" -dependencies = [ - "advapi32-sys 0.1.2 (registry+/~https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.2 (registry+/~https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "graphviz" @@ -192,7 +179,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.17 (registry+/~https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.28 (registry+/~https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -233,6 +220,7 @@ dependencies = [ "log 0.0.0", "rustc 0.0.0", "rustc_const_eval 0.0.0", + "rustc_const_math 0.0.0", "syntax 0.0.0", ] @@ -278,6 +266,7 @@ version = "0.0.0" dependencies = [ "log 0.0.0", "rustc 0.0.0", + "serialize 0.0.0", "syntax 0.0.0", ] @@ -323,7 +312,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "gcc 0.3.17 (registry+/~https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.28 (registry+/~https://github.com/rust-lang/crates.io-index)", "log 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -362,13 +351,3 @@ dependencies = [ "syntax 0.0.0", ] -[[package]] -name = "winapi" -version = "0.2.2" -source = "registry+/~https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" - diff --git a/src/tools/tidy/src/cargo_lock.rs b/src/tools/tidy/src/cargo_lock.rs new file mode 100644 index 0000000000000..4324db489b7f8 --- /dev/null +++ b/src/tools/tidy/src/cargo_lock.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::path::Path; + +const CARGO_LOCK: &'static str = "Cargo.lock"; + +pub fn check(path: &Path, bad: &mut bool) { + use std::process::Command; + + super::walk(path, + &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), + &mut |file| { + let name = file.file_name().unwrap().to_string_lossy(); + if name == CARGO_LOCK { + let rel_path = file.strip_prefix(path).unwrap(); + let ret_code = Command::new("git") + .arg("diff-index") + .arg("--quiet") + .arg("HEAD") + .arg(rel_path) + .current_dir(path) + .status() + .unwrap_or_else(|e| { + panic!("could not run git diff-index: {}", e); + }); + if !ret_code.success() { + let parent_path = file.parent().unwrap().join("Cargo.toml"); + print!("dirty lock file found at {} ", rel_path.display()); + println!("please commit your changes or update the lock file by running:"); + println!("\n\tcargo update --manifest-path {}", parent_path.display()); + *bad = true; + } + } + }); +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index e9e2508aba9bd..2839bbded1a5f 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,6 +35,7 @@ mod style; mod errors; mod features; mod cargo; +mod cargo_lock; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -46,6 +47,7 @@ fn main() { errors::check(&path, &mut bad); cargo::check(&path, &mut bad); features::check(&path, &mut bad); + cargo_lock::check(&path, &mut bad); if bad { panic!("some tidy checks failed"); From 5f9e30431021f1c8eae7f4cfa6db9b1d39a8e216 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 4 May 2016 22:55:35 +0530 Subject: [PATCH 04/23] Improve diagnostics for constants being used in irrefutable patterns It's pretty confusing and this error triggers in resolve only when "shadowing" a const, so let's make that clearer. --- src/librustc_resolve/lib.rs | 8 ++++---- src/test/compile-fail/const-pattern-irrefutable.rs | 6 +++--- src/test/compile-fail/issue-27033.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e747ed1526061..a617f425ecdaa 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -141,7 +141,7 @@ enum ResolutionError<'a> { /// error E0413: declaration shadows an enum variant or unit-like struct in scope DeclarationShadowsEnumVariantOrUnitLikeStruct(Name), /// error E0414: only irrefutable patterns allowed here - OnlyIrrefutablePatternsAllowedHere(Name), + ConstantForIrrefutableBinding(Name), /// error E0415: identifier is bound more than once in this parameter list IdentifierBoundMoreThanOnceInParameterList(&'a str), /// error E0416: identifier is bound more than once in the same pattern @@ -323,11 +323,11 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, or unit-like struct in scope", name) } - ResolutionError::OnlyIrrefutablePatternsAllowedHere(name) => { + ResolutionError::ConstantForIrrefutableBinding(name) => { let mut err = struct_span_err!(resolver.session, span, E0414, - "only irrefutable patterns allowed here"); + "variable bindings cannot shadow constants"); err.span_note(span, "there already is a constant in scope sharing the same \ name as this pattern"); @@ -2233,7 +2233,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolve_error( self, pattern.span, - ResolutionError::OnlyIrrefutablePatternsAllowedHere(name) + ResolutionError::ConstantForIrrefutableBinding(name) ); self.record_def(pattern.id, err_path_resolution()); } diff --git a/src/test/compile-fail/const-pattern-irrefutable.rs b/src/test/compile-fail/const-pattern-irrefutable.rs index 825c39011fcc1..0be1e974e7d7d 100644 --- a/src/test/compile-fail/const-pattern-irrefutable.rs +++ b/src/test/compile-fail/const-pattern-irrefutable.rs @@ -19,10 +19,10 @@ use foo::d; //~ NOTE constant imported here const a: u8 = 2; //~ NOTE constant defined here fn main() { - let a = 4; //~ ERROR only irrefutable + let a = 4; //~ ERROR variable bindings cannot //~^ NOTE there already is a constant in scope - let c = 4; //~ ERROR only irrefutable + let c = 4; //~ ERROR variable bindings cannot //~^ NOTE there already is a constant in scope - let d = 4; //~ ERROR only irrefutable + let d = 4; //~ ERROR variable bindings cannot //~^ NOTE there already is a constant in scope } diff --git a/src/test/compile-fail/issue-27033.rs b/src/test/compile-fail/issue-27033.rs index 051edfe5f451b..a729cf95a7bf3 100644 --- a/src/test/compile-fail/issue-27033.rs +++ b/src/test/compile-fail/issue-27033.rs @@ -14,7 +14,7 @@ fn main() { }; const C: u8 = 1; match 1 { - C @ 2 => { //~ ERROR only irrefutable patterns allowed here + C @ 2 => { //~ ERROR variable bindings cannot shadow constants println!("{}", C); } _ => {} From c5aa8794908425a36e71e9628a23c5d15f66c65e Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 4 May 2016 22:09:51 -0400 Subject: [PATCH 05/23] implement RFC 1521 Adds documentation to Clone, specifying that Copy types should have a trivial Clone impl. Fixes #33416. --- src/libcore/clone.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index ad2a205a82376..e8ea993c6940a 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -49,6 +49,11 @@ use marker::Sized; /// A common trait for cloning an object. /// /// This trait can be used with `#[derive]`. +/// +/// Types that are `Copy` should have a trivial implementation of `Clone`. More formally: +/// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`. +/// Manual implementations should be careful to uphold this invariant; however, unsafe code +/// must not rely on it to ensure memory safety. #[stable(feature = "rust1", since = "1.0.0")] pub trait Clone : Sized { /// Returns a copy of the value. From 9f302b6bcdc7b3d35a074ff565e17350f12038b7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 4 May 2016 23:28:50 +0530 Subject: [PATCH 06/23] Add long diagnostics for E0414 --- src/librustc_resolve/diagnostics.rs | 64 ++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 56d3b927dc592..fda7c7aeb3306 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -623,6 +623,69 @@ let Foo = 12i32; // ok! The goal here is to avoid a conflict of names. "##, +E0414: r##" +A variable binding in an irrefutable pattern is shadowing the name of a +constant. Example of erroneous code: + +```compile_fail +const FOO: u8 = 7; + +let FOO = 5; // error: variable bindings cannot shadow constants + +// or + +fn bar(FOO: u8) { // error: variable bindings cannot shadow constants + +} + +// or + +for FOO in bar { + +} +``` + +Introducing a new variable in Rust is done through a pattern. Thus you can have +`let` bindings like `let (a, b) = ...`. However, patterns also allow constants +in them, e.g. if you want to match over a constant: + +```ignore +const FOO: u8 = 1; + +match (x,y) { + (3, 4) => { .. }, // it is (3,4) + (FOO, 1) => { .. }, // it is (1,1) + (foo, 1) => { .. }, // it is (anything, 1) + // call the value in the first slot "foo" + _ => { .. } // it is anything +} +``` + +Here, the second arm matches the value of `x` against the constant `FOO`, +whereas the third arm will accept any value of `x` and call it `foo`. + +This works for `match`, however in cases where an irrefutable pattern is +required, constants can't be used. An irrefutable pattern is one which always +matches, whose purpose is only to bind variable names to values. These are +required by let, for, and function argument patterns. + +Refutable patterns in such a situation do not make sense, for example: + +```ignore +let Some(x) = foo; // what if foo is None, instead? + +let (1, x) = foo; // what if foo.0 is not 1? + +let (SOME_CONST, x) = foo; // what if foo.0 is not SOME_CONST? + +let SOME_CONST = foo; // what if foo is not SOME_CONST? +``` + +Thus, an irrefutable variable binding can't contain a constant. + +To fix this error, just give the marked variable a different name. +"##, + E0415: r##" More than one function parameter have the same name. Example of erroneous code: @@ -1086,7 +1149,6 @@ register_diagnostics! { E0409, // variable is bound with different mode in pattern # than in // pattern #1 E0410, // variable from pattern is not bound in pattern 1 - E0414, // only irrefutable patterns allowed here E0418, // is not an enum variant, struct or const E0420, // is not an associated const E0421, // unresolved associated const From 21117259b096b5e3438bcb0bcb918f8df860c9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Thu, 5 May 2016 06:41:49 +0200 Subject: [PATCH 07/23] specify the archive file as stdout If the `-f` option isn't given, GNU tar will use environment variable `TAPE` first, and next use the compiled-in default, which isn't necessary `stdout` (it is the tape device `/dev/rst0` under OpenBSD for example). --- mk/dist.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mk/dist.mk b/mk/dist.mk index 7fe28a7e26250..9491311ea7c12 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -77,6 +77,7 @@ $(PKG_TAR): $(PKG_FILES) $(Q)mkdir -p tmp/dist/$(PKG_NAME) $(Q)tar \ -C $(S) \ + -f - \ --exclude-vcs \ --exclude=*~ \ --exclude=*.pyc \ @@ -86,7 +87,7 @@ $(PKG_TAR): $(PKG_FILES) --exclude=*/llvm/test/*/*/*.ll \ --exclude=*/llvm/test/*/*/*.td \ --exclude=*/llvm/test/*/*/*.s \ - -c $(UNROOTED_PKG_FILES) | tar -x -C tmp/dist/$(PKG_NAME) + -c $(UNROOTED_PKG_FILES) | tar -x -f - -C tmp/dist/$(PKG_NAME) @$(call E, making $@) $(Q)tar -czf $(PKG_TAR) -C tmp/dist $(PKG_NAME) $(Q)rm -Rf tmp/dist/$(PKG_NAME) From 344681db2fdfe5b098759f0532d3a1ae593fac82 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 May 2016 14:14:41 -0400 Subject: [PATCH 08/23] trans: Split LocalCrateContext ownership out of SharedCrateContext. --- src/librustc_trans/base.rs | 26 ++-- src/librustc_trans/context.rs | 259 ++++++++++++++++++---------------- 2 files changed, 151 insertions(+), 134 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index b100282781ece..14cb945a13cf3 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -69,7 +69,7 @@ use common::{node_id_type, fulfill_obligation}; use common::{type_is_immediate, type_is_zero_size, val_ty}; use common; use consts; -use context::SharedCrateContext; +use context::{SharedCrateContext, CrateContextList}; use controlflow; use datum; use debuginfo::{self, DebugLoc, ToDebugLoc}; @@ -2523,7 +2523,7 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. -fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { +fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) { unsafe { let mut declared = HashSet::new(); @@ -2578,12 +2578,12 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { // when using MSVC linker. We do this only for data, as linker can fix up // code references on its own. // See #26591, #27438 -fn create_imps(cx: &SharedCrateContext) { +fn create_imps(cx: &CrateContextList) { // The x86 ABI seems to require that leading underscores are added to symbol // names, so we need an extra underscore on 32-bit. There's also a leading // '\x01' here which disables LLVM's symbol mangling (e.g. no extra // underscores added in front). - let prefix = if cx.sess().target.target.target_pointer_width == "32" { + let prefix = if cx.shared().sess().target.target.target_pointer_width == "32" { "\x01__imp__" } else { "\x01__imp_" @@ -2715,10 +2715,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, let link_meta = link::build_link_meta(&tcx, name); - let codegen_units = tcx.sess.opts.cg.codegen_units; - let shared_ccx = SharedCrateContext::new(&link_meta.crate_name, - codegen_units, - tcx, + let shared_ccx = SharedCrateContext::new(tcx, &mir_map, export_map, Sha256::new(), @@ -2727,8 +2724,11 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, check_overflow, check_dropflag); + let codegen_units = tcx.sess.opts.cg.codegen_units; + let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units); + { - let ccx = shared_ccx.get_ccx(0); + let ccx = crate_context_list.get_ccx(0); collect_translation_items(&ccx); // Translate all items. See `TransModVisitor` for @@ -2744,7 +2744,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, symbol_names_test::report_symbol_names(&ccx); } - for ccx in shared_ccx.iter() { + for ccx in crate_context_list.iter() { if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); } @@ -2793,7 +2793,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, } } - let modules = shared_ccx.iter() + let modules = crate_context_list.iter() .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() }) .collect(); @@ -2820,13 +2820,13 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, } if codegen_units > 1 { - internalize_symbols(&shared_ccx, + internalize_symbols(&crate_context_list, &reachable_symbols.iter().map(|x| &x[..]).collect()); } if sess.target.target.options.is_like_msvc && sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { - create_imps(&shared_ccx); + create_imps(&crate_context_list); } let metadata_module = ModuleTranslation { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1217b2b5a1b17..926b8a7b60b2a 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -64,8 +64,6 @@ pub struct Stats { /// crate, so it must not contain references to any LLVM data structures /// (aside from metadata-related ones). pub struct SharedCrateContext<'a, 'tcx: 'a> { - local_ccxs: Vec>, - metadata_llmod: ModuleRef, metadata_llcx: ContextRef, @@ -95,7 +93,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, - tn: TypeNames, + tn: TypeNames, // FIXME: This seems to be largely unused. needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, drop_glues: RefCell, ValueRef>>, @@ -188,16 +186,65 @@ impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { } } +pub struct CrateContextList<'a, 'tcx: 'a> { + shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccxs: Vec>, +} + +impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { + + pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>, + local_count: usize) + -> CrateContextList<'a, 'tcx> { + CrateContextList { + shared: shared_ccx, + local_ccxs: (0..local_count).map(|index| { + // Append ".rs" to crate name as LLVM module identifier. + // + // LLVM code generator emits a ".file filename" directive + // for ELF backends. Value of the "filename" is set as the + // LLVM module identifier. Due to a LLVM MC bug[1], LLVM + // crashes if the module identifier is same as other symbols + // such as a function name in the module. + // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 + let llmod_id = format!("{}.{}.rs", shared_ccx.link_meta.crate_name, index); + LocalCrateContext::new(shared_ccx, &llmod_id[..]) + }).collect() + } + } + + pub fn iter<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { + CrateContextIterator { + shared: self.shared, + index: 0, + local_ccxs: &self.local_ccxs[..] + } + } + + pub fn get_ccx<'b>(&'b self, index: usize) -> CrateContext<'b, 'tcx> { + CrateContext { + shared: self.shared, + index: index, + local_ccxs: &self.local_ccxs[..], + } + } + + pub fn shared(&self) -> &'a SharedCrateContext<'a, 'tcx> { + self.shared + } +} + pub struct CrateContext<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, - local: &'a LocalCrateContext<'tcx>, - /// The index of `local` in `shared.local_ccxs`. This is used in + local_ccxs: &'a [LocalCrateContext<'tcx>], + /// The index of `local` in `local_ccxs`. This is used in /// `maybe_iter(true)` to identify the original `LocalCrateContext`. index: usize, } pub struct CrateContextIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccxs: &'a [LocalCrateContext<'tcx>], index: usize, } @@ -205,7 +252,7 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { type Item = CrateContext<'a, 'tcx>; fn next(&mut self) -> Option> { - if self.index >= self.shared.local_ccxs.len() { + if self.index >= self.local_ccxs.len() { return None; } @@ -214,8 +261,8 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { Some(CrateContext { shared: self.shared, - local: &self.shared.local_ccxs[index], index: index, + local_ccxs: self.local_ccxs, }) } } @@ -223,6 +270,7 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { /// The iterator produced by `CrateContext::maybe_iter`. pub struct CrateContextMaybeIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccxs: &'a [LocalCrateContext<'tcx>], index: usize, single: bool, origin: usize, @@ -232,20 +280,20 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { type Item = (CrateContext<'a, 'tcx>, bool); fn next(&mut self) -> Option<(CrateContext<'a, 'tcx>, bool)> { - if self.index >= self.shared.local_ccxs.len() { + if self.index >= self.local_ccxs.len() { return None; } let index = self.index; self.index += 1; if self.single { - self.index = self.shared.local_ccxs.len(); + self.index = self.local_ccxs.len(); } let ccx = CrateContext { shared: self.shared, - local: &self.shared.local_ccxs[index], index: index, + local_ccxs: self.local_ccxs }; Some((ccx, index == self.origin)) } @@ -285,9 +333,7 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR } impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { - pub fn new(crate_name: &str, - local_count: usize, - tcx: &'b TyCtxt<'tcx>, + pub fn new(tcx: &'b TyCtxt<'tcx>, mir_map: &'b MirMap<'tcx>, export_map: ExportMap, symbol_hasher: Sha256, @@ -345,8 +391,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { // start) and then strongly recommending static linkage on MSVC! let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; - let mut shared_ccx = SharedCrateContext { - local_ccxs: Vec::with_capacity(local_count), + SharedCrateContext { metadata_llmod: metadata_llmod, metadata_llcx: metadata_llcx, export_map: export_map, @@ -375,55 +420,9 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { 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 { - // Append ".rs" to crate name as LLVM module identifier. - // - // LLVM code generator emits a ".file filename" directive - // for ELF backends. Value of the "filename" is set as the - // LLVM module identifier. Due to a LLVM MC bug[1], LLVM - // crashes if the module identifier is same as other symbols - // such as a function name in the module. - // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = format!("{}.{}.rs", crate_name, i); - let local_ccx = LocalCrateContext::new(&shared_ccx, &llmod_id[..]); - shared_ccx.local_ccxs.push(local_ccx); } - - shared_ccx } - pub fn iter<'a>(&'a self) -> CrateContextIterator<'a, 'tcx> { - CrateContextIterator { - shared: self, - index: 0, - } - } - - pub fn get_ccx<'a>(&'a self, index: usize) -> CrateContext<'a, 'tcx> { - CrateContext { - shared: self, - local: &self.local_ccxs[index], - index: index, - } - } - - fn get_smallest_ccx<'a>(&'a self) -> CrateContext<'a, 'tcx> { - let (local_ccx, index) = - self.local_ccxs - .iter() - .zip(0..self.local_ccxs.len()) - .min_by_key(|&(local_ccx, _idx)| local_ccx.n_llvm_insns.get()) - .unwrap(); - CrateContext { - shared: self, - local: local_ccx, - index: index, - } - } - - pub fn metadata_llmod(&self) -> ModuleRef { self.metadata_llmod } @@ -478,7 +477,7 @@ impl<'tcx> LocalCrateContext<'tcx> { None }; - let mut local_ccx = LocalCrateContext { + let local_ccx = LocalCrateContext { llmod: llmod, llcx: llcx, tn: TypeNames::new(), @@ -518,21 +517,28 @@ impl<'tcx> LocalCrateContext<'tcx> { .clone())), }; - local_ccx.int_type = Type::int(&local_ccx.dummy_ccx(shared)); - local_ccx.opaque_vec_type = Type::opaque_vec(&local_ccx.dummy_ccx(shared)); - - // Done mutating local_ccx directly. (The rest of the - // initialization goes through RefCell.) - { - let ccx = local_ccx.dummy_ccx(shared); + let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { + // Do a little dance to create a dummy CrateContext, so we can + // create some things in the LLVM module of this codegen unit + let mut local_ccxs = vec![local_ccx]; + let (int_type, opaque_vec_type, str_slice_ty) = { + let dummy_ccx = LocalCrateContext::dummy_ccx(shared, + local_ccxs.as_mut_slice()); + let mut str_slice_ty = Type::named_struct(&dummy_ccx, "str_slice"); + str_slice_ty.set_struct_body(&[Type::i8p(&dummy_ccx), + Type::int(&dummy_ccx)], + false); + (Type::int(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty) + }; + (int_type, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap()) + }; - let mut str_slice_ty = Type::named_struct(&ccx, "str_slice"); - str_slice_ty.set_struct_body(&[Type::i8p(&ccx), ccx.int_type()], false); - ccx.tn().associate_type("str_slice", &str_slice_ty); + local_ccx.int_type = int_type; + local_ccx.opaque_vec_type = opaque_vec_type; + local_ccx.tn.associate_type("str_slice", &str_slice_ty); - if ccx.sess().count_llvm_insns() { - base::init_insn_ctxt() - } + if shared.tcx.sess.count_llvm_insns() { + base::init_insn_ctxt() } local_ccx @@ -541,18 +547,19 @@ impl<'tcx> LocalCrateContext<'tcx> { /// Create a dummy `CrateContext` from `self` and the provided /// `SharedCrateContext`. This is somewhat dangerous because `self` may - /// not actually be an element of `shared.local_ccxs`, which can cause some - /// operations to panic unexpectedly. + /// not be fully initialized. /// /// This is used in the `LocalCrateContext` constructor to allow calling /// functions that expect a complete `CrateContext`, even before the local /// portion is fully initialized and attached to the `SharedCrateContext`. - fn dummy_ccx<'a>(&'a self, shared: &'a SharedCrateContext<'a, 'tcx>) + fn dummy_ccx<'a>(shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccxs: &'a [LocalCrateContext<'tcx>]) -> CrateContext<'a, 'tcx> { + assert!(local_ccxs.len() == 1); CrateContext { shared: shared, - local: self, - index: !0 as usize, + index: 0, + local_ccxs: local_ccxs } } } @@ -563,13 +570,23 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn local(&self) -> &'b LocalCrateContext<'tcx> { - self.local + &self.local_ccxs[self.index] } /// Get a (possibly) different `CrateContext` from the same /// `SharedCrateContext`. - pub fn rotate(&self) -> CrateContext<'b, 'tcx> { - self.shared.get_smallest_ccx() + pub fn rotate(&'b self) -> CrateContext<'b, 'tcx> { + let (_, index) = + self.local_ccxs + .iter() + .zip(0..self.local_ccxs.len()) + .min_by_key(|&(local_ccx, _idx)| local_ccx.n_llvm_insns.get()) + .unwrap(); + CrateContext { + shared: self.shared, + index: index, + local_ccxs: &self.local_ccxs[..], + } } /// Either iterate over only `self`, or iterate over all `CrateContext`s in @@ -584,10 +601,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { index: if iter_all { 0 } else { self.index }, single: !iter_all, origin: self.index, + local_ccxs: self.local_ccxs, } } - pub fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx> { self.shared.tcx } @@ -601,7 +618,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn raw_builder<'a>(&'a self) -> BuilderRef { - self.local.builder.b + self.local().builder.b } pub fn get_intrinsic(&self, key: &str) -> ValueRef { @@ -615,11 +632,11 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn llmod(&self) -> ModuleRef { - self.local.llmod + self.local().llmod } pub fn llcx(&self) -> ContextRef { - self.local.llcx + self.local().llcx } pub fn td(&self) -> llvm::TargetDataRef { @@ -627,7 +644,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn tn<'a>(&'a self) -> &'a TypeNames { - &self.local.tn + &self.local().tn } pub fn export_map<'a>(&'a self) -> &'a ExportMap { @@ -647,81 +664,81 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn needs_unwind_cleanup_cache(&self) -> &RefCell, bool>> { - &self.local.needs_unwind_cleanup_cache + &self.local().needs_unwind_cleanup_cache } pub fn fn_pointer_shims(&self) -> &RefCell, ValueRef>> { - &self.local.fn_pointer_shims + &self.local().fn_pointer_shims } pub fn drop_glues<'a>(&'a self) -> &'a RefCell, ValueRef>> { - &self.local.drop_glues + &self.local().drop_glues } pub fn external<'a>(&'a self) -> &'a RefCell>> { - &self.local.external + &self.local().external } pub fn external_srcs<'a>(&'a self) -> &'a RefCell> { - &self.local.external_srcs + &self.local().external_srcs } pub fn instances<'a>(&'a self) -> &'a RefCell, ValueRef>> { - &self.local.instances + &self.local().instances } pub fn monomorphizing<'a>(&'a self) -> &'a RefCell> { - &self.local.monomorphizing + &self.local().monomorphizing } pub fn vtables<'a>(&'a self) -> &'a RefCell, ValueRef>> { - &self.local.vtables + &self.local().vtables } pub fn const_cstr_cache<'a>(&'a self) -> &'a RefCell> { - &self.local.const_cstr_cache + &self.local().const_cstr_cache } pub fn const_unsized<'a>(&'a self) -> &'a RefCell> { - &self.local.const_unsized + &self.local().const_unsized } pub fn const_globals<'a>(&'a self) -> &'a RefCell> { - &self.local.const_globals + &self.local().const_globals } pub fn const_values<'a>(&'a self) -> &'a RefCell), ValueRef>> { - &self.local.const_values + &self.local().const_values } pub fn extern_const_values<'a>(&'a self) -> &'a RefCell> { - &self.local.extern_const_values + &self.local().extern_const_values } pub fn impl_method_cache<'a>(&'a self) -> &'a RefCell> { - &self.local.impl_method_cache + &self.local().impl_method_cache } pub fn closure_bare_wrapper_cache<'a>(&'a self) -> &'a RefCell> { - &self.local.closure_bare_wrapper_cache + &self.local().closure_bare_wrapper_cache } pub fn statics_to_rauw<'a>(&'a self) -> &'a RefCell> { - &self.local.statics_to_rauw + &self.local().statics_to_rauw } pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> { - &self.local.lltypes + &self.local().lltypes } pub fn llsizingtypes<'a>(&'a self) -> &'a RefCell, Type>> { - &self.local.llsizingtypes + &self.local().llsizingtypes } pub fn adt_reprs<'a>(&'a self) -> &'a RefCell, Rc>>> { - &self.local.adt_reprs + &self.local().adt_reprs } pub fn symbol_hasher<'a>(&'a self) -> &'a RefCell { @@ -729,7 +746,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell, String>> { - &self.local.type_hashcodes + &self.local().type_hashcodes } pub fn stats<'a>(&'a self) -> &'a Stats { @@ -745,43 +762,43 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn int_type(&self) -> Type { - self.local.int_type + self.local().int_type } pub fn opaque_vec_type(&self) -> Type { - self.local.opaque_vec_type + self.local().opaque_vec_type } pub fn closure_vals<'a>(&'a self) -> &'a RefCell, ValueRef>> { - &self.local.closure_vals + &self.local().closure_vals } pub fn dbg_cx<'a>(&'a self) -> &'a Option> { - &self.local.dbg_cx + &self.local().dbg_cx } pub fn eh_personality<'a>(&'a self) -> &'a Cell> { - &self.local.eh_personality + &self.local().eh_personality } pub fn eh_unwind_resume<'a>(&'a self) -> &'a Cell> { - &self.local.eh_unwind_resume + &self.local().eh_unwind_resume } pub fn rust_try_fn<'a>(&'a self) -> &'a Cell> { - &self.local.rust_try_fn + &self.local().rust_try_fn } fn intrinsics<'a>(&'a self) -> &'a RefCell> { - &self.local.intrinsics + &self.local().intrinsics } pub fn count_llvm_insn(&self) { - self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); + self.local().n_llvm_insns.set(self.local().n_llvm_insns.get() + 1); } pub fn trait_cache(&self) -> &RefCell>> { - &self.local.trait_cache + &self.local().trait_cache } pub fn obj_size_bound(&self) -> u64 { @@ -795,14 +812,14 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn enter_type_of(&self, ty: Ty<'tcx>) -> TypeOfDepthLock<'b, 'tcx> { - let current_depth = self.local.type_of_depth.get(); + let current_depth = self.local().type_of_depth.get(); debug!("enter_type_of({:?}) at depth {:?}", ty, current_depth); if current_depth > self.sess().recursion_limit.get() { self.sess().fatal( &format!("overflow representing the type `{}`", ty)) } - self.local.type_of_depth.set(current_depth + 1); - TypeOfDepthLock(self.local) + self.local().type_of_depth.set(current_depth + 1); + TypeOfDepthLock(self.local()) } pub fn check_overflow(&self) -> bool { From 51b4d6ee85d494639d281eaa59f546a40eb5d429 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 May 2016 14:24:41 -0400 Subject: [PATCH 09/23] Make trans::collector item printing methods independent of CrateContext. --- src/librustc_trans/base.rs | 2 +- src/librustc_trans/collector.rs | 128 ++++++++++++++++---------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 14cb945a13cf3..a7c8b1e8365f4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2965,7 +2965,7 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { let mut item_keys: Vec<_> = items .iter() .map(|i| { - let mut output = i.to_string(ccx); + let mut output = i.to_string(ccx.tcx()); output.push_str(" @@"); let mut empty = Vec::new(); let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index e8181579911d2..2d005692247f9 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -378,7 +378,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.to_string(ccx)); + debug!("BEGIN collect_items_rec({})", starting_point.to_string(ccx.tcx())); let mut neighbors = Vec::new(); let recursion_depth_reset; @@ -427,7 +427,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, recursion_depths.insert(def_id, depth); } - debug!("END collect_items_rec({})", starting_point.to_string(ccx)); + debug!("END collect_items_rec({})", starting_point.to_string(ccx.tcx())); } fn record_references<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -654,7 +654,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } }; - debug!("find_drop_glue_neighbors: {}", type_to_string(ccx, ty)); + debug!("find_drop_glue_neighbors: {}", type_to_string(ccx.tcx(), ty)); // Make sure the exchange_free_fn() lang-item gets translated if // there is a boxed value. @@ -783,7 +783,7 @@ fn do_static_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, param_substs: &'tcx Substs<'tcx>) -> Option<(DefId, &'tcx Substs<'tcx>)> { debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})", - def_id_to_string(ccx, fn_def_id), + def_id_to_string(ccx.tcx(), fn_def_id), fn_substs, param_substs); @@ -831,8 +831,8 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trait_id={}, \ callee_substs={:?}, \ param_substs={:?}", - def_id_to_string(ccx, trait_method.def_id), - def_id_to_string(ccx, trait_id), + def_id_to_string(ccx.tcx(), trait_method.def_id), + def_id_to_string(ccx.tcx(), trait_id), callee_substs, param_substs); @@ -965,7 +965,7 @@ fn create_fn_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> TransItem<'tcx> { debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})", - def_id_to_string(ccx, def_id), + def_id_to_string(ccx.tcx(), def_id), fn_substs, param_substs); @@ -1076,7 +1076,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { if self.mode == TransItemCollectionMode::Eager { debug!("RootCollector: ADT drop-glue for {}", - def_id_to_string(self.ccx, + def_id_to_string(self.ccx.tcx(), self.ccx.tcx().map.local_def_id(item.id))); let ty = glue::get_drop_glue_type(self.ccx, ty); @@ -1086,7 +1086,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", - def_id_to_string(self.ccx, + def_id_to_string(self.ccx.tcx(), self.ccx.tcx().map.local_def_id(item.id))); self.output.push(TransItem::Static(item.id)); } @@ -1096,7 +1096,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { let def_id = self.ccx.tcx().map.local_def_id(item.id); debug!("RootCollector: ItemFn({})", - def_id_to_string(self.ccx, def_id)); + def_id_to_string(self.ccx.tcx(), def_id)); let instance = Instance::mono(self.ccx.tcx(), def_id); self.output.push(TransItem::Fn(instance)); @@ -1133,7 +1133,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { let def_id = self.ccx.tcx().map.local_def_id(ii.id); debug!("RootCollector: MethodImplItem({})", - def_id_to_string(self.ccx, def_id)); + def_id_to_string(self.ccx.tcx(), def_id)); let instance = Instance::mono(self.ccx.tcx(), def_id); self.output.push(TransItem::Fn(instance)); @@ -1164,7 +1164,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let impl_def_id = tcx.map.local_def_id(item.id); debug!("create_trans_items_for_default_impls(item={})", - def_id_to_string(ccx, impl_def_id)); + def_id_to_string(ccx.tcx(), impl_def_id)); if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { let default_impls = tcx.provided_trait_methods(trait_ref.def_id); @@ -1226,9 +1226,9 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, /// Same as `unique_type_name()` but with the result pushed onto the given /// `output` parameter. -pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: ty::Ty<'tcx>, - output: &mut String) { +pub fn push_unique_type_name<'tcx>(tcx: &TyCtxt<'tcx>, + t: ty::Ty<'tcx>, + output: &mut String) { match t.sty { ty::TyBool => output.push_str("bool"), ty::TyChar => output.push_str("char"), @@ -1247,13 +1247,13 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs) => { - push_item_name(cx, adt_def.did, output); - push_type_params(cx, &substs.types, &[], output); + push_item_name(tcx, adt_def.did, output); + push_type_params(tcx, &substs.types, &[], output); }, ty::TyTuple(ref component_types) => { output.push('('); for &component_type in component_types { - push_unique_type_name(cx, component_type, output); + push_unique_type_name(tcx, component_type, output); output.push_str(", "); } if !component_types.is_empty() { @@ -1264,7 +1264,7 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }, ty::TyBox(inner_type) => { output.push_str("Box<"); - push_unique_type_name(cx, inner_type, output); + push_unique_type_name(tcx, inner_type, output); output.push('>'); }, ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { @@ -1274,7 +1274,7 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::MutMutable => output.push_str("mut "), } - push_unique_type_name(cx, inner_type, output); + push_unique_type_name(tcx, inner_type, output); }, ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { output.push('&'); @@ -1282,22 +1282,22 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("mut "); } - push_unique_type_name(cx, inner_type, output); + push_unique_type_name(tcx, inner_type, output); }, ty::TyArray(inner_type, len) => { output.push('['); - push_unique_type_name(cx, inner_type, output); + push_unique_type_name(tcx, inner_type, output); output.push_str(&format!("; {}", len)); output.push(']'); }, ty::TySlice(inner_type) => { output.push('['); - push_unique_type_name(cx, inner_type, output); + push_unique_type_name(tcx, inner_type, output); output.push(']'); }, ty::TyTrait(ref trait_data) => { - push_item_name(cx, trait_data.principal.skip_binder().def_id, output); - push_type_params(cx, + push_item_name(tcx, trait_data.principal.skip_binder().def_id, output); + push_type_params(tcx, &trait_data.principal.skip_binder().substs.types, &trait_data.bounds.projection_bounds, output); @@ -1316,10 +1316,10 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); - let sig = cx.tcx().erase_late_bound_regions(sig); + let sig = tcx.erase_late_bound_regions(sig); if !sig.inputs.is_empty() { for ¶meter_type in &sig.inputs { - push_unique_type_name(cx, parameter_type, output); + push_unique_type_name(tcx, parameter_type, output); output.push_str(", "); } output.pop(); @@ -1340,7 +1340,7 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::FnConverging(result_type) if result_type.is_nil() => {} ty::FnConverging(result_type) => { output.push_str(" -> "); - push_unique_type_name(cx, result_type, output); + push_unique_type_name(tcx, result_type, output); } ty::FnDiverging => { output.push_str(" -> !"); @@ -1348,11 +1348,11 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }, ty::TyClosure(def_id, ref closure_substs) => { - push_item_name(cx, def_id, output); + push_item_name(tcx, def_id, output); output.push_str("{"); output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); output.push_str("}"); - push_type_params(cx, &closure_substs.func_substs.types, &[], output); + push_type_params(tcx, &closure_substs.func_substs.types, &[], output); } ty::TyError | ty::TyInfer(_) | @@ -1364,17 +1364,17 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } -fn push_item_name(ccx: &CrateContext, +fn push_item_name(tcx: &TyCtxt, def_id: DefId, output: &mut String) { - let def_path = ccx.tcx().def_path(def_id); + let def_path = tcx.def_path(def_id); // some_crate:: - output.push_str(&ccx.tcx().crate_name(def_path.krate)); + output.push_str(&tcx.crate_name(def_path.krate)); output.push_str("::"); // foo::bar::ItemName:: - for part in ccx.tcx().def_path(def_id).data { + for part in tcx.def_path(def_id).data { output.push_str(&format!("{}[{}]::", part.data.as_interned_str(), part.disambiguator)); @@ -1385,10 +1385,10 @@ fn push_item_name(ccx: &CrateContext, output.pop(); } -fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - types: &'tcx subst::VecPerParamSpace>, - projections: &[ty::PolyProjectionPredicate<'tcx>], - output: &mut String) { +fn push_type_params<'tcx>(tcx: &TyCtxt<'tcx>, + types: &'tcx subst::VecPerParamSpace>, + projections: &[ty::PolyProjectionPredicate<'tcx>], + output: &mut String) { if types.is_empty() && projections.is_empty() { return; } @@ -1396,7 +1396,7 @@ fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push('<'); for &type_parameter in types { - push_unique_type_name(cx, type_parameter, output); + push_unique_type_name(tcx, type_parameter, output); output.push_str(", "); } @@ -1405,7 +1405,7 @@ fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let name = token::get_ident_interner().get(projection.projection_ty.item_name); output.push_str(&name[..]); output.push_str("="); - push_unique_type_name(cx, projection.ty, output); + push_unique_type_name(tcx, projection.ty, output); output.push_str(", "); } @@ -1415,24 +1415,24 @@ fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push('>'); } -fn push_instance_as_string<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>, - output: &mut String) { - push_item_name(ccx, instance.def, output); - push_type_params(ccx, &instance.substs.types, &[], output); +fn push_instance_as_string<'tcx>(tcx: &TyCtxt<'tcx>, + instance: Instance<'tcx>, + output: &mut String) { + push_item_name(tcx, instance.def, output); + push_type_params(tcx, &instance.substs.types, &[], output); } -pub fn def_id_to_string(ccx: &CrateContext, def_id: DefId) -> String { +pub fn def_id_to_string(tcx: &TyCtxt, def_id: DefId) -> String { let mut output = String::new(); - push_item_name(ccx, def_id, &mut output); + push_item_name(tcx, def_id, &mut output); output } -fn type_to_string<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - ty: ty::Ty<'tcx>) - -> String { +fn type_to_string<'tcx>(tcx: &TyCtxt<'tcx>, + ty: ty::Ty<'tcx>) + -> String { let mut output = String::new(); - push_unique_type_name(ccx, ty, &mut output); + push_unique_type_name(tcx, ty, &mut output); output } @@ -1489,8 +1489,8 @@ impl<'tcx> TransItem<'tcx> { } } - pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String { - let hir_map = &ccx.tcx().map; + pub fn to_string(&self, tcx: &TyCtxt<'tcx>) -> String { + let hir_map = &tcx.map; return match *self { TransItem::DropGlue(dg) => { @@ -1499,26 +1499,26 @@ impl<'tcx> TransItem<'tcx> { DropGlueKind::Ty(_) => s.push_str("drop-glue "), DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), }; - push_unique_type_name(ccx, dg.ty(), &mut s); + push_unique_type_name(tcx, dg.ty(), &mut s); s } TransItem::Fn(instance) => { - to_string_internal(ccx, "fn ", instance) + to_string_internal(tcx, "fn ", instance) }, TransItem::Static(node_id) => { let def_id = hir_map.local_def_id(node_id); - let instance = Instance::mono(ccx.tcx(), def_id); - to_string_internal(ccx, "static ", instance) + let instance = Instance::mono(tcx, def_id); + to_string_internal(tcx, "static ", instance) }, }; - fn to_string_internal<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - prefix: &str, - instance: Instance<'tcx>) - -> String { + fn to_string_internal<'tcx>(tcx: &TyCtxt<'tcx>, + prefix: &str, + instance: Instance<'tcx>) + -> String { let mut result = String::with_capacity(32); result.push_str(prefix); - push_instance_as_string(ccx, instance, &mut result); + push_instance_as_string(tcx, instance, &mut result); result } } @@ -1572,7 +1572,7 @@ pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { let mut item_keys = FnvHashMap(); for (item, item_state) in trans_items.iter() { - let k = item.to_string(&ccx); + let k = item.to_string(ccx.tcx()); if item_keys.contains_key(&k) { let prev: (TransItem, TransItemState) = item_keys[&k]; @@ -1600,7 +1600,7 @@ pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { let mut generated = FnvHashSet(); for (item, item_state) in trans_items.iter() { - let item_key = item.to_string(&ccx); + let item_key = item.to_string(ccx.tcx()); match *item_state { TransItemState::PredictedAndGenerated => { From f5805f6ba344dbe1e7b55064765e271e775da396 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 May 2016 14:29:02 -0400 Subject: [PATCH 10/23] trans: Make normalize_and_test_predicates() not depend on CrateContext. --- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/common.rs | 7 +++---- src/librustc_trans/meth.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2d005692247f9..f01443ddd566a 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1191,7 +1191,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert!(mth.is_provided); let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); - if !normalize_and_test_predicates(ccx, predicates.into_vec()) { + if !normalize_and_test_predicates(ccx.tcx(), predicates.into_vec()) { continue; } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5ce7caf5deb06..67cc1488ac6b8 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -1129,14 +1129,13 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, /// returns false, then either normalize encountered an error or one /// of the predicates did not hold. Used when creating vtables to /// check for unsatisfiable methods. -pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - predicates: Vec>) - -> bool +pub fn normalize_and_test_predicates<'tcx>(tcx: &TyCtxt<'tcx>, + predicates: Vec>) + -> bool { debug!("normalize_and_test_predicates(predicates={:?})", predicates); - let tcx = ccx.tcx(); let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any); let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 9e5476ae80d47..b351394950b5e 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -287,7 +287,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // try and trans it, in that case. Issue #23435. if mth.is_provided { let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); - if !normalize_and_test_predicates(ccx, predicates.into_vec()) { + if !normalize_and_test_predicates(tcx, predicates.into_vec()) { debug!("get_vtable_methods: predicates do not hold"); return None; } From 8a8bd1dea07fdecaa4f7444315bf4d8e8d614edd Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 May 2016 14:32:59 -0400 Subject: [PATCH 11/23] trans: Make meth::get_vtable_methods() not depend on CrateContext. --- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/meth.rs | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index f01443ddd566a..7fac250ef77df 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1005,7 +1005,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, impl_def_id, substs, nested: _ }) => { - let items = meth::get_vtable_methods(ccx, impl_def_id, substs) + let items = meth::get_vtable_methods(ccx.tcx(), impl_def_id, substs) .into_iter() // filter out None values .filter_map(|opt_impl_method| opt_impl_method) diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index b351394950b5e..d08c26783e985 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -157,7 +157,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs, nested: _ }) => { let nullptr = C_null(Type::nil(ccx).ptr_to()); - get_vtable_methods(ccx, id, substs) + get_vtable_methods(tcx, id, substs) .into_iter() .map(|opt_mth| opt_mth.map_or(nullptr, |mth| { Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx).val @@ -215,13 +215,11 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, vtable } -pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - impl_id: DefId, - substs: &'tcx subst::Substs<'tcx>) - -> Vec>> +pub fn get_vtable_methods<'tcx>(tcx: &TyCtxt<'tcx>, + impl_id: DefId, + substs: &'tcx subst::Substs<'tcx>) + -> Vec>> { - let tcx = ccx.tcx(); - debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs); let trt_id = match tcx.impl_trait_ref(impl_id) { From a36e5bd0354e33579b8c76a1c1e7733f4b4ed9e3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 May 2016 14:59:16 -0400 Subject: [PATCH 12/23] trans: Make various trans::collector functions independent of CrateContext. --- src/librustc_trans/collector.rs | 101 ++++++++++++++++---------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 7fac250ef77df..be27be3fc709d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -397,7 +397,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, } TransItem::Fn(instance) => { // Keep track of the monomorphization recursion depth - recursion_depth_reset = Some(check_recursion_limit(ccx, + recursion_depth_reset = Some(check_recursion_limit(ccx.tcx(), instance, recursion_depths)); @@ -417,7 +417,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, } } - record_references(ccx, starting_point, &neighbors[..], reference_map); + record_references(ccx.tcx(), starting_point, &neighbors[..], reference_map); for neighbour in neighbors { collect_items_rec(ccx, neighbour, visited, recursion_depths, reference_map); @@ -430,23 +430,23 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, debug!("END collect_items_rec({})", starting_point.to_string(ccx.tcx())); } -fn record_references<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - caller: TransItem<'tcx>, - callees: &[TransItem<'tcx>], - reference_map: &mut ReferenceMap<'tcx>) { +fn record_references<'tcx>(tcx: &TyCtxt<'tcx>, + caller: TransItem<'tcx>, + callees: &[TransItem<'tcx>], + reference_map: &mut ReferenceMap<'tcx>) { let iter = callees.into_iter() .map(|callee| { let is_inlining_candidate = callee.is_from_extern_crate() || - callee.requests_inline(ccx.tcx()); + callee.requests_inline(tcx); (*callee, is_inlining_candidate) }); reference_map.record_references(caller, iter); } -fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>, - recursion_depths: &mut DefIdMap) - -> (DefId, usize) { +fn check_recursion_limit<'tcx>(tcx: &TyCtxt<'tcx>, + instance: Instance<'tcx>, + recursion_depths: &mut DefIdMap) + -> (DefId, usize) { let recursion_depth = recursion_depths.get(&instance.def) .map(|x| *x) .unwrap_or(0); @@ -455,13 +455,13 @@ fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if recursion_depth > ccx.sess().recursion_limit.get() { + if recursion_depth > tcx.sess.recursion_limit.get() { let error = format!("reached the recursion limit while instantiating `{}`", instance); - if let Some(node_id) = ccx.tcx().map.as_local_node_id(instance.def) { - ccx.sess().span_fatal(ccx.tcx().map.span(node_id), &error); + if let Some(node_id) = tcx.map.as_local_node_id(instance.def) { + tcx.sess.span_fatal(tcx.map.span(node_id), &error); } else { - ccx.sess().fatal(&error); + tcx.sess.fatal(&error); } } @@ -485,8 +485,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { match *rvalue { mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id, ref substs), _) => { - assert!(can_have_local_instance(self.ccx, def_id)); - let trans_item = create_fn_trans_item(self.ccx, + assert!(can_have_local_instance(self.ccx.tcx(), def_id)); + let trans_item = create_fn_trans_item(self.ccx.tcx(), def_id, substs.func_substs, self.param_substs); @@ -524,9 +524,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { .require(ExchangeMallocFnLangItem) .unwrap_or_else(|e| self.ccx.sess().fatal(&e)); - assert!(can_have_local_instance(self.ccx, exchange_malloc_fn_def_id)); + assert!(can_have_local_instance(self.ccx.tcx(), exchange_malloc_fn_def_id)); let exchange_malloc_fn_trans_item = - create_fn_trans_item(self.ccx, + create_fn_trans_item(self.ccx.tcx(), exchange_malloc_fn_def_id, &Substs::empty(), self.param_substs); @@ -593,7 +593,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // result in a translation item ... if can_result_in_trans_item(self.ccx, callee_def_id) { // ... and create one if it does. - let trans_item = create_fn_trans_item(self.ccx, + let trans_item = create_fn_trans_item(self.ccx.tcx(), callee_def_id, callee_substs, self.param_substs); @@ -628,18 +628,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { return false; } - can_have_local_instance(ccx, def_id) + can_have_local_instance(ccx.tcx(), def_id) } } } -fn can_have_local_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId) - -> bool { +fn can_have_local_instance<'tcx>(tcx: &TyCtxt<'tcx>, + def_id: DefId) + -> bool { // Take a look if we have the definition available. If not, we // will not emit code for this item in the local crate, and thus // don't create a translation item for it. - def_id.is_local() || ccx.sess().cstore.is_item_mir_available(def_id) + def_id.is_local() || tcx.sess.cstore.is_item_mir_available(def_id) } fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -664,9 +664,9 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, .require(ExchangeFreeFnLangItem) .unwrap_or_else(|e| ccx.sess().fatal(&e)); - assert!(can_have_local_instance(ccx, exchange_free_fn_def_id)); + assert!(can_have_local_instance(ccx.tcx(), exchange_free_fn_def_id)); let exchange_free_fn_trans_item = - create_fn_trans_item(ccx, + create_fn_trans_item(ccx.tcx(), exchange_free_fn_def_id, &Substs::empty(), &Substs::empty()); @@ -703,8 +703,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => bug!() }; - if can_have_local_instance(ccx, destructor_did) { - let trans_item = create_fn_trans_item(ccx, + if can_have_local_instance(ccx.tcx(), destructor_did) { + let trans_item = create_fn_trans_item(ccx.tcx(), destructor_did, substs, &Substs::empty()); @@ -958,29 +958,27 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -fn create_fn_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId, - fn_substs: &Substs<'tcx>, - param_substs: &Substs<'tcx>) - -> TransItem<'tcx> -{ +fn create_fn_trans_item<'tcx>(tcx: &TyCtxt<'tcx>, + def_id: DefId, + fn_substs: &Substs<'tcx>, + param_substs: &Substs<'tcx>) + -> TransItem<'tcx> { debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})", - def_id_to_string(ccx.tcx(), def_id), + def_id_to_string(tcx, def_id), fn_substs, param_substs); // We only get here, if fn_def_id either designates a local item or // an inlineable external item. Non-inlineable external items are // ignored because we don't want to generate any code for them. - let concrete_substs = monomorphize::apply_param_substs(ccx.tcx(), + let concrete_substs = monomorphize::apply_param_substs(tcx, param_substs, fn_substs); - let concrete_substs = ccx.tcx().erase_regions(&concrete_substs); + let concrete_substs = tcx.erase_regions(&concrete_substs); let trans_item = TransItem::Fn(Instance::new(def_id, - &ccx.tcx().mk_substs(concrete_substs))); - + &tcx.mk_substs(concrete_substs))); return trans_item; } @@ -1011,8 +1009,8 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, .filter_map(|opt_impl_method| opt_impl_method) // create translation items .filter_map(|impl_method| { - if can_have_local_instance(ccx, impl_method.method.def_id) { - Some(create_fn_trans_item(ccx, + if can_have_local_instance(ccx.tcx(), impl_method.method.def_id) { + Some(create_fn_trans_item(ccx.tcx(), impl_method.method.def_id, &impl_method.substs, &Substs::empty())) @@ -1060,7 +1058,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemImpl(..) => { if self.mode == TransItemCollectionMode::Eager { - create_trans_items_for_default_impls(self.ccx, + create_trans_items_for_default_impls(self.ccx.tcx(), item, self.output); } @@ -1146,9 +1144,9 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } } -fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - item: &'tcx hir::Item, - output: &mut Vec>) { +fn create_trans_items_for_default_impls<'tcx>(tcx: &TyCtxt<'tcx>, + item: &'tcx hir::Item, + output: &mut Vec>) { match item.node { hir::ItemImpl(_, _, @@ -1160,11 +1158,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return } - let tcx = ccx.tcx(); let impl_def_id = tcx.map.local_def_id(item.id); debug!("create_trans_items_for_default_impls(item={})", - def_id_to_string(ccx.tcx(), impl_def_id)); + def_id_to_string(tcx, impl_def_id)); if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { let default_impls = tcx.provided_trait_methods(trait_ref.def_id); @@ -1191,13 +1188,13 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert!(mth.is_provided); let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); - if !normalize_and_test_predicates(ccx.tcx(), predicates.into_vec()) { + if !normalize_and_test_predicates(tcx, predicates.into_vec()) { continue; } - if can_have_local_instance(ccx, default_impl.def_id) { - let empty_substs = ccx.tcx().mk_substs(ccx.tcx().erase_regions(mth.substs)); - let item = create_fn_trans_item(ccx, + if can_have_local_instance(tcx, default_impl.def_id) { + let empty_substs = tcx.mk_substs(tcx.erase_regions(mth.substs)); + let item = create_fn_trans_item(tcx, default_impl.def_id, callee_substs, empty_substs); From 09d2712b6c063eee0ef287ee50ca6dda18fef951 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 00:47:28 -0400 Subject: [PATCH 13/23] trans: Make common::fulfill_obligation only depend on SharedCrateContext. Plus make it produce a nicer dependency graph via DepTrackingMap::memoize(). --- src/librustc_trans/base.rs | 2 +- src/librustc_trans/callee.rs | 2 +- src/librustc_trans/collector.rs | 6 +- src/librustc_trans/common.rs | 118 +++++++++++++++----------------- src/librustc_trans/context.rs | 15 ++-- src/librustc_trans/glue.rs | 2 +- src/librustc_trans/meth.rs | 2 +- 7 files changed, 70 insertions(+), 77 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a7c8b1e8365f4..f64b33b714e6d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -679,7 +679,7 @@ pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, substs: ccx.tcx().mk_substs(trait_substs) }); - match fulfill_obligation(ccx, DUMMY_SP, trait_ref) { + match fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { ccx.tcx().custom_coerce_unsized_kind(impl_def_id) } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 8c22ddbb462c0..88f7bbd1aadb8 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -155,7 +155,7 @@ impl<'tcx> Callee<'tcx> { let method_item = tcx.impl_or_trait_item(def_id); let trait_id = method_item.container().id(); let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); - match common::fulfill_obligation(ccx, DUMMY_SP, trait_ref) { + match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(vtable_impl) => { let impl_did = vtable_impl.impl_def_id; let mname = tcx.item_name(def_id); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index be27be3fc709d..3812bd506d18c 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -698,7 +698,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs: self_type_substs, }.to_poly_trait_ref(); - let substs = match fulfill_obligation(ccx, DUMMY_SP, trait_ref) { + let substs = match fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(data) => data.substs, _ => bug!() }; @@ -841,7 +841,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, callee_substs); let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id)); - let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); + let vtbl = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -996,7 +996,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Walk all methods of the trait, including those of its supertraits for trait_ref in traits::supertraits(ccx.tcx(), poly_trait_ref) { - let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref); + let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); match vtable { traits::VtableImpl( traits::VtableImplData { diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 67cc1488ac6b8..a70af8db49213 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -20,6 +20,7 @@ use rustc::cfg; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::infer; +use rustc::util::common::MemoizationMap; use middle::lang_items::LangItem; use rustc::ty::subst::Substs; use abi::{Abi, FnType}; @@ -54,7 +55,7 @@ use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::InternedString; use syntax::parse::token; -pub use context::CrateContext; +pub use context::{CrateContext, SharedCrateContext}; /// Is the type's representation size known at compile time? pub fn type_is_sized<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { @@ -1051,7 +1052,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) -> /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should /// guarantee to us that all nested obligations *could be* resolved if we wanted to. -pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +pub fn fulfill_obligation<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, span: Span, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> @@ -1061,68 +1062,63 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Remove any references to regions; this helps improve caching. let trait_ref = tcx.erase_regions(&trait_ref); - // First check the cache. - match ccx.trait_cache().borrow().get(&trait_ref) { - Some(vtable) => { - info!("Cache hit: {:?}", trait_ref); - return (*vtable).clone(); - } - None => { } - } - - debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}", - trait_ref, trait_ref.def_id()); - - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any); - let mut selcx = SelectionContext::new(&infcx); - - let obligation = - traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID), - trait_ref.to_poly_trait_predicate()); - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - debug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref); - ccx.sess().span_fatal( - span, - "reached the recursion limit during monomorphization (selection ambiguity)"); - } - Err(e) => { - span_bug!( - span, - "Encountered error `{:?}` selecting `{:?}` during trans", - e, - trait_ref) - } - }; - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infer::drain_fulfillment_cx_or_panic( - span, &infcx, &mut fulfill_cx, &vtable - ); + ccx.trait_cache().memoize(trait_ref, || { + debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}", + trait_ref, trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let infcx = infer::normalizing_infer_ctxt(tcx, + &tcx.tables, + ProjectionMode::Any); + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = traits::ObligationCause::misc(span, + ast::DUMMY_NODE_ID); + let obligation = traits::Obligation::new(obligation_cause, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + debug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref); + ccx.sess().span_fatal( + span, + "reached the recursion limit during monomorphization \ + (selection ambiguity)"); + } + Err(e) => { + span_bug!( + span, + "Encountered error `{:?}` selecting `{:?}` during trans", + e, + trait_ref) + } + }; - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = traits::FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infer::drain_fulfillment_cx_or_panic( + span, &infcx, &mut fulfill_cx, &vtable + ); - ccx.trait_cache().borrow_mut().insert(trait_ref, vtable.clone()); + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable + vtable + }) } /// Normalizes the predicates and checks whether they hold. If this diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 926b8a7b60b2a..1bb7e62725554 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -84,6 +84,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { use_dll_storage_attrs: bool, translation_items: RefCell, TransItemState>>, + trait_cache: RefCell>>, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -166,8 +167,6 @@ pub struct LocalCrateContext<'tcx> { /// Depth of the current type-of computation - used to bail out type_of_depth: Cell, - - trait_cache: RefCell>>, } // Implement DepTrackingMapConfig for `trait_cache` @@ -420,6 +419,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { available_drop_glues: RefCell::new(FnvHashMap()), use_dll_storage_attrs: use_dll_storage_attrs, translation_items: RefCell::new(FnvHashMap()), + trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } } @@ -443,6 +443,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.item_symbols } + pub fn trait_cache(&self) -> &RefCell>> { + &self.trait_cache + } + pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { &self.link_meta } @@ -512,9 +516,6 @@ impl<'tcx> LocalCrateContext<'tcx> { intrinsics: RefCell::new(FnvHashMap()), n_llvm_insns: Cell::new(0), type_of_depth: Cell::new(0), - trait_cache: RefCell::new(DepTrackingMap::new(shared.tcx - .dep_graph - .clone())), }; let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { @@ -797,10 +798,6 @@ 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>> { - &self.local().trait_cache - } - pub fn obj_size_bound(&self) -> u64 { self.tcx().data_layout.obj_size_bound() } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 06761a7016add..06f9000c4ba90 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -364,7 +364,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def_id: tcx.lang_items.drop_trait().unwrap(), substs: tcx.mk_substs(Substs::empty().with_self_ty(t)) }); - let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) { + let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(data) => data, _ => bug!("dtor for {:?} is not an impl???", t) }; diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index d08c26783e985..648a232ef6946 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -144,7 +144,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Not in the cache. Build it. let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| { - let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone()); + let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref.clone()); match vtable { // Should default trait error here? traits::VtableDefaultImpl(_) | From bf674ec511a911c249ea233f92b904cf655558a1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 00:55:53 -0400 Subject: [PATCH 14/23] trans: Make base::custom_coerce_unsize_info only depend on SharedCrateContext. --- src/librustc_trans/base.rs | 4 ++-- src/librustc_trans/collector.rs | 5 ++--- src/librustc_trans/expr.rs | 4 +++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f64b33b714e6d..84a5bff6050b2 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -665,7 +665,7 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, +pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &SharedCrateContext<'ccx, 'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> CustomCoerceUnsized { @@ -679,7 +679,7 @@ pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, substs: ccx.tcx().mk_substs(trait_substs) }); - match fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { + match fulfill_obligation(ccx, DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { ccx.tcx().custom_coerce_unsized_kind(impl_def_id) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 3812bd506d18c..2601656894f86 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -211,8 +211,7 @@ use syntax::parse::token; use base::{custom_coerce_unsize_info, llvm_linkage_by_name}; use context::CrateContext; -use common::{fulfill_obligation, normalize_and_test_predicates, - type_is_sized}; +use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized}; use glue::{self, DropGlueKind}; use llvm; use meth; @@ -934,7 +933,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, &ty::TyStruct(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); - let kind = custom_coerce_unsize_info(ccx, source_ty, target_ty); + let kind = custom_coerce_unsize_info(ccx.shared(), source_ty, target_ty); let coerce_index = match kind { CustomCoerceUnsized::Struct(i) => i diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs index cd11ca586890c..edb3d167ddeb0 100644 --- a/src/librustc_trans/expr.rs +++ b/src/librustc_trans/expr.rs @@ -510,7 +510,9 @@ 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 kind = custom_coerce_unsize_info(bcx.ccx(), source.ty, target.ty); + let kind = custom_coerce_unsize_info(bcx.ccx().shared(), + source.ty, + target.ty); let repr_source = adt::represent_type(bcx.ccx(), source.ty); let src_fields = match &*repr_source { From 15955df63fbb6ff09e8f8a60cce30db200aa1e60 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 01:23:44 -0400 Subject: [PATCH 15/23] trans: Make glue::get_drop_glue_type() independent of CrateContext. --- src/librustc_trans/collector.rs | 14 +++++++------- src/librustc_trans/glue.rs | 26 ++++++++++++++------------ src/librustc_trans/mir/block.rs | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2601656894f86..a469ef48deeac 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -390,7 +390,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, TransItem::Static(node_id) => { let def_id = ccx.tcx().map.local_def_id(node_id); let ty = ccx.tcx().lookup_item_type(def_id).ty; - let ty = glue::get_drop_glue_type(ccx, ty); + let ty = glue::get_drop_glue_type(ccx.tcx(), ty); neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); recursion_depth_reset = None; } @@ -551,7 +551,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.param_substs, &ty); let ty = self.ccx.tcx().erase_regions(&ty); - let ty = glue::get_drop_glue_type(self.ccx, ty); + let ty = glue::get_drop_glue_type(self.ccx.tcx(), ty); self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } @@ -737,7 +737,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let field_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &field.unsubst_ty()); - let field_type = glue::get_drop_glue_type(ccx, field_type); + let field_type = glue::get_drop_glue_type(ccx.tcx(), field_type); if glue::type_needs_drop(ccx.tcx(), field_type) { output.push(TransItem::DropGlue(DropGlueKind::Ty(field_type))); @@ -746,7 +746,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ty::TyClosure(_, ref substs) => { for upvar_ty in &substs.upvar_tys { - let upvar_ty = glue::get_drop_glue_type(ccx, upvar_ty); + let upvar_ty = glue::get_drop_glue_type(ccx.tcx(), upvar_ty); if glue::type_needs_drop(ccx.tcx(), upvar_ty) { output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty))); } @@ -754,14 +754,14 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ty::TyBox(inner_type) | ty::TyArray(inner_type, _) => { - let inner_type = glue::get_drop_glue_type(ccx, inner_type); + let inner_type = glue::get_drop_glue_type(ccx.tcx(), inner_type); if glue::type_needs_drop(ccx.tcx(), inner_type) { output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type))); } } ty::TyTuple(ref args) => { for arg in args { - let arg = glue::get_drop_glue_type(ccx, arg); + let arg = glue::get_drop_glue_type(ccx.tcx(), arg); if glue::type_needs_drop(ccx.tcx(), arg) { output.push(TransItem::DropGlue(DropGlueKind::Ty(arg))); } @@ -1076,7 +1076,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { def_id_to_string(self.ccx.tcx(), self.ccx.tcx().map.local_def_id(item.id))); - let ty = glue::get_drop_glue_type(self.ccx, ty); + let ty = glue::get_drop_glue_type(self.ccx.tcx(), ty); self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 06f9000c4ba90..e83580b95bcc4 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -19,7 +19,7 @@ use llvm; use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; use rustc::ty::subst::{Substs}; -use rustc::traits; +use rustc::{infer, traits}; use rustc::ty::{self, Ty, TyCtxt}; use abi::{Abi, FnType}; use adt; @@ -92,13 +92,12 @@ pub fn type_needs_drop<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { tcx.type_needs_drop_given_env(ty, &tcx.empty_parameter_environment()) } -pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>) -> Ty<'tcx> { - let tcx = ccx.tcx(); +pub fn get_drop_glue_type<'tcx>(tcx: &TyCtxt<'tcx>, + t: Ty<'tcx>) -> Ty<'tcx> { // Even if there is no dtor for t, there might be one deeper down and we // might need to pass in the vtable ptr. if !type_is_sized(tcx, t) { - return ccx.tcx().erase_regions(&t); + return tcx.erase_regions(&t); } // FIXME (#22815): note that type_needs_drop conservatively @@ -116,15 +115,18 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, match t.sty { ty::TyBox(typ) if !type_needs_drop(&tcx, typ) && type_is_sized(tcx, typ) => { - let llty = sizing_type_of(ccx, typ); - // `Box` does not allocate. - if llsize_of_alloc(ccx, llty) == 0 { + let infcx = infer::normalizing_infer_ctxt(tcx, + &tcx.tables, + traits::ProjectionMode::Any); + let layout = t.layout(&infcx).unwrap(); + if layout.size(&tcx.data_layout).bytes() == 0 { + // `Box` does not allocate. tcx.types.i8 } else { - ccx.tcx().erase_regions(&t) + tcx.erase_regions(&t) } } - _ => ccx.tcx().erase_regions(&t) + _ => tcx.erase_regions(&t) } } @@ -154,7 +156,7 @@ pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DropGlueKind::Ty(t) }; let glue = get_drop_glue_core(ccx, g); - let glue_type = get_drop_glue_type(ccx, t); + let glue_type = get_drop_glue_type(ccx.tcx(), t); let ptr = if glue_type != t { PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to()) } else { @@ -231,7 +233,7 @@ impl<'tcx> DropGlueKind<'tcx> { fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKind<'tcx>) -> ValueRef { debug!("make drop glue for {:?}", g); - let g = g.map_ty(|t| get_drop_glue_type(ccx, t)); + let g = g.map_ty(|t| get_drop_glue_type(ccx.tcx(), t)); debug!("drop glue type {:?}", g); match ccx.drop_glues().borrow().get(&g) { Some(&glue) => return glue, diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index d0b47934bcf16..1061c1b2c7c19 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -135,7 +135,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { return; } let drop_fn = glue::get_drop_glue(bcx.ccx(), ty); - let drop_ty = glue::get_drop_glue_type(bcx.ccx(), ty); + let drop_ty = glue::get_drop_glue_type(bcx.tcx(), ty); let llvalue = if drop_ty != ty { bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) } else { From a66224d437ef4993d00056f72cc79f54fca1247e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 13:33:14 -0400 Subject: [PATCH 16/23] Make trans::collector only depend on SharedCrateContext. --- src/librustc_trans/base.rs | 6 ++-- src/librustc_trans/collector.rs | 50 ++++++++++++++++----------------- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/context.rs | 38 +++++++++++++++---------- src/librustc_trans/glue.rs | 2 +- 5 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 84a5bff6050b2..b1d79814f75a0 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1825,7 +1825,7 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, closure_env: closure::ClosureEnv) { ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); - if collector::collecting_debug_information(ccx) { + if collector::collecting_debug_information(ccx.shared()) { ccx.record_translation_item_as_generated(TransItem::Fn(instance)); } @@ -2739,7 +2739,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, krate.visit_all_items(&mut TransModVisitor { ccx: &ccx }); } - collector::print_collection_results(&ccx); + collector::print_collection_results(ccx.shared()); symbol_names_test::report_symbol_names(&ccx); } @@ -2935,7 +2935,7 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { }; let (items, reference_map) = time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(&ccx, collection_mode) + collector::collect_crate_translation_items(ccx.shared(), collection_mode) }); let strategy = if ccx.sess().opts.debugging_opts.incremental.is_some() { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index a469ef48deeac..935a48c09dd61 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -210,7 +210,7 @@ use syntax::{attr, errors}; use syntax::parse::token; use base::{custom_coerce_unsize_info, llvm_linkage_by_name}; -use context::CrateContext; +use context::SharedCrateContext; use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized}; use glue::{self, DropGlueKind}; use llvm; @@ -319,7 +319,7 @@ impl<'tcx> ReferenceMap<'tcx> { } } -pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode) -> (FnvHashSet>, ReferenceMap<'tcx>) { @@ -347,7 +347,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Find all non-generic items by walking the HIR. These items serve as roots to // start monomorphizing from. -fn collect_roots<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn collect_roots<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode) -> Vec> { debug!("Collecting roots"); @@ -368,7 +368,7 @@ fn collect_roots<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } // Collect all monomorphized translation items reachable from `starting_point` -fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>, +fn collect_items_rec<'a, 'tcx: 'a>(ccx: &SharedCrateContext<'a, 'tcx>, starting_point: TransItem<'tcx>, visited: &mut FnvHashSet>, recursion_depths: &mut DefIdMap, @@ -470,7 +470,7 @@ fn check_recursion_limit<'tcx>(tcx: &TyCtxt<'tcx>, } struct MirNeighborCollector<'a, 'tcx: 'a> { - ccx: &'a CrateContext<'a, 'tcx>, + ccx: &'a SharedCrateContext<'a, 'tcx>, mir: &'a mir::Mir<'tcx>, output: &'a mut Vec>, param_substs: &'tcx Substs<'tcx> @@ -590,7 +590,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // object shim or a closure that is handled differently), // we check if the callee is something that will actually // result in a translation item ... - if can_result_in_trans_item(self.ccx, callee_def_id) { + if can_result_in_trans_item(self.ccx.tcx(), callee_def_id) { // ... and create one if it does. let trans_item = create_fn_trans_item(self.ccx.tcx(), callee_def_id, @@ -603,21 +603,21 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_operand(operand); - fn can_result_in_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId) - -> bool { - if !match ccx.tcx().lookup_item_type(def_id).ty.sty { + fn can_result_in_trans_item<'tcx>(tcx: &TyCtxt<'tcx>, + def_id: DefId) + -> bool { + if !match tcx.lookup_item_type(def_id).ty.sty { ty::TyFnDef(def_id, _, _) => { // Some constructors also have type TyFnDef but they are // always instantiated inline and don't result in // translation item. Same for FFI functions. - match ccx.tcx().map.get_if_local(def_id) { + match tcx.map.get_if_local(def_id) { Some(hir_map::NodeVariant(_)) | Some(hir_map::NodeStructCtor(_)) | Some(hir_map::NodeForeignItem(_)) => false, Some(_) => true, None => { - ccx.sess().cstore.variant_kind(def_id).is_none() + tcx.sess.cstore.variant_kind(def_id).is_none() } } } @@ -627,7 +627,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { return false; } - can_have_local_instance(ccx.tcx(), def_id) + can_have_local_instance(tcx, def_id) } } } @@ -641,7 +641,7 @@ fn can_have_local_instance<'tcx>(tcx: &TyCtxt<'tcx>, def_id.is_local() || tcx.sess.cstore.is_item_mir_available(def_id) } -fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, dg: DropGlueKind<'tcx>, output: &mut Vec>) { let ty = match dg { @@ -697,7 +697,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs: self_type_substs, }.to_poly_trait_ref(); - let substs = match fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { + let substs = match fulfill_obligation(ccx, DUMMY_SP, trait_ref) { traits::VtableImpl(data) => data.substs, _ => bug!() }; @@ -776,7 +776,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -fn do_static_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn do_static_dispatch<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, fn_def_id: DefId, fn_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) @@ -819,7 +819,7 @@ fn do_static_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Given a trait-method and substitution information, find out the actual // implementation of the trait method. -fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, trait_method: &ty::Method, trait_id: DefId, callee_substs: &'tcx Substs<'tcx>, @@ -840,7 +840,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, callee_substs); let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id)); - let vtbl = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); + let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -908,7 +908,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, /// /// Finally, there is also the case of custom unsizing coercions, e.g. for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, source_ty: ty::Ty<'tcx>, target_ty: ty::Ty<'tcx>) -> (ty::Ty<'tcx>, ty::Ty<'tcx>) { @@ -933,7 +933,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, &ty::TyStruct(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); - let kind = custom_coerce_unsize_info(ccx.shared(), source_ty, target_ty); + let kind = custom_coerce_unsize_info(ccx, source_ty, target_ty); let coerce_index = match kind { CustomCoerceUnsized::Struct(i) => i @@ -983,7 +983,7 @@ fn create_fn_trans_item<'tcx>(tcx: &TyCtxt<'tcx>, /// Creates a `TransItem` for each method that is referenced by the vtable for /// the given trait/impl pair. -fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, trait_ty: ty::Ty<'tcx>, impl_ty: ty::Ty<'tcx>, output: &mut Vec>) { @@ -995,7 +995,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Walk all methods of the trait, including those of its supertraits for trait_ref in traits::supertraits(ccx.tcx(), poly_trait_ref) { - let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); + let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref); match vtable { traits::VtableImpl( traits::VtableImplData { @@ -1032,7 +1032,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, //=----------------------------------------------------------------------------- struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { - ccx: &'b CrateContext<'a, 'tcx>, + ccx: &'b SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode, output: &'b mut Vec>, enclosing_item: Option<&'tcx hir::Item>, @@ -1543,12 +1543,12 @@ pub enum TransItemState { NotPredictedButGenerated, } -pub fn collecting_debug_information(ccx: &CrateContext) -> bool { +pub fn collecting_debug_information(ccx: &SharedCrateContext) -> bool { return cfg!(debug_assertions) && ccx.sess().opts.debugging_opts.print_trans_items.is_some(); } -pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { +pub fn print_collection_results<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>) { use std::hash::{Hash, SipHasher, Hasher}; if !collecting_debug_information(ccx) { diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index b9af0bbe3d123..94b94803f1dd6 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1138,7 +1138,7 @@ pub fn trans_static(ccx: &CrateContext, attrs: &[ast::Attribute]) -> Result { - if collector::collecting_debug_information(ccx) { + if collector::collecting_debug_information(ccx.shared()) { ccx.record_translation_item_as_generated(TransItem::Static(id)); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1bb7e62725554..cdfd32a1d640b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -466,6 +466,28 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } + + pub fn get_mir(&self, def_id: DefId) -> Option> { + if def_id.is_local() { + let node_id = self.tcx.map.as_local_node_id(def_id).unwrap(); + self.mir_map.map.get(&node_id).map(CachedMir::Ref) + } else { + if let Some(mir) = self.mir_cache.borrow().get(&def_id).cloned() { + return Some(CachedMir::Owned(mir)); + } + + let mir = self.sess().cstore.maybe_get_item_mir(self.tcx, def_id); + let cached = mir.map(Rc::new); + if let Some(ref mir) = cached { + self.mir_cache.borrow_mut().insert(def_id, mir.clone()); + } + cached.map(CachedMir::Owned) + } + } + + pub fn translation_items(&self) -> &RefCell, TransItemState>> { + &self.translation_items + } } impl<'tcx> LocalCrateContext<'tcx> { @@ -835,21 +857,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn get_mir(&self, def_id: DefId) -> Option> { - if def_id.is_local() { - let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); - self.shared.mir_map.map.get(&node_id).map(CachedMir::Ref) - } else { - if let Some(mir) = self.shared.mir_cache.borrow().get(&def_id).cloned() { - return Some(CachedMir::Owned(mir)); - } - - let mir = self.sess().cstore.maybe_get_item_mir(self.tcx(), def_id); - let cached = mir.map(Rc::new); - if let Some(ref mir) = cached { - self.shared.mir_cache.borrow_mut().insert(def_id, mir.clone()); - } - cached.map(CachedMir::Owned) - } + self.shared.get_mir(def_id) } pub fn translation_items(&self) -> &RefCell, TransItemState>> { diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index e83580b95bcc4..898ac636c1d43 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -489,7 +489,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>) -> Block<'blk, 'tcx> { - if collector::collecting_debug_information(bcx.ccx()) { + if collector::collecting_debug_information(bcx.ccx().shared()) { bcx.ccx() .record_translation_item_as_generated(TransItem::DropGlue(g)); } From a95a50f15072faeff198093557bfa378b7ab41e1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 14:27:34 -0400 Subject: [PATCH 17/23] Restructure trans_crate() so that codegen unit partitioning happens before creating LocalCrateContexts. --- src/librustc_trans/back/write.rs | 3 ++- src/librustc_trans/base.rs | 43 +++++++++++++++++------------- src/librustc_trans/context.rs | 8 +++--- src/librustc_trans/partitioning.rs | 14 +++++++++- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 9f7a794185ad5..cf81777be261d 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -639,7 +639,8 @@ pub fn run_passes(sess: &Session, } // Sanity check - assert!(trans.modules.len() == sess.opts.cg.codegen_units); + assert!(trans.modules.len() == sess.opts.cg.codegen_units || + sess.opts.debugging_opts.incremental.is_some()); let tm = create_target_machine(sess); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index b1d79814f75a0..7ead14d19dcc1 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -82,7 +82,7 @@ use machine::{llalign_of_min, llsize_of, llsize_of_real}; use meth; use mir; use monomorphize::{self, Instance}; -use partitioning::{self, PartitioningStrategy, InstantiationMode}; +use partitioning::{self, PartitioningStrategy, InstantiationMode, CodegenUnit}; use symbol_names_test; use tvec; use type_::Type; @@ -2187,7 +2187,8 @@ pub fn update_linkage(ccx: &CrateContext, // `llval` is a translation of an item defined in a separate // compilation unit. This only makes sense if there are at least // two compilation units. - assert!(ccx.sess().opts.cg.codegen_units > 1); + assert!(ccx.sess().opts.cg.codegen_units > 1 || + ccx.sess().opts.debugging_opts.incremental.is_some()); // `llval` is a copy of something defined elsewhere, so use // `AvailableExternallyLinkage` to avoid duplicating code in the // output. @@ -2724,12 +2725,15 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, check_overflow, check_dropflag); - let codegen_units = tcx.sess.opts.cg.codegen_units; + let codegen_units = collect_and_partition_translation_items(&shared_ccx); + let codegen_unit_count = codegen_units.len(); + assert!(tcx.sess.opts.cg.codegen_units == codegen_unit_count || + tcx.sess.opts.debugging_opts.incremental.is_some()); + let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units); { let ccx = crate_context_list.get_ccx(0); - collect_translation_items(&ccx); // Translate all items. See `TransModVisitor` for // details on why we walk in this particular way. @@ -2819,7 +2823,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, } } - if codegen_units > 1 { + if codegen_unit_count > 1 { internalize_symbols(&crate_context_list, &reachable_symbols.iter().map(|x| &x[..]).collect()); } @@ -2911,10 +2915,11 @@ 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(); +fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) + -> Vec> { + let time_passes = scx.sess().time_passes(); - let collection_mode = match ccx.sess().opts.debugging_opts.print_trans_items { + let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items { Some(ref s) => { let mode_string = s.to_lowercase(); let mode_string = mode_string.trim(); @@ -2925,7 +2930,7 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { let message = format!("Unknown codegen-item collection mode '{}'. \ Falling back to 'lazy' mode.", mode_string); - ccx.sess().warn(&message); + scx.sess().warn(&message); } TransItemCollectionMode::Lazy @@ -2935,27 +2940,27 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { }; let (items, reference_map) = time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(ccx.shared(), collection_mode) + collector::collect_crate_translation_items(scx, collection_mode) }); - let strategy = if ccx.sess().opts.debugging_opts.incremental.is_some() { + let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() { PartitioningStrategy::PerModule } else { - PartitioningStrategy::FixedUnitCount(ccx.sess().opts.cg.codegen_units) + PartitioningStrategy::FixedUnitCount(scx.sess().opts.cg.codegen_units) }; let codegen_units = time(time_passes, "codegen unit partitioning", || { - partitioning::partition(ccx.tcx(), + partitioning::partition(scx.tcx(), items.iter().cloned(), strategy, &reference_map) }); - if ccx.sess().opts.debugging_opts.print_trans_items.is_some() { + if scx.sess().opts.debugging_opts.print_trans_items.is_some() { let mut item_to_cgus = HashMap::new(); - for cgu in codegen_units { - for (trans_item, linkage) in cgu.items { + for cgu in &codegen_units { + for (&trans_item, &linkage) in &cgu.items { item_to_cgus.entry(trans_item) .or_insert(Vec::new()) .push((cgu.name.clone(), linkage)); @@ -2965,7 +2970,7 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { let mut item_keys: Vec<_> = items .iter() .map(|i| { - let mut output = i.to_string(ccx.tcx()); + let mut output = i.to_string(scx.tcx()); output.push_str(" @@"); let mut empty = Vec::new(); let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); @@ -3004,10 +3009,12 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { println!("TRANS_ITEM {}", item); } - let mut ccx_map = ccx.translation_items().borrow_mut(); + let mut ccx_map = scx.translation_items().borrow_mut(); for cgi in items { ccx_map.insert(cgi, TransItemState::PredictedButNotGenerated); } } + + codegen_units } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index cdfd32a1d640b..edf728a337663 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -28,6 +28,7 @@ use mir::CachedMir; use monomorphize::Instance; use collector::{TransItem, TransItemState}; +use partitioning::CodegenUnit; use type_::{Type, TypeNames}; use rustc::ty::subst::{Substs, VecPerParamSpace}; use rustc::ty::{self, Ty, TyCtxt}; @@ -193,11 +194,12 @@ pub struct CrateContextList<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>, - local_count: usize) + codegen_units: Vec>) -> CrateContextList<'a, 'tcx> { CrateContextList { shared: shared_ccx, - local_ccxs: (0..local_count).map(|index| { + // FIXME: We don't actually use the codegen unit partitioning yet. + local_ccxs: codegen_units.iter().map(|cgu| { // Append ".rs" to crate name as LLVM module identifier. // // LLVM code generator emits a ".file filename" directive @@ -206,7 +208,7 @@ impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { // crashes if the module identifier is same as other symbols // such as a function name in the module. // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = format!("{}.{}.rs", shared_ccx.link_meta.crate_name, index); + let llmod_id = format!("{}.rs", cgu.name); LocalCrateContext::new(shared_ccx, &llmod_id[..]) }).collect() } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 250292ee684de..6e50292a91a58 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -182,7 +182,19 @@ pub fn partition<'tcx, I>(tcx: &TyCtxt<'tcx>, // easily determine which declarations need to be placed within each one. let post_declarations = place_declarations(post_inlining, reference_map); - post_declarations.0 + let mut final_partitioning = post_declarations.0; + + if final_partitioning.len() == 0 { + // Some crates don't contain anything that will result in a translation + // item. We still want to have at least one (empty) codegen unit in that + // case. + final_partitioning.push(CodegenUnit { + name: token::intern_and_get_ident(&format!("{}.0", tcx.crate_name)[..]), + items: FnvHashMap() + }); + } + + final_partitioning } struct PreInliningPartitioning<'tcx> { From c62fa76a979435542cf446e15b3b1cdfc96f5850 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 15:21:17 -0400 Subject: [PATCH 18/23] trans: Make partitioning available in LocalCrateContext. --- src/librustc_trans/context.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index edf728a337663..a61c7bfc25ea4 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -96,6 +96,7 @@ pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, tn: TypeNames, // FIXME: This seems to be largely unused. + codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, drop_glues: RefCell, ValueRef>>, @@ -198,18 +199,8 @@ impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { -> CrateContextList<'a, 'tcx> { CrateContextList { shared: shared_ccx, - // FIXME: We don't actually use the codegen unit partitioning yet. - local_ccxs: codegen_units.iter().map(|cgu| { - // Append ".rs" to crate name as LLVM module identifier. - // - // LLVM code generator emits a ".file filename" directive - // for ELF backends. Value of the "filename" is set as the - // LLVM module identifier. Due to a LLVM MC bug[1], LLVM - // crashes if the module identifier is same as other symbols - // such as a function name in the module. - // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = format!("{}.rs", cgu.name); - LocalCrateContext::new(shared_ccx, &llmod_id[..]) + local_ccxs: codegen_units.into_iter().map(|codegen_unit| { + LocalCrateContext::new(shared_ccx, codegen_unit) }).collect() } } @@ -494,10 +485,21 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'tcx> LocalCrateContext<'tcx> { fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, - name: &str) + codegen_unit: CodegenUnit<'tcx>) -> LocalCrateContext<'tcx> { unsafe { - let (llcx, llmod) = create_context_and_module(&shared.tcx.sess, name); + // Append ".rs" to LLVM module identifier. + // + // LLVM code generator emits a ".file filename" directive + // for ELF backends. Value of the "filename" is set as the + // LLVM module identifier. Due to a LLVM MC bug[1], LLVM + // crashes if the module identifier is same as other symbols + // such as a function name in the module. + // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 + let llmod_id = format!("{}.rs", codegen_unit.name); + + let (llcx, llmod) = create_context_and_module(&shared.tcx.sess, + &llmod_id[..]); let dbg_cx = if shared.tcx.sess.opts.debuginfo != NoDebugInfo { Some(debuginfo::CrateDebugContext::new(llmod)) @@ -508,6 +510,7 @@ impl<'tcx> LocalCrateContext<'tcx> { let local_ccx = LocalCrateContext { llmod: llmod, llcx: llcx, + codegen_unit: codegen_unit, tn: TypeNames::new(), needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()), fn_pointer_shims: RefCell::new(FnvHashMap()), @@ -664,6 +667,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().llcx } + pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> { + &self.local().codegen_unit + } + pub fn td(&self) -> llvm::TargetDataRef { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } From 29e397707a1d394ef9531efb5a11f9e13d20efc2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 16:53:59 -0400 Subject: [PATCH 19/23] trans: Add some explanatory comments to trans::context types. --- src/librustc_trans/context.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a61c7bfc25ea4..0e6e9934eaee8 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -187,6 +187,9 @@ impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { } } +/// This list owns a number of LocalCrateContexts and binds them to their common +/// SharedCrateContext. This type just exists as a convenience, something to +/// pass around all LocalCrateContexts with and get an iterator over them. pub struct CrateContextList<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: Vec>, @@ -226,6 +229,9 @@ impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { } } +/// A CrateContext value binds together one LocalCrateContext with the +/// SharedCrateContext. It exists as a convenience wrapper, so we don't have to +/// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans. pub struct CrateContext<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: &'a [LocalCrateContext<'tcx>], From a90ce0a3c11a3a86e9906a630988542d0a8e7983 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 17:00:59 -0400 Subject: [PATCH 20/23] Make FixedCount partitioning handle case where codegen units have to be added. --- src/librustc_trans/partitioning.rs | 35 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 6e50292a91a58..7b21b61209759 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -182,19 +182,7 @@ pub fn partition<'tcx, I>(tcx: &TyCtxt<'tcx>, // easily determine which declarations need to be placed within each one. let post_declarations = place_declarations(post_inlining, reference_map); - let mut final_partitioning = post_declarations.0; - - if final_partitioning.len() == 0 { - // Some crates don't contain anything that will result in a translation - // item. We still want to have at least one (empty) codegen unit in that - // case. - final_partitioning.push(CodegenUnit { - name: token::intern_and_get_ident(&format!("{}.0", tcx.crate_name)[..]), - items: FnvHashMap() - }); - } - - final_partitioning + post_declarations.0 } struct PreInliningPartitioning<'tcx> { @@ -268,10 +256,6 @@ fn place_root_translation_items<'tcx, I>(tcx: &TyCtxt<'tcx>, fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>, target_cgu_count: usize, crate_name: &str) { - if target_cgu_count >= initial_partitioning.codegen_units.len() { - return; - } - assert!(target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; @@ -290,7 +274,22 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< } for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.name = token::intern_and_get_ident(&format!("{}.{}", crate_name, index)[..]); + cgu.name = numbered_codegen_unit_name(crate_name, index); + } + + // If the initial partitioning contained less than target_cgu_count to begin + // with, we won't have enough codegen units here, so add a empty units until + // we reach the target count + while codegen_units.len() < target_cgu_count { + let index = codegen_units.len(); + codegen_units.push(CodegenUnit { + name: numbered_codegen_unit_name(crate_name, index), + items: FnvHashMap() + }); + } + + fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { + token::intern_and_get_ident(&format!("{}.{}", crate_name, index)[..]) } } From 244a766eac32615b72041993e033e7e6376ab2e1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 17:07:36 -0400 Subject: [PATCH 21/23] trans: Consistently name SharedCrateContext instances 'scx' --- src/librustc_trans/base.rs | 20 +-- src/librustc_trans/collector.rs | 210 ++++++++++++++++---------------- src/librustc_trans/common.rs | 8 +- 3 files changed, 119 insertions(+), 119 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 7ead14d19dcc1..ace45f6dfe76d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -665,7 +665,7 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &SharedCrateContext<'ccx, 'tcx>, +pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> CustomCoerceUnsized { @@ -675,13 +675,13 @@ pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &SharedCrateContext<'ccx, 'tcx subst::VecPerParamSpace::empty()); let trait_ref = ty::Binder(ty::TraitRef { - def_id: ccx.tcx().lang_items.coerce_unsized_trait().unwrap(), - substs: ccx.tcx().mk_substs(trait_substs) + def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), + substs: scx.tcx().mk_substs(trait_substs) }); - match fulfill_obligation(ccx, DUMMY_SP, trait_ref) { + match fulfill_obligation(scx, DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - ccx.tcx().custom_coerce_unsized_kind(impl_def_id) + scx.tcx().custom_coerce_unsized_kind(impl_def_id) } vtable => { bug!("invalid CoerceUnsized vtable: {:?}", vtable); @@ -2661,10 +2661,10 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn filter_reachable_ids(ccx: &SharedCrateContext) -> NodeSet { - ccx.reachable().iter().map(|x| *x).filter(|id| { +pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet { + scx.reachable().iter().map(|x| *x).filter(|id| { // First, only worry about nodes which have a symbol name - ccx.item_symbols().borrow().contains_key(id) + scx.item_symbols().borrow().contains_key(id) }).filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two @@ -2679,9 +2679,9 @@ pub fn filter_reachable_ids(ccx: &SharedCrateContext) -> NodeSet { // // As a result, if this id is an FFI item (foreign item) then we only // let it through if it's included statically. - match ccx.tcx().map.get(id) { + match scx.tcx().map.get(id) { hir_map::NodeForeignItem(..) => { - ccx.sess().cstore.is_statically_included_foreign_item(id) + scx.sess().cstore.is_statically_included_foreign_item(id) } _ => true, } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 935a48c09dd61..02c79f730b615 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -319,14 +319,14 @@ impl<'tcx> ReferenceMap<'tcx> { } } -pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode) -> (FnvHashSet>, ReferenceMap<'tcx>) { // We are not tracking dependencies of this pass as it has to be re-executed // every time no matter what. - ccx.tcx().dep_graph.with_ignore(|| { - let roots = collect_roots(ccx, mode); + scx.tcx().dep_graph.with_ignore(|| { + let roots = collect_roots(scx, mode); debug!("Building translation item graph, beginning at roots"); let mut visited = FnvHashSet(); @@ -334,7 +334,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &SharedCrateContext<'a, 't let mut reference_map = ReferenceMap::new(); for root in roots { - collect_items_rec(ccx, + collect_items_rec(scx, root, &mut visited, &mut recursion_depths, @@ -347,7 +347,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &SharedCrateContext<'a, 't // Find all non-generic items by walking the HIR. These items serve as roots to // start monomorphizing from. -fn collect_roots<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode) -> Vec> { debug!("Collecting roots"); @@ -355,20 +355,20 @@ fn collect_roots<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, { let mut visitor = RootCollector { - ccx: ccx, + scx: scx, mode: mode, output: &mut roots, enclosing_item: None, }; - ccx.tcx().map.krate().visit_all_items(&mut visitor); + scx.tcx().map.krate().visit_all_items(&mut visitor); } roots } // Collect all monomorphized translation items reachable from `starting_point` -fn collect_items_rec<'a, 'tcx: 'a>(ccx: &SharedCrateContext<'a, 'tcx>, +fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, starting_point: TransItem<'tcx>, visited: &mut FnvHashSet>, recursion_depths: &mut DefIdMap, @@ -377,36 +377,36 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &SharedCrateContext<'a, 'tcx>, // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.to_string(ccx.tcx())); + debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx())); let mut neighbors = Vec::new(); let recursion_depth_reset; match starting_point { TransItem::DropGlue(t) => { - find_drop_glue_neighbors(ccx, t, &mut neighbors); + find_drop_glue_neighbors(scx, t, &mut neighbors); recursion_depth_reset = None; } TransItem::Static(node_id) => { - let def_id = ccx.tcx().map.local_def_id(node_id); - let ty = ccx.tcx().lookup_item_type(def_id).ty; - let ty = glue::get_drop_glue_type(ccx.tcx(), ty); + let def_id = scx.tcx().map.local_def_id(node_id); + let ty = scx.tcx().lookup_item_type(def_id).ty; + let ty = glue::get_drop_glue_type(scx.tcx(), ty); neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); recursion_depth_reset = None; } TransItem::Fn(instance) => { // Keep track of the monomorphization recursion depth - recursion_depth_reset = Some(check_recursion_limit(ccx.tcx(), + recursion_depth_reset = Some(check_recursion_limit(scx.tcx(), instance, recursion_depths)); // Scan the MIR in order to find function calls, closures, and // drop-glue - let mir = errors::expect(ccx.sess().diagnostic(), ccx.get_mir(instance.def), + let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(instance.def), || format!("Could not find MIR for function: {}", instance)); let mut visitor = MirNeighborCollector { - ccx: ccx, + scx: scx, mir: &mir, output: &mut neighbors, param_substs: instance.substs @@ -416,17 +416,17 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &SharedCrateContext<'a, 'tcx>, } } - record_references(ccx.tcx(), starting_point, &neighbors[..], reference_map); + record_references(scx.tcx(), starting_point, &neighbors[..], reference_map); for neighbour in neighbors { - collect_items_rec(ccx, neighbour, visited, recursion_depths, reference_map); + collect_items_rec(scx, neighbour, visited, recursion_depths, reference_map); } if let Some((def_id, depth)) = recursion_depth_reset { recursion_depths.insert(def_id, depth); } - debug!("END collect_items_rec({})", starting_point.to_string(ccx.tcx())); + debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx())); } fn record_references<'tcx>(tcx: &TyCtxt<'tcx>, @@ -470,7 +470,7 @@ fn check_recursion_limit<'tcx>(tcx: &TyCtxt<'tcx>, } struct MirNeighborCollector<'a, 'tcx: 'a> { - ccx: &'a SharedCrateContext<'a, 'tcx>, + scx: &'a SharedCrateContext<'a, 'tcx>, mir: &'a mir::Mir<'tcx>, output: &'a mut Vec>, param_substs: &'tcx Substs<'tcx> @@ -484,8 +484,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { match *rvalue { mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id, ref substs), _) => { - assert!(can_have_local_instance(self.ccx.tcx(), def_id)); - let trans_item = create_fn_trans_item(self.ccx.tcx(), + assert!(can_have_local_instance(self.scx.tcx(), def_id)); + let trans_item = create_fn_trans_item(self.scx.tcx(), def_id, substs.func_substs, self.param_substs); @@ -495,21 +495,21 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = monomorphize::apply_param_substs(self.ccx.tcx(), + let target_ty = monomorphize::apply_param_substs(self.scx.tcx(), self.param_substs, &target_ty); - let source_ty = self.mir.operand_ty(self.ccx.tcx(), operand); - let source_ty = monomorphize::apply_param_substs(self.ccx.tcx(), + let source_ty = self.mir.operand_ty(self.scx.tcx(), operand); + let source_ty = monomorphize::apply_param_substs(self.scx.tcx(), self.param_substs, &source_ty); - let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.ccx, + let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. if target_ty.is_trait() && !source_ty.is_trait() { - create_trans_items_for_vtable_methods(self.ccx, + create_trans_items_for_vtable_methods(self.scx, target_ty, source_ty, self.output); @@ -517,15 +517,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::Rvalue::Box(_) => { let exchange_malloc_fn_def_id = - self.ccx + self.scx .tcx() .lang_items .require(ExchangeMallocFnLangItem) - .unwrap_or_else(|e| self.ccx.sess().fatal(&e)); + .unwrap_or_else(|e| self.scx.sess().fatal(&e)); - assert!(can_have_local_instance(self.ccx.tcx(), exchange_malloc_fn_def_id)); + assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id)); let exchange_malloc_fn_trans_item = - create_fn_trans_item(self.ccx.tcx(), + create_fn_trans_item(self.scx.tcx(), exchange_malloc_fn_def_id, &Substs::empty(), self.param_substs); @@ -544,14 +544,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting lvalue {:?}", *lvalue); if let mir_visit::LvalueContext::Drop = context { - let ty = self.mir.lvalue_ty(self.ccx.tcx(), lvalue) - .to_ty(self.ccx.tcx()); + let ty = self.mir.lvalue_ty(self.scx.tcx(), lvalue) + .to_ty(self.scx.tcx()); - let ty = monomorphize::apply_param_substs(self.ccx.tcx(), + let ty = monomorphize::apply_param_substs(self.scx.tcx(), self.param_substs, &ty); - let ty = self.ccx.tcx().erase_regions(&ty); - let ty = glue::get_drop_glue_type(self.ccx.tcx(), ty); + let ty = self.scx.tcx().erase_regions(&ty); + let ty = glue::get_drop_glue_type(self.scx.tcx(), ty); self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } @@ -579,7 +579,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // // Calling do_static_dispatch() here will map the def_id of // `std::cmp::partial_cmp` to the def_id of `i32::partial_cmp` - let dispatched = do_static_dispatch(self.ccx, + let dispatched = do_static_dispatch(self.scx, callee_def_id, callee_substs, self.param_substs); @@ -590,9 +590,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // object shim or a closure that is handled differently), // we check if the callee is something that will actually // result in a translation item ... - if can_result_in_trans_item(self.ccx.tcx(), callee_def_id) { + if can_result_in_trans_item(self.scx.tcx(), callee_def_id) { // ... and create one if it does. - let trans_item = create_fn_trans_item(self.ccx.tcx(), + let trans_item = create_fn_trans_item(self.scx.tcx(), callee_def_id, callee_substs, self.param_substs); @@ -641,7 +641,7 @@ fn can_have_local_instance<'tcx>(tcx: &TyCtxt<'tcx>, def_id.is_local() || tcx.sess.cstore.is_item_mir_available(def_id) } -fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, dg: DropGlueKind<'tcx>, output: &mut Vec>) { let ty = match dg { @@ -653,19 +653,19 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, } }; - debug!("find_drop_glue_neighbors: {}", type_to_string(ccx.tcx(), ty)); + debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty)); // Make sure the exchange_free_fn() lang-item gets translated if // there is a boxed value. if let ty::TyBox(_) = ty.sty { - let exchange_free_fn_def_id = ccx.tcx() + let exchange_free_fn_def_id = scx.tcx() .lang_items .require(ExchangeFreeFnLangItem) - .unwrap_or_else(|e| ccx.sess().fatal(&e)); + .unwrap_or_else(|e| scx.sess().fatal(&e)); - assert!(can_have_local_instance(ccx.tcx(), exchange_free_fn_def_id)); + assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id)); let exchange_free_fn_trans_item = - create_fn_trans_item(ccx.tcx(), + create_fn_trans_item(scx.tcx(), exchange_free_fn_def_id, &Substs::empty(), &Substs::empty()); @@ -684,12 +684,12 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, if let Some(destructor_did) = destructor_did { use rustc::ty::ToPolyTraitRef; - let drop_trait_def_id = ccx.tcx() + let drop_trait_def_id = scx.tcx() .lang_items .drop_trait() .unwrap(); - let self_type_substs = ccx.tcx().mk_substs( + let self_type_substs = scx.tcx().mk_substs( Substs::empty().with_self_ty(ty)); let trait_ref = ty::TraitRef { @@ -697,13 +697,13 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, substs: self_type_substs, }.to_poly_trait_ref(); - let substs = match fulfill_obligation(ccx, DUMMY_SP, trait_ref) { + let substs = match fulfill_obligation(scx, DUMMY_SP, trait_ref) { traits::VtableImpl(data) => data.substs, _ => bug!() }; - if can_have_local_instance(ccx.tcx(), destructor_did) { - let trans_item = create_fn_trans_item(ccx.tcx(), + if can_have_local_instance(scx.tcx(), destructor_did) { + let trans_item = create_fn_trans_item(scx.tcx(), destructor_did, substs, &Substs::empty()); @@ -734,35 +734,35 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, ty::TyStruct(ref adt_def, substs) | ty::TyEnum(ref adt_def, substs) => { for field in adt_def.all_fields() { - let field_type = monomorphize::apply_param_substs(ccx.tcx(), + let field_type = monomorphize::apply_param_substs(scx.tcx(), substs, &field.unsubst_ty()); - let field_type = glue::get_drop_glue_type(ccx.tcx(), field_type); + let field_type = glue::get_drop_glue_type(scx.tcx(), field_type); - if glue::type_needs_drop(ccx.tcx(), field_type) { + if glue::type_needs_drop(scx.tcx(), field_type) { output.push(TransItem::DropGlue(DropGlueKind::Ty(field_type))); } } } ty::TyClosure(_, ref substs) => { for upvar_ty in &substs.upvar_tys { - let upvar_ty = glue::get_drop_glue_type(ccx.tcx(), upvar_ty); - if glue::type_needs_drop(ccx.tcx(), upvar_ty) { + let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty); + if glue::type_needs_drop(scx.tcx(), upvar_ty) { output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty))); } } } ty::TyBox(inner_type) | ty::TyArray(inner_type, _) => { - let inner_type = glue::get_drop_glue_type(ccx.tcx(), inner_type); - if glue::type_needs_drop(ccx.tcx(), inner_type) { + let inner_type = glue::get_drop_glue_type(scx.tcx(), inner_type); + if glue::type_needs_drop(scx.tcx(), inner_type) { output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type))); } } ty::TyTuple(ref args) => { for arg in args { - let arg = glue::get_drop_glue_type(ccx.tcx(), arg); - if glue::type_needs_drop(ccx.tcx(), arg) { + let arg = glue::get_drop_glue_type(scx.tcx(), arg); + if glue::type_needs_drop(scx.tcx(), arg) { output.push(TransItem::DropGlue(DropGlueKind::Ty(arg))); } } @@ -776,25 +776,25 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, } } -fn do_static_dispatch<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, fn_def_id: DefId, fn_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) -> Option<(DefId, &'tcx Substs<'tcx>)> { debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})", - def_id_to_string(ccx.tcx(), fn_def_id), + def_id_to_string(scx.tcx(), fn_def_id), fn_substs, param_substs); - let is_trait_method = ccx.tcx().trait_of_item(fn_def_id).is_some(); + let is_trait_method = scx.tcx().trait_of_item(fn_def_id).is_some(); if is_trait_method { - match ccx.tcx().impl_or_trait_item(fn_def_id) { + match scx.tcx().impl_or_trait_item(fn_def_id) { ty::MethodTraitItem(ref method) => { match method.container { ty::TraitContainer(trait_def_id) => { debug!(" => trait method, attempting to find impl"); - do_static_trait_method_dispatch(ccx, + do_static_trait_method_dispatch(scx, method, trait_def_id, fn_substs, @@ -819,19 +819,19 @@ fn do_static_dispatch<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, // Given a trait-method and substitution information, find out the actual // implementation of the trait method. -fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, trait_method: &ty::Method, trait_id: DefId, callee_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) -> Option<(DefId, &'tcx Substs<'tcx>)> { - let tcx = ccx.tcx(); + let tcx = scx.tcx(); debug!("do_static_trait_method_dispatch(trait_method={}, \ trait_id={}, \ callee_substs={:?}, \ param_substs={:?}", - def_id_to_string(ccx.tcx(), trait_method.def_id), - def_id_to_string(ccx.tcx(), trait_id), + def_id_to_string(scx.tcx(), trait_method.def_id), + def_id_to_string(scx.tcx(), trait_id), callee_substs, param_substs); @@ -840,7 +840,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, callee_substs); let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id)); - let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); + let vtbl = fulfill_obligation(scx, DUMMY_SP, trait_ref); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -908,7 +908,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, /// /// Finally, there is also the case of custom unsizing coercions, e.g. for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, source_ty: ty::Ty<'tcx>, target_ty: ty::Ty<'tcx>) -> (ty::Ty<'tcx>, ty::Ty<'tcx>) { @@ -922,10 +922,10 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { let (inner_source, inner_target) = (a, b); - if !type_is_sized(ccx.tcx(), inner_source) { + if !type_is_sized(scx.tcx(), inner_source) { (inner_source, inner_target) } else { - ccx.tcx().struct_lockstep_tails(inner_source, inner_target) + scx.tcx().struct_lockstep_tails(inner_source, inner_target) } } @@ -933,7 +933,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, &ty::TyStruct(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); - let kind = custom_coerce_unsize_info(ccx, source_ty, target_ty); + let kind = custom_coerce_unsize_info(scx, source_ty, target_ty); let coerce_index = match kind { CustomCoerceUnsized::Struct(i) => i @@ -945,10 +945,10 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, assert!(coerce_index < source_fields.len() && source_fields.len() == target_fields.len()); - find_vtable_types_for_unsizing(ccx, - source_fields[coerce_index].ty(ccx.tcx(), + find_vtable_types_for_unsizing(scx, + source_fields[coerce_index].ty(scx.tcx(), source_substs), - target_fields[coerce_index].ty(ccx.tcx(), + target_fields[coerce_index].ty(scx.tcx(), target_substs)) } _ => bug!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", @@ -983,33 +983,33 @@ fn create_fn_trans_item<'tcx>(tcx: &TyCtxt<'tcx>, /// Creates a `TransItem` for each method that is referenced by the vtable for /// the given trait/impl pair. -fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, trait_ty: ty::Ty<'tcx>, impl_ty: ty::Ty<'tcx>, output: &mut Vec>) { assert!(!trait_ty.needs_subst() && !impl_ty.needs_subst()); if let ty::TyTrait(ref trait_ty) = trait_ty.sty { - let poly_trait_ref = trait_ty.principal_trait_ref_with_self_ty(ccx.tcx(), + let poly_trait_ref = trait_ty.principal_trait_ref_with_self_ty(scx.tcx(), impl_ty); // Walk all methods of the trait, including those of its supertraits - for trait_ref in traits::supertraits(ccx.tcx(), poly_trait_ref) { - let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref); + for trait_ref in traits::supertraits(scx.tcx(), poly_trait_ref) { + let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref); match vtable { traits::VtableImpl( traits::VtableImplData { impl_def_id, substs, nested: _ }) => { - let items = meth::get_vtable_methods(ccx.tcx(), impl_def_id, substs) + let items = meth::get_vtable_methods(scx.tcx(), impl_def_id, substs) .into_iter() // filter out None values .filter_map(|opt_impl_method| opt_impl_method) // create translation items .filter_map(|impl_method| { - if can_have_local_instance(ccx.tcx(), impl_method.method.def_id) { - Some(create_fn_trans_item(ccx.tcx(), + if can_have_local_instance(scx.tcx(), impl_method.method.def_id) { + Some(create_fn_trans_item(scx.tcx(), impl_method.method.def_id, &impl_method.substs, &Substs::empty())) @@ -1032,7 +1032,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &SharedCrateContext<'a, //=----------------------------------------------------------------------------- struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { - ccx: &'b SharedCrateContext<'a, 'tcx>, + scx: &'b SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode, output: &'b mut Vec>, enclosing_item: Option<&'tcx hir::Item>, @@ -1057,7 +1057,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemImpl(..) => { if self.mode == TransItemCollectionMode::Eager { - create_trans_items_for_default_impls(self.ccx.tcx(), + create_trans_items_for_default_impls(self.scx.tcx(), item, self.output); } @@ -1067,35 +1067,35 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemStruct(_, ref generics) => { if !generics.is_parameterized() { let ty = { - let tables = self.ccx.tcx().tables.borrow(); + let tables = self.scx.tcx().tables.borrow(); tables.node_types[&item.id] }; if self.mode == TransItemCollectionMode::Eager { debug!("RootCollector: ADT drop-glue for {}", - def_id_to_string(self.ccx.tcx(), - self.ccx.tcx().map.local_def_id(item.id))); + def_id_to_string(self.scx.tcx(), + self.scx.tcx().map.local_def_id(item.id))); - let ty = glue::get_drop_glue_type(self.ccx.tcx(), ty); + let ty = glue::get_drop_glue_type(self.scx.tcx(), ty); self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } } } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", - def_id_to_string(self.ccx.tcx(), - self.ccx.tcx().map.local_def_id(item.id))); + def_id_to_string(self.scx.tcx(), + self.scx.tcx().map.local_def_id(item.id))); self.output.push(TransItem::Static(item.id)); } hir::ItemFn(_, _, constness, _, ref generics, _) => { if !generics.is_type_parameterized() && constness == hir::Constness::NotConst { - let def_id = self.ccx.tcx().map.local_def_id(item.id); + let def_id = self.scx.tcx().map.local_def_id(item.id); debug!("RootCollector: ItemFn({})", - def_id_to_string(self.ccx.tcx(), def_id)); + def_id_to_string(self.scx.tcx(), def_id)); - let instance = Instance::mono(self.ccx.tcx(), def_id); + let instance = Instance::mono(self.scx.tcx(), def_id); self.output.push(TransItem::Fn(instance)); } } @@ -1112,7 +1112,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { constness, .. }, _) if constness == hir::Constness::NotConst => { - let hir_map = &self.ccx.tcx().map; + let hir_map = &self.scx.tcx().map; let parent_node_id = hir_map.get_parent_node(ii.id); let is_impl_generic = match hir_map.expect_item(parent_node_id) { &hir::Item { @@ -1127,12 +1127,12 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { }; if !generics.is_type_parameterized() && !is_impl_generic { - let def_id = self.ccx.tcx().map.local_def_id(ii.id); + let def_id = self.scx.tcx().map.local_def_id(ii.id); debug!("RootCollector: MethodImplItem({})", - def_id_to_string(self.ccx.tcx(), def_id)); + def_id_to_string(self.scx.tcx(), def_id)); - let instance = Instance::mono(self.ccx.tcx(), def_id); + let instance = Instance::mono(self.scx.tcx(), def_id); self.output.push(TransItem::Fn(instance)); } } @@ -1543,15 +1543,15 @@ pub enum TransItemState { NotPredictedButGenerated, } -pub fn collecting_debug_information(ccx: &SharedCrateContext) -> bool { +pub fn collecting_debug_information(scx: &SharedCrateContext) -> bool { return cfg!(debug_assertions) && - ccx.sess().opts.debugging_opts.print_trans_items.is_some(); + scx.sess().opts.debugging_opts.print_trans_items.is_some(); } -pub fn print_collection_results<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>) { +pub fn print_collection_results<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) { use std::hash::{Hash, SipHasher, Hasher}; - if !collecting_debug_information(ccx) { + if !collecting_debug_information(scx) { return; } @@ -1561,14 +1561,14 @@ pub fn print_collection_results<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>) { s.finish() } - let trans_items = ccx.translation_items().borrow(); + let trans_items = scx.translation_items().borrow(); { // Check for duplicate item keys let mut item_keys = FnvHashMap(); for (item, item_state) in trans_items.iter() { - let k = item.to_string(ccx.tcx()); + let k = item.to_string(scx.tcx()); if item_keys.contains_key(&k) { let prev: (TransItem, TransItemState) = item_keys[&k]; @@ -1596,7 +1596,7 @@ pub fn print_collection_results<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>) { let mut generated = FnvHashSet(); for (item, item_state) in trans_items.iter() { - let item_key = item.to_string(ccx.tcx()); + let item_key = item.to_string(scx.tcx()); match *item_state { TransItemState::PredictedAndGenerated => { diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index a70af8db49213..538b23763de27 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -1052,17 +1052,17 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) -> /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should /// guarantee to us that all nested obligations *could be* resolved if we wanted to. -pub fn fulfill_obligation<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, +pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, span: Span, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> { - let tcx = ccx.tcx(); + let tcx = scx.tcx(); // Remove any references to regions; this helps improve caching. let trait_ref = tcx.erase_regions(&trait_ref); - ccx.trait_cache().memoize(trait_ref, || { + scx.trait_cache().memoize(trait_ref, || { debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}", trait_ref, trait_ref.def_id()); @@ -1090,7 +1090,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>, debug!("Encountered ambiguity selecting `{:?}` during trans, \ presuming due to overflow", trait_ref); - ccx.sess().span_fatal( + tcx.sess.span_fatal( span, "reached the recursion limit during monomorphization \ (selection ambiguity)"); From b37d7a4bfb5566ea325bdb6be9900d63bd9d2cf0 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 17:09:18 -0400 Subject: [PATCH 22/23] trans::context: Remove some tcx::tls wackiness --- src/librustc_trans/context.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 0e6e9934eaee8..f785579144401 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -180,10 +180,7 @@ 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() - }) + key.to_poly_trait_predicate().dep_node() } } From a9779df1886e18923f40cf0bb67ab72d4e4942df Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 May 2016 22:42:14 -0700 Subject: [PATCH 23/23] Implement RFC 1542 cc #33417 --- src/libcore/convert.rs | 57 ++++- src/libcore/num/mod.rs | 95 +++++++- src/libcoretest/lib.rs | 1 + src/libcoretest/num/mod.rs | 447 +++++++++++++++++++++++++------------ src/libstd/error.rs | 7 + src/libstd/lib.rs | 1 + src/libstd/num/mod.rs | 2 +- 7 files changed, 451 insertions(+), 159 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 2d999868f71ec..48421abc7bbdf 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -20,18 +20,19 @@ //! - Impl the `As*` traits for reference-to-reference conversions //! - Impl the `Into` trait when you want to consume the value in the conversion //! - The `From` trait is the most flexible, useful for value _and_ reference conversions +//! - The `TryFrom` and `TryInto` traits behave like `From` and `Into`, but allow for the +//! conversion to fail //! -//! As a library author, you should prefer implementing `From` rather than -//! `Into`, as `From` provides greater flexibility and offers an equivalent `Into` -//! implementation for free, thanks to a blanket implementation in the standard library. -//! -//! **Note: these traits must not fail**. If the conversion can fail, you must use a dedicated -//! method which returns an `Option` or a `Result`. +//! As a library author, you should prefer implementing `From` or `TryFrom` rather than +//! `Into` or `TryInto`, as `From` and `TryFrom` provide greater flexibility and offer +//! equivalent `Into` or `TryInto` implementations for free, thanks to a blanket implementation +//! in the standard library. //! //! # Generic impl //! //! - `AsRef` and `AsMut` auto-dereference if the inner type is a reference //! - `From for T` implies `Into for U` +//! - `TryFrom for T` implies `TryInto for U` //! - `From` and `Into` are reflexive, which means that all types can `into()` //! themselves and `from()` themselves //! @@ -40,6 +41,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use marker::Sized; +use result::Result; /// A cheap, reference-to-reference conversion. /// @@ -98,8 +100,8 @@ pub trait AsMut { /// A conversion that consumes `self`, which may or may not be expensive. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an `Option` or a `Result`. +/// **Note: this trait must not fail**. If the conversion can fail, use `TryInto` or a dedicated +/// method which returns an `Option` or a `Result`. /// /// Library authors should not directly implement this trait, but should prefer implementing /// the `From` trait, which offers greater flexibility and provides an equivalent `Into` @@ -133,8 +135,8 @@ pub trait Into: Sized { /// Construct `Self` via a conversion. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an `Option` or a `Result`. +/// **Note: this trait must not fail**. If the conversion can fail, use `TryFrom` or a dedicated +/// method which returns an `Option` or a `Result`. /// /// # Examples /// @@ -158,6 +160,30 @@ pub trait From: Sized { fn from(T) -> Self; } +/// An attempted conversion that consumes `self`, which may or may not be expensive. +/// +/// Library authors should not directly implement this trait, but should prefer implementing +/// the `TryFrom` trait, which offers greater flexibility and provides an equivalent `TryInto` +/// implementation for free, thanks to a blanket implementation in the standard library. +#[unstable(feature = "try_from", issue = "33417")] +pub trait TryInto: Sized { + /// The type returned in the event of a conversion error. + type Err; + + /// Performs the conversion. + fn try_into(self) -> Result; +} + +/// Attempt to construct `Self` via a conversion. +#[unstable(feature = "try_from", issue = "33417")] +pub trait TryFrom: Sized { + /// The type returned in the event of a conversion error. + type Err; + + /// Performs the conversion. + fn try_from(T) -> Result; +} + //////////////////////////////////////////////////////////////////////////////// // GENERIC IMPLS //////////////////////////////////////////////////////////////////////////////// @@ -216,6 +242,17 @@ impl From for T { fn from(t: T) -> T { t } } + +// TryFrom implies TryInto +#[unstable(feature = "try_from", issue = "33417")] +impl TryInto for T where U: TryFrom { + type Err = U::Err; + + fn try_into(self) -> Result { + U::try_from(self) + } +} + //////////////////////////////////////////////////////////////////////////////// // CONCRETE IMPLS //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 589ac90b308ad..e048c963d1556 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,7 +15,7 @@ use char::CharExt; use cmp::PartialOrd; -use convert::From; +use convert::{From, TryFrom}; use fmt; use intrinsics; use marker::{Copy, Sized}; @@ -2341,9 +2341,101 @@ macro_rules! from_str_radix_int_impl { } from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 } +/// The error type returned when a checked integral type conversion fails. +#[unstable(feature = "try_from", issue = "33417")] +#[derive(Debug, Copy, Clone)] +pub struct TryFromIntError(()); + +impl TryFromIntError { + #[unstable(feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "0")] + #[doc(hidden)] + pub fn __description(&self) -> &str { + "out of range integral type conversion attempted" + } +} + +#[unstable(feature = "try_from", issue = "33417")] +impl fmt::Display for TryFromIntError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.__description().fmt(fmt) + } +} + +macro_rules! same_sign_from_int_impl { + ($storage:ty, $target:ty, $($source:ty),*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl TryFrom<$source> for $target { + type Err = TryFromIntError; + + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + let min = <$target as FromStrRadixHelper>::min_value() as $storage; + let max = <$target as FromStrRadixHelper>::max_value() as $storage; + if u as $storage < min || u as $storage > max { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +same_sign_from_int_impl!(u64, u8, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i8, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, u16, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i16, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, u32, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i32, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, u64, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i64, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, usize, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, isize, i8, i16, i32, i64, isize); + +macro_rules! cross_sign_from_int_impl { + ($unsigned:ty, $($signed:ty),*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl TryFrom<$unsigned> for $signed { + type Err = TryFromIntError; + + fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> { + let max = <$signed as FromStrRadixHelper>::max_value() as u64; + if u as u64 > max { + Err(TryFromIntError(())) + } else { + Ok(u as $signed) + } + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl TryFrom<$signed> for $unsigned { + type Err = TryFromIntError; + + fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> { + let max = <$unsigned as FromStrRadixHelper>::max_value() as u64; + if u < 0 || u as u64 > max { + Err(TryFromIntError(())) + } else { + Ok(u as $unsigned) + } + } + } + )*} +} + +cross_sign_from_int_impl!(u8, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(u16, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(u32, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(u64, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(usize, i8, i16, i32, i64, isize); + #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { fn min_value() -> Self; + fn max_value() -> Self; fn from_u32(u: u32) -> Self; fn checked_mul(&self, other: u32) -> Option; fn checked_sub(&self, other: u32) -> Option; @@ -2353,6 +2445,7 @@ trait FromStrRadixHelper: PartialOrd + Copy { macro_rules! doit { ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { fn min_value() -> Self { Self::min_value() } + fn max_value() -> Self { Self::max_value() } fn from_u32(u: u32) -> Self { u as Self } fn checked_mul(&self, other: u32) -> Option { Self::checked_mul(*self, other as Self) diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index aa7ab4b4e3f85..a3c46ffcea5d6 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -34,6 +34,7 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] +#![feature(try_from)] extern crate core; extern crate test; diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 11c1bd667fb36..642aea9f4f733 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -8,10 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::convert::TryFrom; use core::cmp::PartialEq; use core::fmt::Debug; -use core::ops::{Add, Sub, Mul, Div, Rem}; use core::marker::Copy; +use core::num::Float; +use core::ops::{Add, Sub, Mul, Div, Rem}; +use core::option::Option; +use core::option::Option::{Some, None}; #[macro_use] mod int_macros; @@ -48,169 +52,318 @@ pub fn test_num(ten: T, two: T) where assert_eq!(ten.rem(two), ten % two); } -#[cfg(test)] -mod tests { - use core::option::Option; - use core::option::Option::{Some, None}; - use core::num::Float; - - #[test] - fn from_str_issue7588() { - let u : Option = u8::from_str_radix("1000", 10).ok(); - assert_eq!(u, None); - let s : Option = i16::from_str_radix("80000", 10).ok(); - assert_eq!(s, None); - } +#[test] +fn from_str_issue7588() { + let u : Option = u8::from_str_radix("1000", 10).ok(); + assert_eq!(u, None); + let s : Option = i16::from_str_radix("80000", 10).ok(); + assert_eq!(s, None); +} - #[test] - fn test_int_from_str_overflow() { - let mut i8_val: i8 = 127; - assert_eq!("127".parse::().ok(), Some(i8_val)); - assert_eq!("128".parse::().ok(), None); +#[test] +fn test_int_from_str_overflow() { + let mut i8_val: i8 = 127; + assert_eq!("127".parse::().ok(), Some(i8_val)); + assert_eq!("128".parse::().ok(), None); - i8_val = i8_val.wrapping_add(1); - assert_eq!("-128".parse::().ok(), Some(i8_val)); - assert_eq!("-129".parse::().ok(), None); + i8_val = i8_val.wrapping_add(1); + assert_eq!("-128".parse::().ok(), Some(i8_val)); + assert_eq!("-129".parse::().ok(), None); - let mut i16_val: i16 = 32_767; - assert_eq!("32767".parse::().ok(), Some(i16_val)); - assert_eq!("32768".parse::().ok(), None); + let mut i16_val: i16 = 32_767; + assert_eq!("32767".parse::().ok(), Some(i16_val)); + assert_eq!("32768".parse::().ok(), None); - i16_val = i16_val.wrapping_add(1); - assert_eq!("-32768".parse::().ok(), Some(i16_val)); - assert_eq!("-32769".parse::().ok(), None); + i16_val = i16_val.wrapping_add(1); + assert_eq!("-32768".parse::().ok(), Some(i16_val)); + assert_eq!("-32769".parse::().ok(), None); - let mut i32_val: i32 = 2_147_483_647; - assert_eq!("2147483647".parse::().ok(), Some(i32_val)); - assert_eq!("2147483648".parse::().ok(), None); + let mut i32_val: i32 = 2_147_483_647; + assert_eq!("2147483647".parse::().ok(), Some(i32_val)); + assert_eq!("2147483648".parse::().ok(), None); - i32_val = i32_val.wrapping_add(1); - assert_eq!("-2147483648".parse::().ok(), Some(i32_val)); - assert_eq!("-2147483649".parse::().ok(), None); + i32_val = i32_val.wrapping_add(1); + assert_eq!("-2147483648".parse::().ok(), Some(i32_val)); + assert_eq!("-2147483649".parse::().ok(), None); - let mut i64_val: i64 = 9_223_372_036_854_775_807; - assert_eq!("9223372036854775807".parse::().ok(), Some(i64_val)); - assert_eq!("9223372036854775808".parse::().ok(), None); + let mut i64_val: i64 = 9_223_372_036_854_775_807; + assert_eq!("9223372036854775807".parse::().ok(), Some(i64_val)); + assert_eq!("9223372036854775808".parse::().ok(), None); - i64_val = i64_val.wrapping_add(1); - assert_eq!("-9223372036854775808".parse::().ok(), Some(i64_val)); - assert_eq!("-9223372036854775809".parse::().ok(), None); - } + i64_val = i64_val.wrapping_add(1); + assert_eq!("-9223372036854775808".parse::().ok(), Some(i64_val)); + assert_eq!("-9223372036854775809".parse::().ok(), None); +} + +#[test] +fn test_leading_plus() { + assert_eq!("+127".parse::().ok(), Some(127)); + assert_eq!("+9223372036854775807".parse::().ok(), Some(9223372036854775807)); +} - #[test] - fn test_leading_plus() { - assert_eq!("+127".parse::().ok(), Some(127)); - assert_eq!("+9223372036854775807".parse::().ok(), Some(9223372036854775807)); +#[test] +fn test_invalid() { + assert_eq!("--129".parse::().ok(), None); + assert_eq!("++129".parse::().ok(), None); + assert_eq!("Съешь".parse::().ok(), None); +} + +#[test] +fn test_empty() { + assert_eq!("-".parse::().ok(), None); + assert_eq!("+".parse::().ok(), None); + assert_eq!("".parse::().ok(), None); +} + +macro_rules! test_impl_from { + ($fn_name: ident, $Small: ty, $Large: ty) => { + #[test] + fn $fn_name() { + let small_max = <$Small>::max_value(); + let small_min = <$Small>::min_value(); + let large_max: $Large = small_max.into(); + let large_min: $Large = small_min.into(); + assert_eq!(large_max as $Small, small_max); + assert_eq!(large_min as $Small, small_min); + } } +} + +// Unsigned -> Unsigned +test_impl_from! { test_u8u16, u8, u16 } +test_impl_from! { test_u8u32, u8, u32 } +test_impl_from! { test_u8u64, u8, u64 } +test_impl_from! { test_u8usize, u8, usize } +test_impl_from! { test_u16u32, u16, u32 } +test_impl_from! { test_u16u64, u16, u64 } +test_impl_from! { test_u32u64, u32, u64 } + +// Signed -> Signed +test_impl_from! { test_i8i16, i8, i16 } +test_impl_from! { test_i8i32, i8, i32 } +test_impl_from! { test_i8i64, i8, i64 } +test_impl_from! { test_i8isize, i8, isize } +test_impl_from! { test_i16i32, i16, i32 } +test_impl_from! { test_i16i64, i16, i64 } +test_impl_from! { test_i32i64, i32, i64 } + +// Unsigned -> Signed +test_impl_from! { test_u8i16, u8, i16 } +test_impl_from! { test_u8i32, u8, i32 } +test_impl_from! { test_u8i64, u8, i64 } +test_impl_from! { test_u16i32, u16, i32 } +test_impl_from! { test_u16i64, u16, i64 } +test_impl_from! { test_u32i64, u32, i64 } + +// Signed -> Float +test_impl_from! { test_i8f32, i8, f32 } +test_impl_from! { test_i8f64, i8, f64 } +test_impl_from! { test_i16f32, i16, f32 } +test_impl_from! { test_i16f64, i16, f64 } +test_impl_from! { test_i32f64, i32, f64 } + +// Unsigned -> Float +test_impl_from! { test_u8f32, u8, f32 } +test_impl_from! { test_u8f64, u8, f64 } +test_impl_from! { test_u16f32, u16, f32 } +test_impl_from! { test_u16f64, u16, f64 } +test_impl_from! { test_u32f64, u32, f64 } + +// Float -> Float +#[test] +fn test_f32f64() { + use core::f32; + + let max: f64 = f32::MAX.into(); + assert_eq!(max as f32, f32::MAX); + assert!(max.is_normal()); + + let min: f64 = f32::MIN.into(); + assert_eq!(min as f32, f32::MIN); + assert!(min.is_normal()); + + let min_positive: f64 = f32::MIN_POSITIVE.into(); + assert_eq!(min_positive as f32, f32::MIN_POSITIVE); + assert!(min_positive.is_normal()); + + let epsilon: f64 = f32::EPSILON.into(); + assert_eq!(epsilon as f32, f32::EPSILON); + assert!(epsilon.is_normal()); + + let zero: f64 = (0.0f32).into(); + assert_eq!(zero as f32, 0.0f32); + assert!(zero.is_sign_positive()); + + let neg_zero: f64 = (-0.0f32).into(); + assert_eq!(neg_zero as f32, -0.0f32); + assert!(neg_zero.is_sign_negative()); + + let infinity: f64 = f32::INFINITY.into(); + assert_eq!(infinity as f32, f32::INFINITY); + assert!(infinity.is_infinite()); + assert!(infinity.is_sign_positive()); + + let neg_infinity: f64 = f32::NEG_INFINITY.into(); + assert_eq!(neg_infinity as f32, f32::NEG_INFINITY); + assert!(neg_infinity.is_infinite()); + assert!(neg_infinity.is_sign_negative()); + + let nan: f64 = f32::NAN.into(); + assert!(nan.is_nan()); +} - #[test] - fn test_invalid() { - assert_eq!("--129".parse::().ok(), None); - assert_eq!("++129".parse::().ok(), None); - assert_eq!("Съешь".parse::().ok(), None); +macro_rules! test_impl_try_from_always_ok { + ($fn_name:ident, $source:ty, $target: ty) => { + #[test] + fn $fn_name() { + let max = <$source>::max_value(); + let min = <$source>::min_value(); + let zero: $source = 0; + assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), + max as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), + min as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + zero as $target); + } } +} - #[test] - fn test_empty() { - assert_eq!("-".parse::().ok(), None); - assert_eq!("+".parse::().ok(), None); - assert_eq!("".parse::().ok(), None); +test_impl_try_from_always_ok! { test_try_u8u8, u8, u8 } +test_impl_try_from_always_ok! { test_try_u8u16, u8, u16 } +test_impl_try_from_always_ok! { test_try_u8u32, u8, u32 } +test_impl_try_from_always_ok! { test_try_u8u64, u8, u64 } +test_impl_try_from_always_ok! { test_try_u8i16, u8, i16 } +test_impl_try_from_always_ok! { test_try_u8i32, u8, i32 } +test_impl_try_from_always_ok! { test_try_u8i64, u8, i64 } + +test_impl_try_from_always_ok! { test_try_u16u16, u16, u16 } +test_impl_try_from_always_ok! { test_try_u16u32, u16, u32 } +test_impl_try_from_always_ok! { test_try_u16u64, u16, u64 } +test_impl_try_from_always_ok! { test_try_u16i32, u16, i32 } +test_impl_try_from_always_ok! { test_try_u16i64, u16, i64 } + +test_impl_try_from_always_ok! { test_try_u32u32, u32, u32 } +test_impl_try_from_always_ok! { test_try_u32u64, u32, u64 } +test_impl_try_from_always_ok! { test_try_u32i64, u32, i64 } + +test_impl_try_from_always_ok! { test_try_u64u64, u64, u64 } + +test_impl_try_from_always_ok! { test_try_i8i8, i8, i8 } +test_impl_try_from_always_ok! { test_try_i8i16, i8, i16 } +test_impl_try_from_always_ok! { test_try_i8i32, i8, i32 } +test_impl_try_from_always_ok! { test_try_i8i64, i8, i64 } + +test_impl_try_from_always_ok! { test_try_i16i16, i16, i16 } +test_impl_try_from_always_ok! { test_try_i16i32, i16, i32 } +test_impl_try_from_always_ok! { test_try_i16i64, i16, i64 } + +test_impl_try_from_always_ok! { test_try_i32i32, i32, i32 } +test_impl_try_from_always_ok! { test_try_i32i64, i32, i64 } + +test_impl_try_from_always_ok! { test_try_i64i64, i64, i64 } + +macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok { + ($fn_name:ident, $source:ty, $target:ty) => { + #[test] + fn $fn_name() { + let max = <$source>::max_value(); + let min = <$source>::min_value(); + let zero: $source = 0; + let neg_one: $source = -1; + assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), + max as $target); + assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + zero as $target); + assert!(<$target as TryFrom<$source>>::try_from(neg_one).is_err()); + } } +} - macro_rules! test_impl_from { - ($fn_name: ident, $Small: ty, $Large: ty) => { - #[test] - fn $fn_name() { - let small_max = <$Small>::max_value(); - let small_min = <$Small>::min_value(); - let large_max: $Large = small_max.into(); - let large_min: $Large = small_min.into(); - assert_eq!(large_max as $Small, small_max); - assert_eq!(large_min as $Small, small_min); - } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u8, i8, u8 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u16, i8, u16 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u32, i8, u32 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u64, i8, u64 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u16, i16, u16 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u32, i16, u32 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u64, i16, u64 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u32, i32, u32 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u64, i32, u64 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u64, i64, u64 } + +macro_rules! test_impl_try_from_unsigned_to_signed_upper_err { + ($fn_name:ident, $source:ty, $target:ty) => { + #[test] + fn $fn_name() { + let max = <$source>::max_value(); + let min = <$source>::min_value(); + let zero: $source = 0; + assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); + assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), + min as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + zero as $target); } } +} - // Unsigned -> Unsigned - test_impl_from! { test_u8u16, u8, u16 } - test_impl_from! { test_u8u32, u8, u32 } - test_impl_from! { test_u8u64, u8, u64 } - test_impl_from! { test_u8usize, u8, usize } - test_impl_from! { test_u16u32, u16, u32 } - test_impl_from! { test_u16u64, u16, u64 } - test_impl_from! { test_u32u64, u32, u64 } - - // Signed -> Signed - test_impl_from! { test_i8i16, i8, i16 } - test_impl_from! { test_i8i32, i8, i32 } - test_impl_from! { test_i8i64, i8, i64 } - test_impl_from! { test_i8isize, i8, isize } - test_impl_from! { test_i16i32, i16, i32 } - test_impl_from! { test_i16i64, i16, i64 } - test_impl_from! { test_i32i64, i32, i64 } - - // Unsigned -> Signed - test_impl_from! { test_u8i16, u8, i16 } - test_impl_from! { test_u8i32, u8, i32 } - test_impl_from! { test_u8i64, u8, i64 } - test_impl_from! { test_u16i32, u16, i32 } - test_impl_from! { test_u16i64, u16, i64 } - test_impl_from! { test_u32i64, u32, i64 } - - // Signed -> Float - test_impl_from! { test_i8f32, i8, f32 } - test_impl_from! { test_i8f64, i8, f64 } - test_impl_from! { test_i16f32, i16, f32 } - test_impl_from! { test_i16f64, i16, f64 } - test_impl_from! { test_i32f64, i32, f64 } - - // Unsigned -> Float - test_impl_from! { test_u8f32, u8, f32 } - test_impl_from! { test_u8f64, u8, f64 } - test_impl_from! { test_u16f32, u16, f32 } - test_impl_from! { test_u16f64, u16, f64 } - test_impl_from! { test_u32f64, u32, f64 } - - // Float -> Float - #[test] - fn test_f32f64() { - use core::f32; - - let max: f64 = f32::MAX.into(); - assert_eq!(max as f32, f32::MAX); - assert!(max.is_normal()); - - let min: f64 = f32::MIN.into(); - assert_eq!(min as f32, f32::MIN); - assert!(min.is_normal()); - - let min_positive: f64 = f32::MIN_POSITIVE.into(); - assert_eq!(min_positive as f32, f32::MIN_POSITIVE); - assert!(min_positive.is_normal()); - - let epsilon: f64 = f32::EPSILON.into(); - assert_eq!(epsilon as f32, f32::EPSILON); - assert!(epsilon.is_normal()); - - let zero: f64 = (0.0f32).into(); - assert_eq!(zero as f32, 0.0f32); - assert!(zero.is_sign_positive()); - - let neg_zero: f64 = (-0.0f32).into(); - assert_eq!(neg_zero as f32, -0.0f32); - assert!(neg_zero.is_sign_negative()); - - let infinity: f64 = f32::INFINITY.into(); - assert_eq!(infinity as f32, f32::INFINITY); - assert!(infinity.is_infinite()); - assert!(infinity.is_sign_positive()); - - let neg_infinity: f64 = f32::NEG_INFINITY.into(); - assert_eq!(neg_infinity as f32, f32::NEG_INFINITY); - assert!(neg_infinity.is_infinite()); - assert!(neg_infinity.is_sign_negative()); - - let nan: f64 = f32::NAN.into(); - assert!(nan.is_nan()); +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u8i8, u8, i8 } + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i8, u16, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i16, u16, i16 } + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i8, u32, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i16, u32, i16 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i32, u32, i32 } + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i8, u64, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i16, u64, i16 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i32, u64, i32 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i64, u64, i64 } + +macro_rules! test_impl_try_from_same_sign_err { + ($fn_name:ident, $source:ty, $target:ty) => { + #[test] + fn $fn_name() { + let max = <$source>::max_value(); + let min = <$source>::min_value(); + let zero: $source = 0; + let t_max = <$target>::max_value(); + let t_min = <$target>::min_value(); + assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); + if min != 0 { + assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); + } + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + zero as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(t_max as $source) + .unwrap(), + t_max as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(t_min as $source) + .unwrap(), + t_min as $target); + } } } + +test_impl_try_from_same_sign_err! { test_try_u16u8, u16, u8 } + +test_impl_try_from_same_sign_err! { test_try_u32u8, u32, u8 } +test_impl_try_from_same_sign_err! { test_try_u32u16, u32, u16 } + +test_impl_try_from_same_sign_err! { test_try_u64u8, u64, u8 } +test_impl_try_from_same_sign_err! { test_try_u64u16, u64, u16 } +test_impl_try_from_same_sign_err! { test_try_u64u32, u64, u32 } + +test_impl_try_from_same_sign_err! { test_try_i16i8, i16, i8 } + +test_impl_try_from_same_sign_err! { test_try_i32i8, i32, i8 } +test_impl_try_from_same_sign_err! { test_try_i32i16, i32, i16 } + +test_impl_try_from_same_sign_err! { test_try_i64i8, i64, i8 } +test_impl_try_from_same_sign_err! { test_try_i64i16, i64, i16 } +test_impl_try_from_same_sign_err! { test_try_i64i32, i64, i32 } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 35cd4a5ec5292..d49d97649467a 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -159,6 +159,13 @@ impl Error for num::ParseIntError { } } +#[unstable(feature = "try_from", issue = "33417")] +impl Error for num::TryFromIntError { + fn description(&self) -> &str { + self.__description() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseFloatError { fn description(&self) -> &str { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index e14a31453d381..d4b40b844fce5 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -270,6 +270,7 @@ #![feature(vec_push_all)] #![feature(zero_one)] #![feature(question_mark)] +#![feature(try_from)] // Issue# 30592: Systematically use alloc_system during stage0 since jemalloc // might be unavailable or disabled diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 1886b4fdf59c6..d33df05acf224 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -19,7 +19,7 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{Zero, One}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::num::{FpCategory, ParseIntError, ParseFloatError}; +pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping;