]> git.lizzy.rs Git - rust.git/commitdiff
Merge branch 'master' of https://github.com/rust-lang/rust into gen
authorJohn Kåre Alsaker <john.kare.alsaker@gmail.com>
Sat, 12 Aug 2017 05:11:19 +0000 (07:11 +0200)
committerJohn Kåre Alsaker <john.kare.alsaker@gmail.com>
Sat, 12 Aug 2017 05:11:19 +0000 (07:11 +0200)
# Conflicts:
# src/librustc_mir/build/scope.rs

33 files changed:
src/Cargo.lock
src/bootstrap/config.rs
src/bootstrap/config.toml.example
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/libcore/intrinsics.rs
src/libcore/mem.rs
src/librustc/mir/tcx.rs
src/librustc_driver/Cargo.toml
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/test.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/dataflow/drop_flag_effects.rs
src/librustc_mir/dataflow/impls/mod.rs
src/librustc_mir/dataflow/move_paths/mod.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/mod.rs
src/librustc_trans/Cargo.toml
src/librustc_trans/back/link.rs
src/librustc_trans/back/write.rs
src/librustc_trans_utils/Cargo.toml [new file with mode: 0644]
src/librustc_trans_utils/lib.rs [new file with mode: 0644]
src/librustc_trans_utils/link.rs [new file with mode: 0644]
src/rustc/Cargo.toml
src/test/mir-opt/end_region_4.rs
src/test/mir-opt/end_region_5.rs
src/test/mir-opt/end_region_6.rs
src/test/mir-opt/end_region_7.rs
src/test/mir-opt/end_region_8.rs
src/test/mir-opt/issue-41110.rs
src/test/run-pass/dynamic-drop.rs

index 38897993d435de0d02c6dcc50469de7ac2b31e3c..c175198c227a54adc24d0fc04abd27072402d0ab 100644 (file)
@@ -65,6 +65,11 @@ name = "ansi_term"
 version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "ar"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "arena"
 version = "0.0.0"
@@ -1333,10 +1338,12 @@ dependencies = [
 name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
+ "ar 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "arena 0.0.0",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_allocator 0.0.0",
  "rustc_back 0.0.0",
@@ -1354,6 +1361,7 @@ dependencies = [
  "rustc_resolve 0.0.0",
  "rustc_save_analysis 0.0.0",
  "rustc_trans 0.0.0",
+ "rustc_trans_utils 0.0.0",
  "rustc_typeck 0.0.0",
  "serialize 0.0.0",
  "syntax 0.0.0",
@@ -1545,11 +1553,21 @@ dependencies = [
  "rustc_incremental 0.0.0",
  "rustc_llvm 0.0.0",
  "rustc_platform_intrinsics 0.0.0",
+ "rustc_trans_utils 0.0.0",
  "serialize 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
 
+[[package]]
+name = "rustc_trans_utils"
+version = "0.0.0"
+dependencies = [
+ "rustc 0.0.0",
+ "syntax 0.0.0",
+ "syntax_pos 0.0.0",
+]
+
 [[package]]
 name = "rustc_tsan"
 version = "0.0.0"
@@ -2141,6 +2159,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
 "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
 "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
+"checksum ar 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b24e4eef8e3fa7e2ca75b157e6039cdf8d9d3a68213ddc19d0fd9d576b9717c9"
 "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
 "checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
 "checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c"
index 5d898cb716dcf68d48b7426e40d9a6e957190b51..ec57bb069e0a4812719f88be8640239e3cf857e6 100644 (file)
@@ -53,6 +53,7 @@ pub struct Config {
     pub profiler: bool,
 
     // llvm codegen options
+    pub llvm_enabled: bool,
     pub llvm_assertions: bool,
     pub llvm_optimize: bool,
     pub llvm_release_debuginfo: bool,
@@ -192,6 +193,7 @@ struct Install {
 #[derive(Deserialize, Default)]
 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
 struct Llvm {
+    enabled: Option<bool>,
     ccache: Option<StringOrBool>,
     ninja: Option<bool>,
     assertions: Option<bool>,
@@ -265,6 +267,7 @@ struct TomlTarget {
 impl Config {
     pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
         let mut config = Config::default();
+        config.llvm_enabled = true;
         config.llvm_optimize = true;
         config.use_jemalloc = true;
         config.backtrace = true;
@@ -345,6 +348,7 @@ pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
                 Some(StringOrBool::Bool(false)) | None => {}
             }
             set(&mut config.ninja, llvm.ninja);
+            set(&mut config.llvm_enabled, llvm.enabled);
             set(&mut config.llvm_assertions, llvm.assertions);
             set(&mut config.llvm_optimize, llvm.optimize);
             set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
index 9314135050f016f84b487e8405e814b3dd75affc..19678dc77937568216a7fafa88302834669bca10 100644 (file)
 # =============================================================================
 [llvm]
 
+# Indicates whether rustc will support compilation with LLVM
+# note: rustc does not compile without LLVM at the moment
+#enabled = true
+
 # Indicates whether the LLVM build is a Release or Debug build
 #optimize = true
 
index 5b5ef3f07f98e839caf20904532bc2a2e4f33f98..a8485d1d152d18703837f735a7e778e8c62dd2f8 100644 (file)
@@ -429,6 +429,9 @@ fn rustc_features(&self) -> String {
         if self.config.use_jemalloc {
             features.push_str(" jemalloc");
         }
+        if self.config.llvm_enabled {
+            features.push_str(" llvm");
+        }
         features
     }
 
index ee0eca5d482432853ba2ee66e2ff3f6bef067173..59efbd5c4d20d8d9ce7f96d355cf746e20e13fec 100644 (file)
@@ -56,6 +56,12 @@ fn make_run(run: RunConfig) {
     fn run(self, builder: &Builder) {
         let build = builder.build;
         let target = self.target;
+
+        // If we're not compiling for LLVM bail out here.
+        if !build.config.llvm_enabled {
+            return;
+        }
+
         // If we're using a custom LLVM bail out here, but we can only use a
         // custom LLVM for the build triple.
         if let Some(config) = build.config.target_config.get(&target) {
index 65c18d6d7772b45852b493f57d6c6737083b7b4c..fdca8d00d7a75f1fc0a693765a576b7d536d893d 100644 (file)
     /// Aborts the execution of the process.
     pub fn abort() -> !;
 
-    /// Tells LLVM that this point in the code is not reachable,
-    /// enabling further optimizations.
+    /// Tells LLVM that this point in the code is not reachable, enabling
+    /// further optimizations.
     ///
-    /// NB: This is very different from the `unreachable!()` macro!
+    /// NB: This is very different from the `unreachable!()` macro: Unlike the
+    /// macro, which panics when it is executed, it is *undefined behavior* to
+    /// reach code marked with this function.
     pub fn unreachable() -> !;
 
     /// Informs the optimizer that a condition is always true.
index 866296a5670318c8047ea441e78e89c86256493f..6f7adbe1e7a0e9e67754ae9731582c4e209b4668 100644 (file)
@@ -942,3 +942,15 @@ fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result {
         }
     }
 }
+
+/// Tells LLVM that this point in the code is not reachable, enabling further
+/// optimizations.
+///
+/// NB: This is very different from the `unreachable!()` macro: Unlike the
+/// macro, which panics when it is executed, it is *undefined behavior* to
+/// reach code marked with this function.
+#[inline]
+#[unstable(feature = "unreachable", issue = "43751")]
+pub unsafe fn unreachable() -> ! {
+    intrinsics::unreachable()
+}
index 14c53ee2dd7820b2cd791405351adddc6ebc07d5..eb403442f46399de4b82d559a70e7562afb4b4f4 100644 (file)
@@ -135,6 +135,11 @@ pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> L
     }
 }
 
+pub enum RvalueInitializationState {
+    Shallow,
+    Deep
+}
+
 impl<'tcx> Rvalue<'tcx> {
     pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
         where D: HasLocalDecls<'tcx>
@@ -209,6 +214,16 @@ pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> T
             }
         }
     }
+
+    #[inline]
+    /// Returns whether this rvalue is deeply initialized (most rvalues) or
+    /// whether its only shallowly initialized (`Rvalue::Box`).
+    pub fn initialization_state(&self) -> RvalueInitializationState {
+        match *self {
+            Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
+            _ => RvalueInitializationState::Deep
+        }
+    }
 }
 
 impl<'tcx> Operand<'tcx> {
index f1bdf0b2c3d3757bb2e03e1b48ac797e09812921..d6155f53485e3a8caca6b161bb38ac83e55ce1e8 100644 (file)
@@ -12,6 +12,7 @@ crate-type = ["dylib"]
 arena = { path = "../libarena" }
 graphviz = { path = "../libgraphviz" }
 log = { version = "0.3", features = ["release_max_level_info"] }
+owning_ref = "0.3.3"
 env_logger = { version = "0.4", default-features = false }
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
@@ -29,9 +30,15 @@ rustc_plugin = { path = "../librustc_plugin" }
 rustc_privacy = { path = "../librustc_privacy" }
 rustc_resolve = { path = "../librustc_resolve" }
 rustc_save_analysis = { path = "../librustc_save_analysis" }
-rustc_trans = { path = "../librustc_trans" }
+rustc_trans = { path = "../librustc_trans", optional = true }
+rustc_trans_utils = { path = "../librustc_trans_utils" }
 rustc_typeck = { path = "../librustc_typeck" }
 serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
 syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
+
+ar = "0.3.0"
+
+[features]
+llvm = ["rustc_trans"]
index da22f1e411dba5a2cf2cdefead97c30a5d69ae83..7efa2846cd6f3dd6deb8af749f3bbb46eab26506 100644 (file)
@@ -18,7 +18,9 @@
 use rustc::session::config::{self, Input, OutputFilenames, OutputType};
 use rustc::session::search_paths::PathKind;
 use rustc::lint;
-use rustc::middle::{self, dependency_format, stability, reachable};
+use rustc::middle::{self, stability, reachable};
+#[cfg(feature="llvm")]
+use rustc::middle::dependency_format;
 use rustc::middle::privacy::AccessLevels;
 use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes};
 use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
@@ -31,7 +33,9 @@
 use rustc_resolve::{MakeGlobMap, Resolver};
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::{self, CStore};
+#[cfg(feature="llvm")]
 use rustc_trans::back::{link, write};
+#[cfg(feature="llvm")]
 use rustc_trans as trans;
 use rustc_typeck as typeck;
 use rustc_privacy;
@@ -69,6 +73,11 @@ pub fn compile_input(sess: &Session,
                      output: &Option<PathBuf>,
                      addl_plugins: Option<Vec<String>>,
                      control: &CompileController) -> CompileResult {
+    #[cfg(feature="llvm")]
+    use rustc_trans::back::write::OngoingCrateTranslation;
+    #[cfg(not(feature="llvm"))]
+    type OngoingCrateTranslation = ();
+
     macro_rules! controller_entry_point {
         ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
             let state = &mut $make_state;
@@ -88,7 +97,7 @@ macro_rules! controller_entry_point {
     // We need nested scopes here, because the intermediate results can keep
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
-    let (outputs, trans) = {
+    let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
         let krate = match phase_1_parse_input(control, sess, input) {
             Ok(krate) => krate,
             Err(mut parse_error) => {
@@ -113,7 +122,8 @@ macro_rules! controller_entry_point {
         };
 
         let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
-        let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input);
+        let crate_name =
+            ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
         let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
             phase_2_configure_and_expand(
                 sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
@@ -206,6 +216,8 @@ macro_rules! controller_entry_point {
                 println!("Pre-trans");
                 tcx.print_debug_stats();
             }
+
+            #[cfg(feature="llvm")]
             let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map,
                                                   &outputs);
 
@@ -221,38 +233,59 @@ macro_rules! controller_entry_point {
                 }
             }
 
+            #[cfg(not(feature="llvm"))]
+            {
+                let _ = incremental_hashes_map;
+                sess.err(&format!("LLVM is not supported by this rustc"));
+                sess.abort_if_errors();
+                unreachable!();
+            }
+
+            #[cfg(feature="llvm")]
             Ok((outputs, trans))
         })??
     };
 
-    if sess.opts.debugging_opts.print_type_sizes {
-        sess.code_stats.borrow().print_type_sizes();
+    #[cfg(not(feature="llvm"))]
+    {
+        let _ = outputs;
+        let _ = trans;
+        unreachable!();
     }
 
-    let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
+    #[cfg(feature="llvm")]
+    {
+        if sess.opts.debugging_opts.print_type_sizes {
+            sess.code_stats.borrow().print_type_sizes();
+        }
 
-    controller_entry_point!(after_llvm,
-                            sess,
-                            CompileState::state_after_llvm(input, sess, outdir, output, &trans),
-                            phase5_result);
-    phase5_result?;
+        let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
 
-    phase_6_link_output(sess, &trans, &outputs);
+        controller_entry_point!(after_llvm,
+                                sess,
+                                CompileState::state_after_llvm(input, sess, outdir, output, &trans),
+                                phase5_result);
+        phase5_result?;
 
-    // Now that we won't touch anything in the incremental compilation directory
-    // any more, we can finalize it (which involves renaming it)
-    rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
+        phase_6_link_output(sess, &trans, &outputs);
 
-    if sess.opts.debugging_opts.perf_stats {
-        sess.print_perf_stats();
-    }
+        // Now that we won't touch anything in the incremental compilation directory
+        // any more, we can finalize it (which involves renaming it)
+        rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
 
-    controller_entry_point!(compilation_done,
-                            sess,
-                            CompileState::state_when_compilation_done(input, sess, outdir, output),
-                            Ok(()));
+        if sess.opts.debugging_opts.perf_stats {
+            sess.print_perf_stats();
+        }
+
+        controller_entry_point!(
+            compilation_done,
+            sess,
+            CompileState::state_when_compilation_done(input, sess, outdir, output),
+            Ok(())
+        );
 
-    Ok(())
+        Ok(())
+    }
 }
 
 fn keep_hygiene_data(sess: &Session) -> bool {
@@ -360,6 +393,7 @@ pub struct CompileState<'a, 'tcx: 'a> {
     pub resolutions: Option<&'a Resolutions>,
     pub analysis: Option<&'a ty::CrateAnalysis>,
     pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
+    #[cfg(feature="llvm")]
     pub trans: Option<&'a trans::CrateTranslation>,
 }
 
@@ -386,6 +420,7 @@ fn empty(input: &'a Input,
             resolutions: None,
             analysis: None,
             tcx: None,
+            #[cfg(feature="llvm")]
             trans: None,
         }
     }
@@ -474,7 +509,7 @@ fn state_after_analysis(input: &'a Input,
         }
     }
 
-
+    #[cfg(feature="llvm")]
     fn state_after_llvm(input: &'a Input,
                         session: &'tcx Session,
                         out_dir: &'a Option<PathBuf>,
@@ -488,6 +523,7 @@ fn state_after_llvm(input: &'a Input,
         }
     }
 
+    #[cfg(feature="llvm")]
     fn state_when_compilation_done(input: &'a Input,
                                    session: &'tcx Session,
                                    out_dir: &'a Option<PathBuf>,
@@ -906,6 +942,7 @@ macro_rules! try_with_f {
     mir::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
     rustc_privacy::provide(&mut local_providers);
+    #[cfg(feature="llvm")]
     trans::provide(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
@@ -918,6 +955,7 @@ macro_rules! try_with_f {
 
     let mut extern_providers = ty::maps::Providers::default();
     cstore::provide(&mut extern_providers);
+    #[cfg(feature="llvm")]
     trans::provide(&mut extern_providers);
     ty::provide_extern(&mut extern_providers);
     traits::provide_extern(&mut extern_providers);
@@ -1066,6 +1104,7 @@ macro_rules! try_with_f {
 
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
+#[cfg(feature="llvm")]
 pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                            analysis: ty::CrateAnalysis,
                                            incremental_hashes_map: IncrementalHashesMap,
@@ -1087,6 +1126,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 /// Run LLVM itself, producing a bitcode file, assembly file or object file
 /// as a side effect.
+#[cfg(feature="llvm")]
 pub fn phase_5_run_llvm_passes(sess: &Session,
                                trans: write::OngoingCrateTranslation)
                                -> (CompileResult, trans::CrateTranslation) {
@@ -1105,6 +1145,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 
 /// Run the linker on any artifacts that resulted from the LLVM run.
 /// This should produce either a finished executable or library.
+#[cfg(feature="llvm")]
 pub fn phase_6_link_output(sess: &Session,
                            trans: &trans::CrateTranslation,
                            outputs: &OutputFilenames) {
@@ -1126,7 +1167,12 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
         match *output_type {
             OutputType::Exe => {
                 for output in sess.crate_types.borrow().iter() {
-                    let p = link::filename_for_input(sess, *output, crate_name, outputs);
+                    let p = ::rustc_trans_utils::link::filename_for_input(
+                        sess,
+                        *output,
+                        crate_name,
+                        outputs
+                    );
                     out_filenames.push(p);
                 }
             }
@@ -1236,7 +1282,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
     if base.is_empty() {
         base.extend(attr_types);
         if base.is_empty() {
-            base.push(link::default_output_for_target(session));
+            base.push(::rustc_trans_utils::link::default_output_for_target(session));
         }
         base.sort();
         base.dedup();
@@ -1244,7 +1290,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
 
     base.into_iter()
         .filter(|crate_type| {
-            let res = !link::invalid_output_for_target(session, *crate_type);
+            let res = !::rustc_trans_utils::link::invalid_output_for_target(session, *crate_type);
 
             if !res {
                 session.warn(&format!("dropping unsupported crate type `{}` for target `{}`",
index 6f0a50180d794b5de9f413f4306109d6e7bfea6f..91ba7ed1958e7c85299cf4795b54fc30ddcc486b 100644 (file)
 #![feature(rustc_diagnostic_macros)]
 #![feature(set_stdio)]
 
+#[cfg(not(feature="llvm"))]
+extern crate ar;
+
 extern crate arena;
 extern crate getopts;
 extern crate graphviz;
 extern crate env_logger;
+#[cfg(not(feature="llvm"))]
+extern crate owning_ref;
 extern crate libc;
 extern crate rustc;
 extern crate rustc_allocator;
@@ -49,7 +54,9 @@
 extern crate rustc_mir;
 extern crate rustc_resolve;
 extern crate rustc_save_analysis;
+#[cfg(feature="llvm")]
 extern crate rustc_trans;
+extern crate rustc_trans_utils;
 extern crate rustc_typeck;
 extern crate serialize;
 #[macro_use]
@@ -64,7 +71,7 @@
 use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc_trans::back::link;
+#[cfg(feature="llvm")]
 use rustc_trans::back::write::{RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS};
 use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::{early_error, early_warn};
 use rustc::lint::Lint;
 use rustc::lint;
+#[cfg(not(feature="llvm"))]
+use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait;
 use rustc_metadata::locator;
 use rustc_metadata::cstore::CStore;
 use rustc::util::common::{time, ErrorReported};
+#[cfg(not(feature="llvm"))]
+use rustc_back::target::Target;
 
 use serialize::json::ToJson;
 
 use std::io::{self, Read, Write};
 use std::iter::repeat;
 use std::path::PathBuf;
+#[cfg(not(feature="llvm"))]
+use std::path::Path;
 use std::process::{self, Command, Stdio};
 use std::rc::Rc;
 use std::str;
 use syntax::parse::{self, PResult};
 use syntax_pos::{DUMMY_SP, MultiSpan};
 
+#[cfg(not(feature="llvm"))]
+use owning_ref::{OwningRef, ErasedBoxRef};
+
 #[cfg(test)]
 pub mod test;
 
 pub mod driver;
 pub mod pretty;
+#[cfg(feature="llvm")]
 pub mod target_features;
 mod derive_registrar;
 
@@ -151,9 +168,49 @@ pub fn run<F>(run_compiler: F) -> isize
     0
 }
 
+#[cfg(not(feature="llvm"))]
+pub struct NoLLvmMetadataLoader;
+
+#[cfg(not(feature="llvm"))]
+pub use NoLLvmMetadataLoader as MetadataLoader;
+#[cfg(feature="llvm")]
+pub use rustc_trans::LlvmMetadataLoader as MetadataLoader;
+
+#[cfg(not(feature="llvm"))]
+impl MetadataLoaderTrait for NoLLvmMetadataLoader {
+    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
+        use std::fs::File;
+        use std::io;
+        use self::ar::Archive;
+
+        let file = File::open(filename).map_err(|e|format!("metadata file open err: {:?}", e))?;
+        let mut archive = Archive::new(file);
+
+        while let Some(entry_result) = archive.next_entry() {
+            let mut entry = entry_result.map_err(|e|format!("metadata section read err: {:?}", e))?;
+            if entry.header().identifier() == "rust.metadata.bin" {
+                let mut buf = Vec::new();
+                io::copy(&mut entry, &mut buf).unwrap();
+                let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into();
+                return Ok(buf.map_owner_box().erase_owner());
+            }
+        }
+
+        Err("Couldnt find metadata section".to_string())
+    }
+
+    fn get_dylib_metadata(&self,
+                          _target: &Target,
+                          _filename: &Path)
+                          -> Result<ErasedBoxRef<[u8]>, String> {
+        panic!("Dylib metadata loading not supported without LLVM")
+    }
+}
+
 // Parse args and run the compiler. This is the primary entry point for rustc.
 // See comments on CompilerCalls below for details about the callbacks argument.
 // The FileLoader provides a way to load files from sources other than the file system.
+#[cfg_attr(not(feature="llvm"), allow(unused_mut))]
 pub fn run_compiler<'a>(args: &[String],
                         callbacks: &mut CompilerCalls<'a>,
                         file_loader: Option<Box<FileLoader + 'static>>,
@@ -175,6 +232,7 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
     let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
 
     if sopts.debugging_opts.debug_llvm {
+        #[cfg(feature="llvm")]
         rustc_trans::enable_llvm_debug();
     }
 
@@ -197,17 +255,19 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
     };
 
     let dep_graph = DepGraph::new(sopts.build_dep_graph());
-    let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
+    let cstore = Rc::new(CStore::new(&dep_graph, box ::MetadataLoader));
 
     let loader = file_loader.unwrap_or(box RealFileLoader);
     let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
     let mut sess = session::build_session_with_codemap(
         sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest,
     );
+    #[cfg(feature="llvm")]
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
     let mut cfg = config::build_configuration(&sess, cfg);
+    #[cfg(feature="llvm")]
     target_features::add_configuration(&mut cfg, &sess);
     sess.parse_sess.config = cfg;
 
@@ -460,6 +520,7 @@ fn early_callback(&mut self,
         Compilation::Continue
     }
 
+    #[cfg_attr(not(feature="llvm"), allow(unused_mut))]
     fn no_input(&mut self,
                 matches: &getopts::Matches,
                 sopts: &config::Options,
@@ -477,15 +538,17 @@ fn no_input(&mut self,
                     return None;
                 }
                 let dep_graph = DepGraph::new(sopts.build_dep_graph());
-                let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
+                let cstore = Rc::new(CStore::new(&dep_graph, box ::MetadataLoader));
                 let mut sess = build_session(sopts.clone(),
                     &dep_graph,
                     None,
                     descriptions.clone(),
                     cstore.clone());
+                #[cfg(feature="llvm")]
                 rustc_trans::init(&sess);
                 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
                 let mut cfg = config::build_configuration(&sess, cfg.clone());
+                #[cfg(feature="llvm")]
                 target_features::add_configuration(&mut cfg, &sess);
                 sess.parse_sess.config = cfg;
                 let should_stop =
@@ -678,14 +741,19 @@ fn print_crate_info(sess: &Session,
                     };
                     let attrs = attrs.as_ref().unwrap();
                     let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
-                    let id = link::find_crate_name(Some(sess), attrs, input);
+                    let id = rustc_trans_utils::link::find_crate_name(Some(sess), attrs, input);
                     if *req == PrintRequest::CrateName {
                         println!("{}", id);
                         continue;
                     }
                     let crate_types = driver::collect_crate_types(sess, attrs);
                     for &style in &crate_types {
-                        let fname = link::filename_for_input(sess, style, &id, &t_outputs);
+                        let fname = rustc_trans_utils::link::filename_for_input(
+                            sess,
+                            style,
+                            &id,
+                            &t_outputs
+                        );
                         println!("{}",
                                  fname.file_name()
                                       .unwrap()
@@ -734,6 +802,7 @@ fn print_crate_info(sess: &Session,
                 }
                 PrintRequest::RelocationModels => {
                     println!("Available relocation models:");
+                    #[cfg(feature="llvm")]
                     for &(name, _) in RELOC_MODEL_ARGS.iter() {
                         println!("    {}", name);
                     }
@@ -741,13 +810,17 @@ fn print_crate_info(sess: &Session,
                 }
                 PrintRequest::CodeModels => {
                     println!("Available code models:");
+                    #[cfg(feature="llvm")]
                     for &(name, _) in CODE_GEN_MODEL_ARGS.iter(){
                         println!("    {}", name);
                     }
                     println!("");
                 }
                 PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => {
+                    #[cfg(feature="llvm")]
                     rustc_trans::print(*req, sess);
+                    #[cfg(not(feature="llvm"))]
+                    panic!("LLVM not supported by this rustc")
                 }
             }
         }
@@ -786,6 +859,7 @@ fn unw(x: Option<&str>) -> &str {
         println!("commit-date: {}", unw(commit_date_str()));
         println!("host: {}", config::host_triple());
         println!("release: {}", unw(release_str()));
+        #[cfg(feature="llvm")]
         rustc_trans::print_version();
     }
 }
@@ -1083,6 +1157,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     if cg_flags.contains(&"passes=list".to_string()) {
+        #[cfg(feature="llvm")]
         rustc_trans::print_passes();
         return None;
     }
@@ -1210,6 +1285,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
+    #[cfg(feature="llvm")]
     all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
index 8668ab301543b6aa3826190472437f030e51ce0c..7f65a8b97cd669b76297f14ea01d9681151982bd 100644 (file)
@@ -14,6 +14,7 @@
 use rustc::dep_graph::DepGraph;
 use rustc_lint;
 use rustc_resolve::MakeGlobMap;
+#[cfg(feature="llvm")]
 use rustc_trans;
 use rustc::middle::lang_items;
 use rustc::middle::free_region::FreeRegionMap;
@@ -106,13 +107,14 @@ fn test_env<F>(source_string: &str,
 
     let dep_graph = DepGraph::new(false);
     let _ignore = dep_graph.in_ignore();
-    let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader));
+    let cstore = Rc::new(CStore::new(&dep_graph, box ::MetadataLoader));
     let sess = session::build_session_(options,
                                        &dep_graph,
                                        None,
                                        diagnostic_handler,
                                        Rc::new(CodeMap::new(FilePathMapping::empty())),
                                        cstore.clone());
+    #[cfg(feature="llvm")]
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     let input = config::Input::Str {
index b2a38679240102291a755c10aba91df8e5159d8d..c870e200645400d83d089d65a6b4ed2b2461e1ed 100644 (file)
@@ -94,19 +94,19 @@ fn expr_as_rvalue(&mut self,
                 }
                 block.and(Rvalue::UnaryOp(op, arg))
             }
-            ExprKind::Box { value, value_extents } => {
+            ExprKind::Box { value } => {
                 let value = this.hir.mirror(value);
                 let result = this.temp(expr.ty, expr_span);
                 // to start, malloc some memory of suitable type (thus far, uninitialized):
                 let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
                 this.cfg.push_assign(block, source_info, &result, box_);
-                this.in_scope((value_extents, source_info), block, |this| {
+                if let Some(scope) = scope {
                     // schedule a shallow free of that memory, lest we unwind:
-                    this.schedule_box_free(expr_span, value_extents, &result, value.ty);
-                    // initialize the box contents:
-                    unpack!(block = this.into(&result.clone().deref(), block, value));
-                    block.and(Rvalue::Use(Operand::Consume(result)))
-                })
+                    this.schedule_drop(expr_span, scope, &result, value.ty);
+                }
+                // initialize the box contents:
+                unpack!(block = this.into(&result.clone().deref(), block, value));
+                block.and(Rvalue::Use(Operand::Consume(result)))
             }
             ExprKind::Cast { source } => {
                 let source = this.hir.mirror(source);
index cb7b13f1e614c54cea349e2eec89cd80957b79d3..c35f709a528a2f468c09d3ab85a333381df66d20 100644 (file)
@@ -89,9 +89,6 @@
 
 use build::{BlockAnd, BlockAndExtension, Builder, CFG};
 use rustc::middle::region::CodeExtent;
-use rustc::middle::lang_items;
-use rustc::middle::const_val::ConstVal;
-use rustc::ty::subst::{Kind, Subst};
 use rustc::ty::{Ty, TyCtxt};
 use rustc::mir::*;
 use rustc::mir::transform::MirSource;
@@ -127,21 +124,6 @@ pub struct Scope<'tcx> {
     /// end of the vector (top of the stack) first.
     drops: Vec<DropData<'tcx>>,
 
-    /// A scope may only have one associated free, because:
-    ///
-    /// 1. We require a `free` to only be scheduled in the scope of
-    ///    `EXPR` in `box EXPR`;
-    /// 2. It only makes sense to have it translated into the diverge-path.
-    ///
-    /// This kind of drop will be run *after* all the regular drops
-    /// scheduled onto this scope, because drops may have dependencies
-    /// on the allocated memory.
-    ///
-    /// This is expected to go away once `box EXPR` becomes a sugar
-    /// for placement protocol and gets desugared in some earlier
-    /// stage.
-    free: Option<FreeData<'tcx>>,
-
     /// The cache for drop chain on “normal” exit into a particular BasicBlock.
     cached_exits: FxHashMap<(BasicBlock, CodeExtent), BasicBlock>,
 
@@ -181,22 +163,6 @@ enum DropKind {
     Storage
 }
 
-#[derive(Debug)]
-struct FreeData<'tcx> {
-    /// span where free obligation was incurred
-    span: Span,
-
-    /// Lvalue containing the allocated box.
-    value: Lvalue<'tcx>,
-
-    /// type of item for which the box was allocated for (i.e. the T in Box<T>).
-    item_ty: Ty<'tcx>,
-
-    /// The cached block containing code to run the free. The block will also execute all the drops
-    /// in the scope.
-    cached_block: CachedBlock,
-}
-
 #[derive(Clone, Debug)]
 pub struct BreakableScope<'tcx> {
     /// Extent of the loop
@@ -258,9 +224,6 @@ fn invalidate_cache(&mut self, unwind: bool) {
                 cached_block.invalidate();
             }
         }
-        if let Some(ref mut freedata) = self.free {
-            freedata.cached_block.invalidate();
-        }
     }
 
     /// Returns the cached entrypoint for diverging exit from this scope.
@@ -278,8 +241,6 @@ fn cached_block(&self, generator_drop: bool) -> Option<BasicBlock> {
         });
         if let Some(cached_block) = drops.next() {
             Some(cached_block.expect("drop cache is not filled"))
-        } else if let Some(ref data) = self.free {
-            Some(data.cached_block.get(generator_drop).expect("free cache is not filled"))
         } else {
             None
         }
@@ -369,7 +330,6 @@ pub fn push_scope(&mut self, extent: (CodeExtent, SourceInfo)) {
             extent_span: extent.1.span,
             needs_cleanup: false,
             drops: vec![],
-            free: None,
             cached_generator_drop: None,
             cached_exits: FxHashMap()
         });
@@ -420,7 +380,6 @@ pub fn exit_scope(&mut self,
         });
         let len = self.scopes.len();
         assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
-        let tmp = self.get_unit_temp();
 
         // If we are emitting a `drop` statement, we need to have the cached
         // diverge cleanup pads ready in case that drop panics.
@@ -454,13 +413,6 @@ pub fn exit_scope(&mut self,
 
             // End all regions for scopes out of which we are breaking.
             self.cfg.push_end_region(block, extent.1, scope.extent);
-
-            if let Some(ref free_data) = scope.free {
-                let next = self.cfg.start_new_block();
-                let free = build_free(self.hir.tcx(), &tmp, free_data, next);
-                self.cfg.terminate(block, scope.source_info(free_data.span), free);
-                block = next;
-            }
         }
         }
         let scope = &self.scopes[len - scope_count];
@@ -704,36 +656,6 @@ pub fn schedule_drop(&mut self,
         span_bug!(span, "extent {:?} not in scope to drop {:?}", extent, lvalue);
     }
 
-    /// Schedule dropping of a not-yet-fully-initialised box.
-    ///
-    /// This cleanup will only be translated into unwind branch.
-    /// The extent should be for the `EXPR` inside `box EXPR`.
-    /// There may only be one “free” scheduled in any given scope.
-    pub fn schedule_box_free(&mut self,
-                             span: Span,
-                             extent: CodeExtent,
-                             value: &Lvalue<'tcx>,
-                             item_ty: Ty<'tcx>) {
-        for scope in self.scopes.iter_mut().rev() {
-            // See the comment in schedule_drop above. The primary difference is that we invalidate
-            // the unwind blocks unconditionally. That’s because the box free may be considered
-            // outer-most cleanup within the scope.
-            scope.invalidate_cache(true);
-            if scope.extent == extent {
-                assert!(scope.free.is_none(), "scope already has a scheduled free!");
-                scope.needs_cleanup = true;
-                scope.free = Some(FreeData {
-                    span: span,
-                    value: value.clone(),
-                    item_ty: item_ty,
-                    cached_block: CachedBlock::default(),
-                });
-                return;
-            }
-        }
-        span_bug!(span, "extent {:?} not in scope to free {:?}", extent, value);
-    }
-
     // Other
     // =====
     /// Creates a path that performs all required cleanup for unwinding.
@@ -751,7 +673,6 @@ fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> Option<BasicBlock> {
         }
         assert!(!self.scopes.is_empty()); // or `any` above would be false
 
-        let unit_temp = self.get_unit_temp();
         let Builder { ref mut hir, ref mut cfg, ref mut scopes,
                       ref mut cached_resume_block, .. } = *self;
 
@@ -779,13 +700,8 @@ fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> Option<BasicBlock> {
         };
 
         for scope in scopes.iter_mut() {
-            target = build_diverge_scope(hir.tcx(),
-                                         cfg,
-                                         &unit_temp,
-                                         scope.extent_span,
-                                         scope,
-                                         target,
-                                         generator_drop);
+            target = build_diverge_scope(
+                hir.tcx(), cfg, scope.extent_span, scope, target, generator_drop);
         }
         Some(target)
     }
@@ -921,9 +837,8 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
     block.unit()
 }
 
-fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+fn build_diverge_scope<'a, 'gcx, 'tcx>(_tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                        cfg: &mut CFG<'tcx>,
-                                       unit_temp: &Lvalue<'tcx>,
                                        span: Span,
                                        scope: &mut Scope<'tcx>,
                                        mut target: BasicBlock,
@@ -949,19 +864,6 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         scope: visibility_scope
     };
 
-    // Next, build up any free.
-    if let Some(ref mut free_data) = scope.free {
-        target = if let Some(cached_block) = free_data.cached_block.get(generator_drop) {
-            cached_block
-        } else {
-            let into = cfg.start_new_cleanup_block();
-            cfg.terminate(into, source_info(free_data.span),
-                          build_free(tcx, unit_temp, free_data, target));
-            *free_data.cached_block.ref_mut(generator_drop) = Some(into);
-            into
-        };
-    }
-
     // Next, build up the drops. Here we iterate the vector in
     // *forward* order, so that we generate drops[0] first (right to
     // left in diagram above).
@@ -1005,24 +907,3 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
     target
 }
-
-fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                              unit_temp: &Lvalue<'tcx>,
-                              data: &FreeData<'tcx>,
-                              target: BasicBlock)
-                              -> TerminatorKind<'tcx> {
-    let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
-    let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]);
-    TerminatorKind::Call {
-        func: Operand::Constant(box Constant {
-            span: data.span,
-            ty: tcx.type_of(free_func).subst(tcx, substs),
-            literal: Literal::Value {
-                value: ConstVal::Function(free_func, substs),
-            }
-        }),
-        args: vec![Operand::Consume(data.value.clone())],
-        destination: Some((unit_temp.clone(), target)),
-        cleanup: None
-    }
-}
index 24d5aa9e46bf232767ee2d41da9bf17117b03482..890fe3c091ab2f166a62c835b8897d1a6d39c272 100644 (file)
@@ -240,7 +240,7 @@ pub(crate) fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
         let lookup_result = move_data.rev_lookup.find(&lvalue);
         on_lookup_result_bits(tcx, mir, move_data,
                               lookup_result,
-                              |moi| callback(moi, DropFlagState::Present));
+                              |mpi| callback(mpi, DropFlagState::Present));
     }
 }
 
@@ -270,7 +270,7 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>(
 
         on_all_children_bits(tcx, mir, move_data,
                              path,
-                             |moi| callback(moi, DropFlagState::Absent))
+                             |mpi| callback(mpi, DropFlagState::Absent))
     }
 
     let block = &mir[loc.block];
@@ -279,11 +279,21 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>(
             mir::StatementKind::SetDiscriminant{ .. } => {
                 span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck");
             }
-            mir::StatementKind::Assign(ref lvalue, _) => {
-                debug!("drop_flag_effects: assignment {:?}", stmt);
-                 on_lookup_result_bits(tcx, mir, move_data,
-                                       move_data.rev_lookup.find(lvalue),
-                                       |moi| callback(moi, DropFlagState::Present))
+            mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
+                match rvalue.initialization_state() {
+                    mir::tcx::RvalueInitializationState::Shallow => {
+                        debug!("drop_flag_effects: box assignment {:?}", stmt);
+                        if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(lvalue) {
+                            callback(mpi, DropFlagState::Present);
+                        }
+                    }
+                    mir::tcx::RvalueInitializationState::Deep => {
+                        debug!("drop_flag_effects: assignment {:?}", stmt);
+                        on_lookup_result_bits(tcx, mir, move_data,
+                                              move_data.rev_lookup.find(lvalue),
+                                              |mpi| callback(mpi, DropFlagState::Present))
+                    }
+                }
             }
             mir::StatementKind::StorageLive(_) |
             mir::StatementKind::StorageDead(_) |
@@ -298,7 +308,7 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>(
                 mir::TerminatorKind::DropAndReplace { ref location, .. } => {
                     on_lookup_result_bits(tcx, mir, move_data,
                                           move_data.rev_lookup.find(location),
-                                          |moi| callback(moi, DropFlagState::Present))
+                                          |mpi| callback(mpi, DropFlagState::Present))
                 }
                 _ => {
                     // other terminators do not contain move-ins
index d5bdc71a705c5da5954ea8eb2f5a9ae1ede27759..d68e64abe4f2ddf0f1ca4693f18d7bce2ff8ef2e 100644 (file)
@@ -23,6 +23,7 @@
 use util::elaborate_drops::DropFlagState;
 
 use super::move_paths::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex};
+use super::move_paths::LookupResult;
 use super::{BitDenotation, BlockSets, DataflowOperator};
 
 use super::drop_flag_effects_for_function_entry;
@@ -469,18 +470,30 @@ fn statement_effect(&self,
             mir::StatementKind::SetDiscriminant { .. } => {
                 span_bug!(stmt.source_info.span, "SetDiscriminant should not exist in borrowck");
             }
-            mir::StatementKind::Assign(ref lvalue, _) => {
+            mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
                 // assigning into this `lvalue` kills all
                 // MoveOuts from it, and *also* all MoveOuts
                 // for children and associated fragment sets.
-                on_lookup_result_bits(tcx,
-                                     mir,
-                                     move_data,
-                                     rev_lookup.find(lvalue),
-                                     |mpi| for moi in &path_map[mpi] {
-                                         assert!(moi.index() < bits_per_block);
-                                         sets.kill_set.add(&moi);
-                                     });
+                match rvalue.initialization_state() {
+                    mir::tcx::RvalueInitializationState::Shallow => {
+                        if let LookupResult::Exact(mpi) = rev_lookup.find(lvalue) {
+                             for moi in &path_map[mpi] {
+                                 assert!(moi.index() < bits_per_block);
+                                 sets.kill_set.add(&moi);
+                             }
+                        }
+                    }
+                    mir::tcx::RvalueInitializationState::Deep => {
+                        on_lookup_result_bits(tcx,
+                                              mir,
+                                              move_data,
+                                              rev_lookup.find(lvalue),
+                                              |mpi| for moi in &path_map[mpi] {
+                                                  assert!(moi.index() < bits_per_block);
+                                                  sets.kill_set.add(&moi);
+                                              });
+                    }
+                }
             }
             mir::StatementKind::StorageLive(_) |
             mir::StatementKind::StorageDead(_) |
index f67891d54fda3f568b16ba3863f66f601f78e7e5..01ce77bce13c11dec77b5af490a1dc4ac31784d9 100644 (file)
@@ -11,6 +11,7 @@
 
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
+use rustc::mir::tcx::RvalueInitializationState;
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_vec::{IndexVec};
 
@@ -406,6 +407,12 @@ fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) {
         match stmt.kind {
             StatementKind::Assign(ref lval, ref rval) => {
                 self.create_move_path(lval);
+                if let RvalueInitializationState::Shallow = rval.initialization_state() {
+                    // Box starts out uninitialized - need to create a separate
+                    // move-path for the interior so it will be separate from
+                    // the exterior.
+                    self.create_move_path(&lval.clone().deref());
+                }
                 self.gather_rvalue(loc, rval);
             }
             StatementKind::StorageLive(_) |
index b8b69382d7d0de32eb7e183be090f6daa92232e1..231e2fb68e65ca175234389f56f42a59cf9c1348 100644 (file)
@@ -561,7 +561,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprBox(ref value) => {
             ExprKind::Box {
                 value: value.to_ref(),
-                value_extents: CodeExtent::Misc(value.id),
             }
         }
         hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() },
index 89d0260fb9f5dd14d92ad10a9e6a9e6b6734c322..073b32ae7fa321a7b7d3963bf52084fe810664aa 100644 (file)
@@ -116,7 +116,6 @@ pub enum ExprKind<'tcx> {
     },
     Box {
         value: ExprRef<'tcx>,
-        value_extents: CodeExtent,
     },
     Call {
         ty: ty::Ty<'tcx>,
index ed9321cc3f3a1197dd97f45703cdfd53ebd50080..4a92a5798604af01b25330400c3873acc0b0a3ea 100644 (file)
@@ -26,6 +26,7 @@ rustc_errors = { path = "../librustc_errors" }
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_llvm = { path = "../librustc_llvm" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
+rustc_trans_utils = { path = "../librustc_trans_utils" }
 serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
index 5e85771217b95e0253e99c6287a2a152bea43ece..a9bd8ea90109e24316c7b4a150802d389c36a95b 100644 (file)
@@ -8,16 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+extern crate rustc_trans_utils;
+
 use super::archive::{ArchiveBuilder, ArchiveConfig};
 use super::linker::Linker;
 use super::rpath::RPathConfig;
 use super::rpath;
 use metadata::METADATA_FILENAME;
-use rustc::session::config::{self, NoDebugInfo, OutputFilenames, Input, OutputType};
+use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType};
 use rustc::session::filesearch;
 use rustc::session::search_paths::PathKind;
 use rustc::session::Session;
-use rustc::middle::cstore::{self, LinkMeta, NativeLibrary, LibSource, LinkagePreference,
+use rustc::middle::cstore::{LinkMeta, NativeLibrary, LibSource, LinkagePreference,
                             NativeLibraryKind};
 use rustc::middle::dependency_format::Linkage;
 use CrateTranslation;
@@ -44,9 +46,7 @@
 use std::str;
 use flate2::Compression;
 use flate2::write::DeflateEncoder;
-use syntax::ast;
 use syntax::attr;
-use syntax_pos::Span;
 
 /// The LLVM module name containing crate-metadata. This includes a `.` on
 /// purpose, so it cannot clash with the name of a user-defined module.
 pub const RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET: usize =
     RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET + 8;
 
-
-pub fn find_crate_name(sess: Option<&Session>,
-                       attrs: &[ast::Attribute],
-                       input: &Input) -> String {
-    let validate = |s: String, span: Option<Span>| {
-        cstore::validate_crate_name(sess, &s, span);
-        s
-    };
-
-    // Look in attributes 100% of the time to make sure the attribute is marked
-    // as used. After doing this, however, we still prioritize a crate name from
-    // the command line over one found in the #[crate_name] attribute. If we
-    // find both we ensure that they're the same later on as well.
-    let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
-                               .and_then(|at| at.value_str().map(|s| (at, s)));
-
-    if let Some(sess) = sess {
-        if let Some(ref s) = sess.opts.crate_name {
-            if let Some((attr, name)) = attr_crate_name {
-                if name != &**s {
-                    let msg = format!("--crate-name and #[crate_name] are \
-                                       required to match, but `{}` != `{}`",
-                                      s, name);
-                    sess.span_err(attr.span, &msg);
-                }
-            }
-            return validate(s.clone(), None);
-        }
-    }
-
-    if let Some((attr, s)) = attr_crate_name {
-        return validate(s.to_string(), Some(attr.span));
-    }
-    if let Input::File(ref path) = *input {
-        if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
-            if s.starts_with("-") {
-                let msg = format!("crate names cannot start with a `-`, but \
-                                   `{}` has a leading hyphen", s);
-                if let Some(sess) = sess {
-                    sess.err(&msg);
-                }
-            } else {
-                return validate(s.replace("-", "_"), None);
-            }
-        }
-    }
-
-    "rust_out".to_string()
-}
+pub use self::rustc_trans_utils::link::{find_crate_name, filename_for_input,
+                                        default_output_for_target, invalid_output_for_target};
 
 pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMeta {
     let krate_dep_node = &DepNode::new_no_params(DepKind::Krate);
@@ -252,37 +205,6 @@ pub fn link_binary(sess: &Session,
     out_filenames
 }
 
-
-/// Returns default crate type for target
-///
-/// Default crate type is used when crate type isn't provided neither
-/// through cmd line arguments nor through crate attributes
-///
-/// It is CrateTypeExecutable for all platforms but iOS as there is no
-/// way to run iOS binaries anyway without jailbreaking and
-/// interaction with Rust code through static library is the only
-/// option for now
-pub fn default_output_for_target(sess: &Session) -> config::CrateType {
-    if !sess.target.target.options.executables {
-        config::CrateTypeStaticlib
-    } else {
-        config::CrateTypeExecutable
-    }
-}
-
-/// Checks if target supports crate_type as output
-pub fn invalid_output_for_target(sess: &Session,
-                                 crate_type: config::CrateType) -> bool {
-    match (sess.target.target.options.dynamic_linking,
-           sess.target.target.options.executables, crate_type) {
-        (false, _, config::CrateTypeCdylib) |
-        (false, _, config::CrateTypeProcMacro) |
-        (false, _, config::CrateTypeDylib) => true,
-        (_, false, config::CrateTypeExecutable) => true,
-        _ => false
-    }
-}
-
 fn is_writeable(p: &Path) -> bool {
     match p.metadata() {
         Err(..) => true,
@@ -299,42 +221,6 @@ fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilen
     out_filename
 }
 
-pub fn filename_for_input(sess: &Session,
-                          crate_type: config::CrateType,
-                          crate_name: &str,
-                          outputs: &OutputFilenames) -> PathBuf {
-    let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
-
-    match crate_type {
-        config::CrateTypeRlib => {
-            outputs.out_directory.join(&format!("lib{}.rlib", libname))
-        }
-        config::CrateTypeCdylib |
-        config::CrateTypeProcMacro |
-        config::CrateTypeDylib => {
-            let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
-                                    &sess.target.target.options.dll_suffix);
-            outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
-                                                suffix))
-        }
-        config::CrateTypeStaticlib => {
-            let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix,
-                                    &sess.target.target.options.staticlib_suffix);
-            outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
-                                                suffix))
-        }
-        config::CrateTypeExecutable => {
-            let suffix = &sess.target.target.options.exe_suffix;
-            let out_filename = outputs.path(OutputType::Exe);
-            if suffix.is_empty() {
-                out_filename.to_path_buf()
-            } else {
-                out_filename.with_extension(&suffix[1..])
-            }
-        }
-    }
-}
-
 pub fn each_linked_rlib(sess: &Session,
                         f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> {
     let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter();
index 0d5fe6c0ae95fa3dffc45dc711098e4e490c6be7..94cae37761fe2bf36cd54e6246eedb10392f2c78 100644 (file)
@@ -1356,6 +1356,16 @@ fn start_executing_work(sess: &Session,
                             maybe_start_llvm_timer(&item, &mut llvm_start_time);
                             main_thread_worker_state = MainThreadWorkerState::LLVMing;
                             spawn_work(cgcx, item);
+                        } else {
+                            // There is no unstarted work, so let the main thread
+                            // take over for a running worker. Otherwise the
+                            // implicit token would just go to waste.
+                            // We reduce the `running` counter by one. The
+                            // `tokens.truncate()` below will take care of
+                            // giving the Token back.
+                            debug_assert!(running > 0);
+                            running -= 1;
+                            main_thread_worker_state = MainThreadWorkerState::LLVMing;
                         }
                     }
                     MainThreadWorkerState::Translating => {
diff --git a/src/librustc_trans_utils/Cargo.toml b/src/librustc_trans_utils/Cargo.toml
new file mode 100644 (file)
index 0000000..f026d4f
--- /dev/null
@@ -0,0 +1,15 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_trans_utils"
+version = "0.0.0"
+
+[lib]
+name = "rustc_trans_utils"
+path = "lib.rs"
+crate-type = ["dylib"]
+test = false
+
+[dependencies]
+rustc = { path = "../librustc" }
+syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs
new file mode 100644 (file)
index 0000000..81e8307
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![crate_name = "rustc_trans_utils"]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+      html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![deny(warnings)]
+
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(const_fn)]
+#![feature(custom_attribute)]
+#![allow(unused_attributes)]
+#![feature(i128_type)]
+#![feature(quote)]
+#![feature(rustc_diagnostic_macros)]
+#![feature(slice_patterns)]
+#![feature(conservative_impl_trait)]
+
+extern crate rustc;
+extern crate syntax;
+extern crate syntax_pos;
+
+pub mod link;
diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_trans_utils/link.rs
new file mode 100644 (file)
index 0000000..29bb062
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::session::config::{self, /*NoDebugInfo,*/ OutputFilenames, Input, OutputType};
+/*use rustc::session::filesearch;
+use rustc::session::search_paths::PathKind;
+*/use rustc::session::Session;
+use rustc::middle::cstore;/*::{self, LinkMeta, NativeLibrary, LibSource, LinkagePreference,
+                            NativeLibraryKind};*/
+/*use rustc::middle::dependency_format::Linkage;
+use rustc::util::common::time;
+use rustc::util::fs::fix_windows_verbatim_for_gcc;
+use rustc::dep_graph::{DepKind, DepNode};
+use rustc::hir::def_id::CrateNum;
+use rustc::hir::svh::Svh;
+use rustc_back::tempdir::TempDir;
+use rustc_back::{PanicStrategy, RelroLevel};
+use rustc_incremental::IncrementalHashesMap;*/
+
+/*use std::ascii;
+use std::char;
+use std::env;
+use std::ffi::OsString;
+use std::fs;
+use std::io::{self, Read, Write};
+use std::mem;
+*/use std::path::PathBuf;/*{Path, PathBuf};
+use std::process::Command;
+use std::str;*/
+use syntax::ast;
+//use syntax::attr;
+use syntax_pos::Span;
+
+pub fn find_crate_name(sess: Option<&Session>,
+                       attrs: &[ast::Attribute],
+                       input: &Input) -> String {
+    let validate = |s: String, span: Option<Span>| {
+        cstore::validate_crate_name(sess, &s, span);
+        s
+    };
+
+    // Look in attributes 100% of the time to make sure the attribute is marked
+    // as used. After doing this, however, we still prioritize a crate name from
+    // the command line over one found in the #[crate_name] attribute. If we
+    // find both we ensure that they're the same later on as well.
+    let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
+                               .and_then(|at| at.value_str().map(|s| (at, s)));
+
+    if let Some(sess) = sess {
+        if let Some(ref s) = sess.opts.crate_name {
+            if let Some((attr, name)) = attr_crate_name {
+                if name != &**s {
+                    let msg = format!("--crate-name and #[crate_name] are \
+                                       required to match, but `{}` != `{}`",
+                                      s, name);
+                    sess.span_err(attr.span, &msg);
+                }
+            }
+            return validate(s.clone(), None);
+        }
+    }
+
+    if let Some((attr, s)) = attr_crate_name {
+        return validate(s.to_string(), Some(attr.span));
+    }
+    if let Input::File(ref path) = *input {
+        if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
+            if s.starts_with("-") {
+                let msg = format!("crate names cannot start with a `-`, but \
+                                   `{}` has a leading hyphen", s);
+                if let Some(sess) = sess {
+                    sess.err(&msg);
+                }
+            } else {
+                return validate(s.replace("-", "_"), None);
+            }
+        }
+    }
+
+    "rust_out".to_string()
+}
+
+pub fn filename_for_input(sess: &Session,
+                          crate_type: config::CrateType,
+                          crate_name: &str,
+                          outputs: &OutputFilenames) -> PathBuf {
+    let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
+
+    match crate_type {
+        config::CrateTypeRlib => {
+            outputs.out_directory.join(&format!("lib{}.rlib", libname))
+        }
+        config::CrateTypeCdylib |
+        config::CrateTypeProcMacro |
+        config::CrateTypeDylib => {
+            let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
+                                    &sess.target.target.options.dll_suffix);
+            outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
+                                                suffix))
+        }
+        config::CrateTypeStaticlib => {
+            let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix,
+                                    &sess.target.target.options.staticlib_suffix);
+            outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
+                                                suffix))
+        }
+        config::CrateTypeExecutable => {
+            let suffix = &sess.target.target.options.exe_suffix;
+            let out_filename = outputs.path(OutputType::Exe);
+            if suffix.is_empty() {
+                out_filename.to_path_buf()
+            } else {
+                out_filename.with_extension(&suffix[1..])
+            }
+        }
+    }
+}
+
+/// Returns default crate type for target
+///
+/// Default crate type is used when crate type isn't provided neither
+/// through cmd line arguments nor through crate attributes
+///
+/// It is CrateTypeExecutable for all platforms but iOS as there is no
+/// way to run iOS binaries anyway without jailbreaking and
+/// interaction with Rust code through static library is the only
+/// option for now
+pub fn default_output_for_target(sess: &Session) -> config::CrateType {
+    if !sess.target.target.options.executables {
+        config::CrateTypeStaticlib
+    } else {
+        config::CrateTypeExecutable
+    }
+}
+
+/// Checks if target supports crate_type as output
+pub fn invalid_output_for_target(sess: &Session,
+                                 crate_type: config::CrateType) -> bool {
+    match (sess.target.target.options.dynamic_linking,
+           sess.target.target.options.executables, crate_type) {
+        (false, _, config::CrateTypeCdylib) |
+        (false, _, config::CrateTypeProcMacro) |
+        (false, _, config::CrateTypeDylib) => true,
+        (_, false, config::CrateTypeExecutable) => true,
+        _ => false
+    }
+}
index 4452f4a2f446bb804b1f3a82085a1ecd529d88ac..d185c061d5bd9fb6656b7240de820824447d2137 100644 (file)
@@ -15,3 +15,4 @@ rustc_driver = { path = "../librustc_driver" }
 
 [features]
 jemalloc = ["rustc_back/jemalloc"]
+llvm = ["rustc_driver/llvm"]
index bfb1b3b65289034f5e3c435512ce1e60bf188987..0b34231b4eec6b0fc84ce5752619e1466f1a3427 100644 (file)
@@ -34,10 +34,9 @@ fn foo(i: i32) {
 //     let _1: D;
 //     let _2: i32;
 //     let _3: &'6_2rce i32;
-//     let _7: &'6_4rce i32;
+//     let _6: &'6_4rce i32;
 //     let mut _4: ();
 //     let mut _5: i32;
-//     let mut _6: ();
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
@@ -51,10 +50,10 @@ fn foo(i: i32) {
 //     }
 //     bb1: {
 //         StorageDead(_5);
-//         StorageLive(_7);
-//         _7 = &'6_4rce _2;
+//         StorageLive(_6);
+//         _6 = &'6_4rce _2;
 //         _0 = ();
-//         StorageDead(_7);
+//         StorageDead(_6);
 //         EndRegion('6_4rce);
 //         StorageDead(_3);
 //         EndRegion('6_2rce);
index 773a348a939770cb61dcbb2b26bdd7b8a2c6f6f3..e51bb9350db60520aa52886a4f811606c84ffec5 100644 (file)
@@ -33,7 +33,6 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _2: ();
 //     let mut _3: [closure@NodeId(18) d:&'19mce D];
 //     let mut _4: &'19mce D;
-//     let mut _5: ();
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
index 112c93843e042e4691267ffba357eb661aaf4d8c..c55e6d105cbdc3fe9c8d4c5ba83ca1568f172731 100644 (file)
@@ -33,7 +33,6 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _2: ();
 //     let mut _3: [closure@NodeId(22) d:&'23mce D];
 //     let mut _4: &'23mce D;
-//     let mut _5: ();
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
index 913986ae816a65024890c6230095cf2e0390632b..9c8e3ec08d498956b271f04d2e54ef62e85f3011 100644 (file)
@@ -33,7 +33,6 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _2: ();
 //     let mut _3: [closure@NodeId(22) d:D];
 //     let mut _4: D;
-//     let mut _5: ();
 //
 //     bb0: {
 //         StorageLive(_1);
@@ -77,7 +76,6 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _0: i32;
 //     let _2: &'14_0rce D;
 //     let mut _3: i32;
-//     let mut _4: ();
 //
 //     bb0: {
 //         StorageLive(_2);
index dc8f8ea11f51c5d2a263d1702bc32607b87317a2..b4dbec5cd2dd7ec5e159feb418640a8459f54303 100644 (file)
@@ -35,7 +35,6 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //    let mut _3: ();
 //    let mut _4: [closure@NodeId(22) r:&'6_1rce D];
 //    let mut _5: &'6_1rce D;
-//    let mut _6: ();
 //    bb0: {
 //        StorageLive(_1);
 //        _1 = D::{{constructor}}(const 0i32,);
index 1daa18256dceec73615a4a01263c89dc168e7bac..3a8b5c449c22ad7fe94d8c633be20a6fa24aa10d 100644 (file)
@@ -39,8 +39,7 @@ fn other(self, s: Self) {}
 //    let mut _2: S;
 //    let mut _3: S;
 //    let mut _4: S;
-//    let mut _5: ();
-//    let mut _6: bool;
+//    let mut _5: bool;
 //
 //    bb0: {
 // END rustc.node4.ElaborateDrops.after.mir
@@ -50,9 +49,8 @@ fn other(self, s: Self) {}
 //    let mut _2: S;
 //    let mut _3: ();
 //    let mut _4: S;
-//    let mut _5: ();
-//    let mut _6: S;
-//    let mut _7: bool;
+//    let mut _5: S;
+//    let mut _6: bool;
 //
 //    bb0: {
 // END rustc.node13.ElaborateDrops.after.mir
index bdcd3eecc696a6ffdc35805aeedc9ce21cdb3101..1aba47af1e9dca30f48f8f877da20e840bff37b0 100644 (file)
@@ -161,6 +161,11 @@ fn vec_simple(a: &Allocator) {
     let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
 }
 
+#[allow(unreachable_code)]
+fn vec_unreachable(a: &Allocator) {
+    let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
+}
+
 fn run_test<F>(mut f: F)
     where F: FnMut(&Allocator)
 {
@@ -209,6 +214,7 @@ fn main() {
 
     run_test(|a| array_simple(a));
     run_test(|a| vec_simple(a));
+    run_test(|a| vec_unreachable(a));
 
     run_test(|a| struct_dynamic_drop(a, false, false, false));
     run_test(|a| struct_dynamic_drop(a, false, false, true));