]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #44374 - jsheard:threadname, r=alexcrichton
authorCorey Farwell <coreyf@rwell.org>
Fri, 15 Sep 2017 02:32:34 +0000 (22:32 -0400)
committerGitHub <noreply@github.com>
Fri, 15 Sep 2017 02:32:34 +0000 (22:32 -0400)
Implement named threads on Windows (v2)

https://msdn.microsoft.com/en-us/library/windows/desktop/mt774976(v=vs.85).aspx

Windows 10 version 1607 finally added a sensible API for naming threads, so we can now implement named threads without having to use MSVC compiler extensions like before. VS2017s debugger and the WPA profiler already use this API where available, but other tools may need some time to catch up.

![thread](https://user-images.githubusercontent.com/3153547/30133438-c92a3cda-934b-11e7-9668-915d53e8d860.png)

26 files changed:
src/bootstrap/native.rs
src/librustc/hir/lowering.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc_data_structures/bitslice.rs
src/librustc_data_structures/indexed_set.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/test.rs
src/librustc_incremental/lib.rs
src/librustc_incremental/persist/fs.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_incremental/persist/work_product.rs
src/librustc_mir/dataflow/impls/mod.rs
src/librustc_mir/dataflow/impls/storage_liveness.rs [new file with mode: 0644]
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/transform/generator.rs
src/librustc_trans/back/write.rs
src/librustdoc/core.rs
src/librustdoc/html/render.rs
src/librustdoc/test.rs
src/test/run-make/issue-19371/foo.rs
src/test/run-pass/generator/match-bindings.rs [new file with mode: 0644]
src/test/rustdoc/const-fn.rs [new file with mode: 0644]

index 2cbae083fc464bd7610d825fcb72e3e5e41e8c95..a2c436627f6da0c360618ec4dc997d2dac04ad15 100644 (file)
@@ -389,7 +389,8 @@ fn run(self, builder: &Builder) {
         drop(fs::remove_dir_all(&dst));
         build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));
 
-        let mut configure = Command::new(obj.join("Configure"));
+        let mut configure = Command::new("perl");
+        configure.arg(obj.join("Configure"));
         configure.arg(format!("--prefix={}", dst.display()));
         configure.arg("no-dso");
         configure.arg("no-ssl2");
index bae419da26c58839e44bf087cf222ba563806c6f..113a5d0e5e96e28d72f7ffefcb3b6224c132126b 100644 (file)
@@ -40,6 +40,7 @@
 //! get confused if the spans from leaf AST nodes occur in multiple places
 //! in the HIR, especially for multiple identifiers.
 
+use dep_graph::DepGraph;
 use hir;
 use hir::map::{Definitions, DefKey};
 use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
@@ -122,13 +123,14 @@ pub trait Resolver {
 
 pub fn lower_crate(sess: &Session,
                    cstore: &CrateStore,
+                   dep_graph: &DepGraph,
                    krate: &Crate,
                    resolver: &mut Resolver)
                    -> hir::Crate {
     // We're constructing the HIR here; we don't care what we will
     // read, since we haven't even constructed the *input* to
     // incr. comp. yet.
-    let _ignore = sess.dep_graph.in_ignore();
+    let _ignore = dep_graph.in_ignore();
 
     LoweringContext {
         crate_root: std_inject::injected_crate_name(krate),
index 59f600f39077c33e53cdad551b39b5d5bc8b4afd..df2de17f1e4711409610e76c9a49a87217dfabbb 100644 (file)
@@ -1949,7 +1949,6 @@ pub fn stable_hash(sub_hashes: BTreeMap<&'static str, &DepTrackingHash>,
 
 #[cfg(test)]
 mod tests {
-    use dep_graph::DepGraph;
     use errors;
     use getopts;
     use lint;
@@ -1982,7 +1981,6 @@ fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
     // When the user supplies --test we should implicitly supply --cfg test
     #[test]
     fn test_switch_implies_cfg_test() {
-        let dep_graph = DepGraph::new(false);
         let matches =
             &match optgroups().parse(&["--test".to_string()]) {
               Ok(m) => m,
@@ -1990,7 +1988,7 @@ fn test_switch_implies_cfg_test() {
             };
         let registry = errors::registry::Registry::new(&[]);
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-        let sess = build_session(sessopts, &dep_graph, None, registry);
+        let sess = build_session(sessopts, None, registry);
         let cfg = build_configuration(&sess, cfg);
         assert!(cfg.contains(&(Symbol::intern("test"), None)));
     }
@@ -1999,7 +1997,6 @@ fn test_switch_implies_cfg_test() {
     // another --cfg test
     #[test]
     fn test_switch_implies_cfg_test_unless_cfg_test() {
-        let dep_graph = DepGraph::new(false);
         let matches =
             &match optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]) {
               Ok(m) => m,
@@ -2009,7 +2006,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
             };
         let registry = errors::registry::Registry::new(&[]);
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-        let sess = build_session(sessopts, &dep_graph, None, registry);
+        let sess = build_session(sessopts, None, registry);
         let cfg = build_configuration(&sess, cfg);
         let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
         assert!(test_items.next().is_some());
@@ -2018,14 +2015,13 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
 
     #[test]
     fn test_can_print_warnings() {
-        let dep_graph = DepGraph::new(false);
         {
             let matches = optgroups().parse(&[
                 "-Awarnings".to_string()
             ]).unwrap();
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, &dep_graph, None, registry);
+            let sess = build_session(sessopts, None, registry);
             assert!(!sess.diagnostic().can_emit_warnings);
         }
 
@@ -2036,7 +2032,7 @@ fn test_can_print_warnings() {
             ]).unwrap();
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, &dep_graph, None, registry);
+            let sess = build_session(sessopts, None, registry);
             assert!(sess.diagnostic().can_emit_warnings);
         }
 
@@ -2046,7 +2042,7 @@ fn test_can_print_warnings() {
             ]).unwrap();
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, &dep_graph, None, registry);
+            let sess = build_session(sessopts, None, registry);
             assert!(sess.diagnostic().can_emit_warnings);
         }
     }
index 1f9cb2b03100fba2fec8d091d2c3b554e2bed528..df5a2648e270ce92b6e517c109911e830fec4242 100644 (file)
@@ -11,7 +11,6 @@
 pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
 pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
 
-use dep_graph::DepGraph;
 use hir::def_id::{CrateNum, DefIndex};
 
 use lint;
@@ -58,7 +57,6 @@
 // Represents the data associated with a compilation
 // session for a single crate.
 pub struct Session {
-    pub dep_graph: DepGraph,
     pub target: config::Config,
     pub host: Target,
     pub opts: config::Options,
@@ -91,7 +89,7 @@ pub struct Session {
     // forms a unique global identifier for the crate. It is used to allow
     // multiple crates with the same name to coexist. See the
     // trans::back::symbol_names module for more information.
-    pub crate_disambiguator: RefCell<Symbol>,
+    pub crate_disambiguator: RefCell<Option<Symbol>>,
     pub features: RefCell<feature_gate::Features>,
 
     /// The maximum recursion limit for potentially infinitely recursive
@@ -169,7 +167,10 @@ enum DiagnosticBuilderMethod {
 
 impl Session {
     pub fn local_crate_disambiguator(&self) -> Symbol {
-        *self.crate_disambiguator.borrow()
+        match *self.crate_disambiguator.borrow() {
+            Some(sym) => sym,
+            None => bug!("accessing disambiguator before initialization"),
+        }
     }
     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
                                                     sp: S,
@@ -501,9 +502,29 @@ pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
             kind)
     }
 
+    pub fn set_incr_session_load_dep_graph(&self, load: bool) {
+        let mut incr_comp_session = self.incr_comp_session.borrow_mut();
+
+        match *incr_comp_session {
+            IncrCompSession::Active { ref mut load_dep_graph, .. } => {
+                *load_dep_graph = load;
+            }
+            _ => {}
+        }
+    }
+
+    pub fn incr_session_load_dep_graph(&self) -> bool {
+        let incr_comp_session = self.incr_comp_session.borrow();
+        match *incr_comp_session {
+            IncrCompSession::Active { load_dep_graph, .. } => load_dep_graph,
+            _ => false,
+        }
+    }
+
     pub fn init_incr_comp_session(&self,
                                   session_dir: PathBuf,
-                                  lock_file: flock::Lock) {
+                                  lock_file: flock::Lock,
+                                  load_dep_graph: bool) {
         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
 
         if let IncrCompSession::NotInitialized = *incr_comp_session { } else {
@@ -513,6 +534,7 @@ pub fn init_incr_comp_session(&self,
         *incr_comp_session = IncrCompSession::Active {
             session_directory: session_dir,
             lock_file,
+            load_dep_graph,
         };
     }
 
@@ -617,14 +639,12 @@ pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -
 }
 
 pub fn build_session(sopts: config::Options,
-                     dep_graph: &DepGraph,
                      local_crate_source_file: Option<PathBuf>,
                      registry: errors::registry::Registry)
                      -> Session {
     let file_path_mapping = sopts.file_path_mapping();
 
     build_session_with_codemap(sopts,
-                               dep_graph,
                                local_crate_source_file,
                                registry,
                                Rc::new(codemap::CodeMap::new(file_path_mapping)),
@@ -632,7 +652,6 @@ pub fn build_session(sopts: config::Options,
 }
 
 pub fn build_session_with_codemap(sopts: config::Options,
-                                  dep_graph: &DepGraph,
                                   local_crate_source_file: Option<PathBuf>,
                                   registry: errors::registry::Registry,
                                   codemap: Rc<codemap::CodeMap>,
@@ -672,14 +691,12 @@ pub fn build_session_with_codemap(sopts: config::Options,
                                       emitter);
 
     build_session_(sopts,
-                   dep_graph,
                    local_crate_source_file,
                    diagnostic_handler,
                    codemap)
 }
 
 pub fn build_session_(sopts: config::Options,
-                      dep_graph: &DepGraph,
                       local_crate_source_file: Option<PathBuf>,
                       span_diagnostic: errors::Handler,
                       codemap: Rc<codemap::CodeMap>)
@@ -715,7 +732,6 @@ pub fn build_session_(sopts: config::Options,
     let working_dir = file_path_mapping.map_prefix(working_dir);
 
     let sess = Session {
-        dep_graph: dep_graph.clone(),
         target: target_cfg,
         host,
         opts: sopts,
@@ -735,7 +751,7 @@ pub fn build_session_(sopts: config::Options,
         plugin_attributes: RefCell::new(Vec::new()),
         crate_types: RefCell::new(Vec::new()),
         dependency_formats: RefCell::new(FxHashMap()),
-        crate_disambiguator: RefCell::new(Symbol::intern("")),
+        crate_disambiguator: RefCell::new(None),
         features: RefCell::new(feature_gate::Features::new()),
         recursion_limit: Cell::new(64),
         type_length_limit: Cell::new(1048576),
@@ -793,6 +809,7 @@ pub enum IncrCompSession {
     Active {
         session_directory: PathBuf,
         lock_file: flock::Lock,
+        load_dep_graph: bool,
     },
     // This is the state after the session directory has been finalized. In this
     // state, the contents of the directory must not be modified any more.
index f74af6ee1632e793f8f6fef0922f9262443e2eb1..7665bfd5b1117316c0a758338ad103adca34e2b5 100644 (file)
@@ -132,6 +132,11 @@ pub trait BitwiseOperator {
     fn join(&self, pred1: usize, pred2: usize) -> usize;
 }
 
+pub struct Intersect;
+impl BitwiseOperator for Intersect {
+    #[inline]
+    fn join(&self, a: usize, b: usize) -> usize { a & b }
+}
 pub struct Union;
 impl BitwiseOperator for Union {
     #[inline]
index 47fa21e3bf0b2bf6a1e47f4d6c78b94c1aca9246..c790463e47adb4f2ce3e897c2229e22dc9f7d88f 100644 (file)
@@ -15,7 +15,7 @@
 use std::ops::{Deref, DerefMut, Range};
 use std::slice;
 use bitslice::{BitSlice, Word};
-use bitslice::{bitwise, Union, Subtract};
+use bitslice::{bitwise, Union, Subtract, Intersect};
 use indexed_vec::Idx;
 
 /// Represents a set (or packed family of sets), of some element type
@@ -164,6 +164,10 @@ pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
         bitwise(self.words_mut(), other.words(), &Subtract)
     }
 
+    pub fn intersect(&mut self, other: &IdxSet<T>) -> bool {
+        bitwise(self.words_mut(), other.words(), &Intersect)
+    }
+
     pub fn iter(&self) -> Iter<T> {
         Iter {
             cur: None,
index c41d5beec6877ab61570ae2f6fcfa17601e1b080..ed012f87996d7a10ba3824ded6ffa76becff2295 100644 (file)
@@ -10,6 +10,7 @@
 
 #![cfg_attr(not(feature="llvm"), allow(dead_code))]
 
+use rustc::dep_graph::DepGraph;
 use rustc::hir::{self, map as hir_map};
 use rustc::hir::lowering::lower_crate;
 use rustc::ich::Fingerprint;
@@ -115,7 +116,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): (OutputFilenames, OngoingCrateTranslation) = {
+    let (outputs, trans, dep_graph): (OutputFilenames, OngoingCrateTranslation, DepGraph) = {
         let krate = match phase_1_parse_input(control, sess, input) {
             Ok(krate) => krate,
             Err(mut parse_error) => {
@@ -144,7 +145,13 @@ macro_rules! controller_entry_point {
             ::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,
+                sess,
+                &cstore,
+                krate,
+                registry,
+                &crate_name,
+                addl_plugins,
+                control.make_glob_map,
                 |expanded_crate| {
                     let mut state = CompileState::state_after_expand(
                         input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
@@ -251,7 +258,7 @@ macro_rules! controller_entry_point {
                 }
             }
 
-            Ok((outputs, trans))
+            Ok((outputs, trans, tcx.dep_graph.clone()))
         })??
     };
 
@@ -266,7 +273,7 @@ macro_rules! controller_entry_point {
             sess.code_stats.borrow().print_type_sizes();
         }
 
-        let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
+        let (phase5_result, trans) = phase_5_run_llvm_passes(sess, &dep_graph, trans);
 
         controller_entry_point!(after_llvm,
                                 sess,
@@ -624,7 +631,15 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
     *sess.features.borrow_mut() = features;
 
     *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
-    *sess.crate_disambiguator.borrow_mut() = Symbol::intern(&compute_crate_disambiguator(sess));
+
+    let disambiguator = Symbol::intern(&compute_crate_disambiguator(sess));
+    *sess.crate_disambiguator.borrow_mut() = Some(disambiguator);
+    rustc_incremental::prepare_session_directory(
+        sess,
+        &crate_name,
+        &disambiguator.as_str(),
+    );
+    let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
 
     time(time_passes, "recursion limit", || {
         middle::recursion_limit::update_limits(sess, &krate);
@@ -694,7 +709,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
     // item, much like we do for macro expansion. In other words, the hash reflects not just
     // its contents but the results of name resolution on those contents. Hopefully we'll push
     // this back at some point.
-    let _ignore = sess.dep_graph.in_ignore();
+    let _ignore = dep_graph.in_ignore();
     let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name);
     let resolver_arenas = Resolver::arenas();
     let mut resolver = Resolver::new(sess,
@@ -847,13 +862,13 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 
     // Lower ast -> hir.
     let hir_forest = time(time_passes, "lowering ast -> hir", || {
-        let hir_crate = lower_crate(sess, cstore, &krate, &mut resolver);
+        let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver);
 
         if sess.opts.debugging_opts.hir_stats {
             hir_stats::print_hir_stats(&hir_crate);
         }
 
-        hir_map::Forest::new(hir_crate, &sess.dep_graph)
+        hir_map::Forest::new(hir_crate, &dep_graph)
     });
 
     time(time_passes,
@@ -1134,9 +1149,10 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// as a side effect.
 #[cfg(feature="llvm")]
 pub fn phase_5_run_llvm_passes(sess: &Session,
+                               dep_graph: &DepGraph,
                                trans: write::OngoingCrateTranslation)
                                -> (CompileResult, trans::CrateTranslation) {
-    let trans = trans.join(sess);
+    let trans = trans.join(sess, dep_graph);
 
     if sess.opts.debugging_opts.incremental_info {
         write::dump_incremental_data(&trans);
@@ -1144,7 +1160,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 
     time(sess.time_passes(),
          "serialize work products",
-         move || rustc_incremental::save_work_products(sess));
+         move || rustc_incremental::save_work_products(sess, dep_graph));
 
     (sess.compile_status(), trans)
 }
index 099dda17823e67f864b112e437ae8ba72c65ec77..522b9eb22320e9d00bc7f806a32236d80e24c67b 100644 (file)
@@ -64,7 +64,6 @@
 use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::CompileIncomplete;
 use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
@@ -294,13 +293,12 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         },
     };
 
-    let dep_graph = DepGraph::new(sopts.build_dep_graph());
     let cstore = Rc::new(CStore::new(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, codemap, emitter_dest,
+        sopts, input_file_path, descriptions, codemap, emitter_dest,
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
@@ -318,7 +316,13 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
 
     let plugins = sess.opts.debugging_opts.extra_plugins.clone();
     let control = callbacks.build_controller(&sess, &matches);
-    (driver::compile_input(&sess, &cstore, &input, &odir, &ofile, Some(plugins), &control),
+    (driver::compile_input(&sess,
+                           &cstore,
+                           &input,
+                           &odir,
+                           &ofile,
+                           Some(plugins),
+                           &control),
      Some(sess))
 }
 
@@ -580,9 +584,7 @@ fn no_input(&mut self,
                     describe_lints(&ls, false);
                     return None;
                 }
-                let dep_graph = DepGraph::new(sopts.build_dep_graph());
                 let mut sess = build_session(sopts.clone(),
-                    &dep_graph,
                     None,
                     descriptions.clone());
                 rustc_trans::init(&sess);
index d2fb9903683676a5e6b853183108de3d203166c0..d0edcbc326098eb738d0ac37347eb37c11d561fb 100644 (file)
@@ -11,7 +11,6 @@
 //! # Standalone Tests for the Inference Module
 
 use driver;
-use rustc::dep_graph::DepGraph;
 use rustc_lint;
 use rustc_resolve::MakeGlobMap;
 use rustc_trans;
@@ -102,11 +101,8 @@ fn test_env<F>(source_string: &str,
     options.unstable_features = UnstableFeatures::Allow;
     let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
 
-    let dep_graph = DepGraph::new(false);
-    let _ignore = dep_graph.in_ignore();
     let cstore = Rc::new(CStore::new(box ::MetadataLoader));
     let sess = session::build_session_(options,
-                                       &dep_graph,
                                        None,
                                        diagnostic_handler,
                                        Rc::new(CodeMap::new(FilePathMapping::empty())));
@@ -130,7 +126,6 @@ fn test_env<F>(source_string: &str,
                                              |_| Ok(()))
             .expect("phase 2 aborted")
     };
-    let _ignore = dep_graph.in_ignore();
 
     let arena = DroplessArena::new();
     let arenas = ty::GlobalArenas::new();
index 8870033095c9c2a1106ddd91d3d88ca049367cb3..3c1e02f8a5adde4c72a4519cc474b84a833de246 100644 (file)
@@ -40,4 +40,5 @@
 pub use persist::save_trans_partition;
 pub use persist::save_work_products;
 pub use persist::in_incr_comp_dir;
+pub use persist::prepare_session_directory;
 pub use persist::finalize_session_directory;
index 434c82095bd9a98d0e21cbf8a3639d934646202c..f3f35a50fe0b3638a17c774548256328055c5e1d 100644 (file)
 //! unsupported file system and emit a warning in that case. This is not yet
 //! implemented.
 
-use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc::hir::def_id::CrateNum;
 use rustc::hir::svh::Svh;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
@@ -193,13 +193,21 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
 /// a dep-graph and work products from a previous session.
 /// If the call fails, the fn may leave behind an invalid session directory.
 /// The garbage collection will take care of it.
-pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
+pub fn prepare_session_directory(sess: &Session,
+                                 crate_name: &str,
+                                 crate_disambiguator: &str) {
+    if sess.opts.incremental.is_none() {
+        return
+    }
+
     debug!("prepare_session_directory");
 
     // {incr-comp-dir}/{crate-name-and-disambiguator}
-    let crate_dir = crate_path_tcx(tcx, LOCAL_CRATE);
+    let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
     debug!("crate-dir: {}", crate_dir.display());
-    try!(create_dir(tcx.sess, &crate_dir, "crate"));
+    if create_dir(sess, &crate_dir, "crate").is_err() {
+        return
+    }
 
     // Hack: canonicalize the path *after creating the directory*
     // because, on windows, long paths can cause problems;
@@ -208,9 +216,9 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
     let crate_dir = match crate_dir.canonicalize() {
         Ok(v) => v,
         Err(err) => {
-            tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
-                                  crate_dir.display(), err));
-            return Err(());
+            sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
+                              crate_dir.display(), err));
+            return
         }
     };
 
@@ -225,11 +233,16 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
 
         // Lock the new session directory. If this fails, return an
         // error without retrying
-        let (directory_lock, lock_file_path) = try!(lock_directory(tcx.sess, &session_dir));
+        let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
+            Ok(e) => e,
+            Err(_) => return,
+        };
 
         // Now that we have the lock, we can actually create the session
         // directory
-        try!(create_dir(tcx.sess, &session_dir, "session"));
+        if create_dir(sess, &session_dir, "session").is_err() {
+            return
+        }
 
         // Find a suitable source directory to copy from. Ignore those that we
         // have already tried before.
@@ -243,14 +256,14 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
             debug!("no source directory found. Continuing with empty session \
                     directory.");
 
-            tcx.sess.init_incr_comp_session(session_dir, directory_lock);
-            return Ok(false)
+            sess.init_incr_comp_session(session_dir, directory_lock, false);
+            return
         };
 
         debug!("attempting to copy data from source: {}",
                source_directory.display());
 
-        let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info;
+        let print_file_copy_stats = sess.opts.debugging_opts.incremental_info;
 
         // Try copying over all files from the source directory
         if let Ok(allows_links) = copy_files(&session_dir, &source_directory,
@@ -259,7 +272,7 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
                    source_directory.display());
 
             if !allows_links {
-                tcx.sess.warn(&format!("Hard linking files in the incremental \
+                sess.warn(&format!("Hard linking files in the incremental \
                                         compilation cache failed. Copying files \
                                         instead. Consider moving the cache \
                                         directory to a file system which supports \
@@ -268,8 +281,8 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
                     );
             }
 
-            tcx.sess.init_incr_comp_session(session_dir, directory_lock);
-            return Ok(true)
+            sess.init_incr_comp_session(session_dir, directory_lock, true);
+            return
         } else {
              debug!("copying failed - trying next directory");
 
@@ -280,13 +293,13 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
             // Try to remove the session directory we just allocated. We don't
             // know if there's any garbage in it from the failed copy action.
             if let Err(err) = safe_remove_dir_all(&session_dir) {
-                tcx.sess.warn(&format!("Failed to delete partly initialized \
-                                        session dir `{}`: {}",
-                                       session_dir.display(),
-                                       err));
+                sess.warn(&format!("Failed to delete partly initialized \
+                                    session dir `{}`: {}",
+                                   session_dir.display(),
+                                   err));
             }
 
-            delete_session_dir_lock_file(tcx.sess, &lock_file_path);
+            delete_session_dir_lock_file(sess, &lock_file_path);
             mem::drop(directory_lock);
         }
     }
index 2c43896ec73d242d9170957f423373baa109006d..ba638289fdf03168b9c5ee60f2a22cdcaa11f60d 100644 (file)
 /// more general overview.
 pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 incremental_hashes_map: &IncrementalHashesMap) {
-    if tcx.sess.opts.incremental.is_none() {
-        return;
+    if tcx.sess.incr_session_load_dep_graph() {
+        let _ignore = tcx.dep_graph.in_ignore();
+        load_dep_graph_if_exists(tcx, incremental_hashes_map);
     }
-
-    match prepare_session_directory(tcx) {
-        Ok(true) => {
-            // We successfully allocated a session directory and there is
-            // something in it to load, so continue
-        }
-        Ok(false) => {
-            // We successfully allocated a session directory, but there is no
-            // dep-graph data in it to load (because this is the first
-            // compilation session with this incr. comp. dir.)
-            return
-        }
-        Err(()) => {
-            // Something went wrong while trying to allocate the session
-            // directory. Don't try to use it any further.
-            return
-        }
-    }
-
-    let _ignore = tcx.dep_graph.in_ignore();
-    load_dep_graph_if_exists(tcx, incremental_hashes_map);
 }
 
 fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
index 5c1582daa78fa07119caa53219831e699ed60e88..fb3308132261f37d722dbdb5e771353388502515 100644 (file)
@@ -22,6 +22,7 @@
 mod work_product;
 mod file_format;
 
+pub use self::fs::prepare_session_directory;
 pub use self::fs::finalize_session_directory;
 pub use self::fs::in_incr_comp_dir;
 pub use self::load::load_dep_graph;
index 339e2bdc15734960534873ae46a39402f11a37f9..65fbaf1ad047a484da1c659d956e324283fdcfb1 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::dep_graph::DepNode;
+use rustc::dep_graph::{DepGraph, DepNode};
 use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
 use rustc::ich::Fingerprint;
@@ -79,21 +79,21 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             &current_metadata_hashes);
 }
 
-pub fn save_work_products(sess: &Session) {
+pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
     if sess.opts.incremental.is_none() {
         return;
     }
 
     debug!("save_work_products()");
-    let _ignore = sess.dep_graph.in_ignore();
+    let _ignore = dep_graph.in_ignore();
     let path = work_products_path(sess);
-    save_in(sess, path, |e| encode_work_products(sess, e));
+    save_in(sess, path, |e| encode_work_products(dep_graph, e));
 
     // We also need to clean out old work-products, as not all of them are
     // deleted during invalidation. Some object files don't change their
     // content, they are just not needed anymore.
-    let new_work_products = sess.dep_graph.work_products();
-    let previous_work_products = sess.dep_graph.previous_work_products();
+    let new_work_products = dep_graph.work_products();
+    let previous_work_products = dep_graph.previous_work_products();
 
     for (id, wp) in previous_work_products.iter() {
         if !new_work_products.contains_key(id) {
@@ -309,8 +309,9 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
     Ok(())
 }
 
-pub fn encode_work_products(sess: &Session, encoder: &mut Encoder) -> io::Result<()> {
-    let work_products: Vec<_> = sess.dep_graph
+pub fn encode_work_products(dep_graph: &DepGraph,
+                            encoder: &mut Encoder) -> io::Result<()> {
+    let work_products: Vec<_> = dep_graph
         .work_products()
         .iter()
         .map(|(id, work_product)| {
index e20d7a006b0ddb0844ec0a88f54eba4624447c36..70d96e3a83d376bed6bd6dbd219e299b7f2960b9 100644 (file)
@@ -11,7 +11,7 @@
 //! This module contains files for saving intermediate work-products.
 
 use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId};
+use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph};
 use rustc::session::Session;
 use rustc::session::config::OutputType;
 use rustc::util::fs::link_or_copy;
@@ -19,6 +19,7 @@
 use std::fs as std_fs;
 
 pub fn save_trans_partition(sess: &Session,
+                            dep_graph: &DepGraph,
                             cgu_name: &str,
                             partition_hash: u64,
                             files: &[(OutputType, PathBuf)]) {
@@ -60,7 +61,7 @@ pub fn save_trans_partition(sess: &Session,
         saved_files,
     };
 
-    sess.dep_graph.insert_work_product(&work_product_id, work_product);
+    dep_graph.insert_work_product(&work_product_id, work_product);
 }
 
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
index a4421b216c311b4d50134c8e4885123d708216e7..19a595622b92edf62b9a4394407a4e5dffa4a1d9 100644 (file)
 use super::drop_flag_effects_for_location;
 use super::on_lookup_result_bits;
 
+mod storage_liveness;
+
+pub use self::storage_liveness::*;
+
 #[allow(dead_code)]
 pub(super) mod borrows;
 
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
new file mode 100644 (file)
index 0000000..98615c6
--- /dev/null
@@ -0,0 +1,82 @@
+// 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.
+
+pub use super::*;
+
+use rustc::mir::*;
+use dataflow::BitDenotation;
+
+#[derive(Copy, Clone)]
+pub struct MaybeStorageLive<'a, 'tcx: 'a> {
+    mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'tcx: 'a> MaybeStorageLive<'a, 'tcx> {
+    pub fn new(mir: &'a Mir<'tcx>)
+               -> Self {
+        MaybeStorageLive { mir: mir }
+    }
+
+    pub fn mir(&self) -> &Mir<'tcx> {
+        self.mir
+    }
+}
+
+impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {
+    type Idx = Local;
+    fn name() -> &'static str { "maybe_storage_live" }
+    fn bits_per_block(&self) -> usize {
+        self.mir.local_decls.len()
+    }
+
+    fn start_block_effect(&self, _sets: &mut BlockSets<Local>) {
+        // Nothing is live on function entry
+    }
+
+    fn statement_effect(&self,
+                        sets: &mut BlockSets<Local>,
+                        loc: Location) {
+        let stmt = &self.mir[loc.block].statements[loc.statement_index];
+
+        match stmt.kind {
+            StatementKind::StorageLive(l) => sets.gen(&l),
+            StatementKind::StorageDead(l) => sets.kill(&l),
+            _ => (),
+        }
+    }
+
+    fn terminator_effect(&self,
+                         _sets: &mut BlockSets<Local>,
+                         _loc: Location) {
+        // Terminators have no effect
+    }
+
+    fn propagate_call_return(&self,
+                             _in_out: &mut IdxSet<Local>,
+                             _call_bb: mir::BasicBlock,
+                             _dest_bb: mir::BasicBlock,
+                             _dest_lval: &mir::Lvalue) {
+        // Nothing to do when a call returns successfully
+    }
+}
+
+impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
+    #[inline]
+    fn join(&self, pred1: usize, pred2: usize) -> usize {
+        pred1 | pred2 // "maybe" means we union effects of both preds
+    }
+}
+
+impl<'a, 'tcx> DataflowOperator for MaybeStorageLive<'a, 'tcx> {
+    #[inline]
+    fn bottom_value() -> bool {
+        false // bottom = dead
+    }
+}
index 9f9909a8f57a99f9b1d4cf74e5319d0432fcb254..9fa5691d647b70015204c5c98d93cc11ee61c4c9 100644 (file)
@@ -24,6 +24,7 @@
 use std::path::PathBuf;
 use std::usize;
 
+pub use self::impls::{MaybeStorageLive};
 pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
 pub use self::impls::{DefinitelyInitializedLvals};
 pub use self::impls::borrows::{Borrows, BorrowData, BorrowIndex};
@@ -351,6 +352,29 @@ fn apply_local_effect(&mut self,
                           flow_state: &mut Self::FlowState);
 }
 
+pub fn state_for_location<T: BitDenotation>(loc: Location,
+                                            analysis: &T,
+                                            result: &DataflowResults<T>)
+    -> IdxSetBuf<T::Idx> {
+    let mut entry = result.sets().on_entry_set_for(loc.block.index()).to_owned();
+
+    {
+        let mut sets = BlockSets {
+            on_entry: &mut entry.clone(),
+            kill_set: &mut entry.clone(),
+            gen_set: &mut entry,
+        };
+
+        for stmt in 0..loc.statement_index {
+            let mut stmt_loc = loc;
+            stmt_loc.statement_index = stmt;
+            analysis.statement_effect(&mut sets, stmt_loc);
+        }
+    }
+
+    entry
+}
+
 pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
 {
     flow_state: DataflowState<O>,
index a52656becd74534190b114501df7e4bff8d6be39..78fe7b26ebfe0063434fe785a4dd08207b2329e6 100644 (file)
@@ -38,7 +38,8 @@
 //! This pass computes the meaning of the state field and the MIR locals which are live
 //! across a suspension point. There are however two hardcoded generator states:
 //!     0 - Generator have not been resumed yet
-//!     1 - Generator has been poisoned
+//!     1 - Generator has returned / is completed
+//!     2 - Generator has been poisoned
 //!
 //! It also rewrites `return x` and `yield y` as setting a new generator state and returning
 //! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
 //! the action to take.
 //!
 //! One of them is the implementation of Generator::resume.
-//! For generators which have already returned it panics.
 //! For generators with state 0 (unresumed) it starts the execution of the generator.
-//! For generators with state 1 (poisoned) it panics.
+//! For generators with state 1 (returned) and state 2 (poisoned) it panics.
 //! Otherwise it continues the execution from the last suspension point.
 //!
 //! The other function is the drop glue for the generator.
-//! For generators which have already returned it does nothing.
 //! For generators with state 0 (unresumed) it drops the upvars of the generator.
-//! For generators with state 1 (poisoned) it does nothing.
+//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
 //! Otherwise it drops all the values in scope at the last suspension point.
 
 use rustc::hir;
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::transform::{MirPass, MirSource};
-use rustc::mir::visit::{LvalueContext, MutVisitor};
+use rustc::mir::visit::{LvalueContext, Visitor, MutVisitor};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
 use rustc::ty::subst::{Kind, Substs};
 use util::dump_mir;
 use util::liveness;
 use rustc_const_math::ConstInt;
 use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::indexed_set::IdxSetBuf;
 use std::collections::HashMap;
 use std::borrow::Cow;
 use std::iter::once;
 use std::mem;
 use transform::simplify;
 use transform::no_landing_pads::no_landing_pads;
+use dataflow::{self, MaybeStorageLive, state_for_location};
 
 pub struct StateTransform;
 
@@ -126,6 +127,13 @@ fn self_arg() -> Local {
     Local::new(1)
 }
 
+struct SuspensionPoint {
+    state: u32,
+    resume: BasicBlock,
+    drop: Option<BasicBlock>,
+    storage_liveness: liveness::LocalSet,
+}
+
 struct TransformVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     state_adt_ref: &'tcx AdtDef,
@@ -137,18 +145,14 @@ struct TransformVisitor<'a, 'tcx: 'a> {
     // Mapping from Local to (type of local, generator struct index)
     remap: HashMap<Local, (Ty<'tcx>, usize)>,
 
-    // The number of generator states. 0 is unresumed, 1 is poisoned. So this is initialized to 2
-    bb_target_count: u32,
+    // A map from a suspension point in a block to the locals which have live storage at that point
+    storage_liveness: HashMap<BasicBlock, liveness::LocalSet>,
 
-    // Map from a (which block to resume execution at, which block to use to drop the generator)
-    // to a generator state
-    bb_targets: HashMap<(BasicBlock, Option<BasicBlock>), u32>,
+    // A list of suspension points, generated during the transform
+    suspension_points: Vec<SuspensionPoint>,
 
     // The original RETURN_POINTER local
     new_ret_local: Local,
-
-    // The block to resume execution when for Return
-    return_block: BasicBlock,
 }
 
 impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
@@ -225,33 +229,39 @@ fn visit_basic_block_data(&mut self,
 
         let ret_val = match data.terminator().kind {
             TerminatorKind::Return => Some((1,
-                self.return_block,
+                None,
                 Operand::Consume(Lvalue::Local(self.new_ret_local)),
                 None)),
             TerminatorKind::Yield { ref value, resume, drop } => Some((0,
-                resume,
+                Some(resume),
                 value.clone(),
                 drop)),
             _ => None
         };
 
         if let Some((state_idx, resume, v, drop)) = ret_val {
-            let bb_idx = {
-                let bb_targets = &mut self.bb_targets;
-                let bb_target = &mut self.bb_target_count;
-                *bb_targets.entry((resume, drop)).or_insert_with(|| {
-                    let target = *bb_target;
-                    *bb_target = target.checked_add(1).unwrap();
-                    target
-                })
-            };
             let source_info = data.terminator().source_info;
-            data.statements.push(self.set_state(bb_idx, source_info));
+            // We must assign the value first in case it gets declared dead below
             data.statements.push(Statement {
                 source_info,
                 kind: StatementKind::Assign(Lvalue::Local(RETURN_POINTER),
                     self.make_state(state_idx, v)),
             });
+            let state = if let Some(resume) = resume { // Yield
+                let state = 3 + self.suspension_points.len() as u32;
+
+                self.suspension_points.push(SuspensionPoint {
+                    state,
+                    resume,
+                    drop,
+                    storage_liveness: self.storage_liveness.get(&block).unwrap().clone(),
+                });
+
+                state
+            } else { // Return
+                 1 // state for returned
+            };
+            data.statements.push(self.set_state(state, source_info));
             data.terminator.as_mut().unwrap().kind = TerminatorKind::Return;
         }
 
@@ -286,16 +296,11 @@ fn make_generator_state_argument_indirect<'a, 'tcx>(
 
 fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
                             mir: &mut Mir<'tcx>) -> Local {
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
     let new_ret = LocalDecl {
         mutability: Mutability::Mut,
         ty: ret_ty,
         name: None,
-        source_info,
+        source_info: source_info(mir),
         internal: false,
         is_user_variable: false,
     };
@@ -311,33 +316,84 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
     new_ret_local
 }
 
+struct StorageIgnored(liveness::LocalSet);
+
+impl<'tcx> Visitor<'tcx> for StorageIgnored {
+    fn visit_statement(&mut self,
+                       _block: BasicBlock,
+                       statement: &Statement<'tcx>,
+                       _location: Location) {
+        match statement.kind {
+            StatementKind::StorageLive(l) |
+            StatementKind::StorageDead(l) => { self.0.remove(&l); }
+            _ => (),
+        }
+    }
+}
+
 fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
-                                               source: MirSource) -> liveness::LocalSet {
+                                               source: MirSource) ->
+                                               (liveness::LocalSet,
+                                                HashMap<BasicBlock, liveness::LocalSet>) {
+    let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
+    let node_id = source.item_id();
+    let analysis = MaybeStorageLive::new(mir);
+    let storage_live =
+        dataflow::do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+                              |bd, p| &bd.mir().local_decls[p]);
+
+    let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
+    ignored.visit_mir(mir);
+
     let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
-    let result = liveness::liveness_of_locals(mir);
-    liveness::dump_mir(tcx, "generator_liveness", source, mir, &result);
+    let liveness = liveness::liveness_of_locals(mir);
+    liveness::dump_mir(tcx, "generator_liveness", source, mir, &liveness);
+
+    let mut storage_liveness_map = HashMap::new();
 
     for (block, data) in mir.basic_blocks().iter_enumerated() {
         if let TerminatorKind::Yield { .. } = data.terminator().kind {
-            set.union(&result.outs[block]);
+            let loc = Location {
+                block: block,
+                statement_index: data.statements.len(),
+            };
+
+            let storage_liveness = state_for_location(loc, &analysis, &storage_live);
+
+            storage_liveness_map.insert(block, storage_liveness.clone());
+
+            let mut live_locals = storage_liveness;
+
+            // Mark locals without storage statements as always having live storage
+            live_locals.union(&ignored.0);
+
+            // Locals live are live at this point only if they are used across suspension points
+            // and their storage is live
+            live_locals.intersect(&liveness.outs[block]);
+
+            // Add the locals life at this suspension point to the set of locals which live across
+            // any suspension points
+            set.union(&live_locals);
         }
     }
 
     // The generator argument is ignored
     set.remove(&self_arg());
 
-    set
+    (set, storage_liveness_map)
 }
 
 fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             source: MirSource,
                             interior: GeneratorInterior<'tcx>,
                             mir: &mut Mir<'tcx>)
-    -> (HashMap<Local, (Ty<'tcx>, usize)>, GeneratorLayout<'tcx>)
+    -> (HashMap<Local, (Ty<'tcx>, usize)>,
+        GeneratorLayout<'tcx>,
+        HashMap<BasicBlock, liveness::LocalSet>)
 {
     // Use a liveness analysis to compute locals which are live across a suspension point
-    let live_locals = locals_live_across_suspend_points(tcx, mir, source);
+    let (live_locals, storage_liveness) = locals_live_across_suspend_points(tcx, mir, source);
 
     // Erase regions from the types passed in from typeck so we can compare them with
     // MIR types
@@ -381,12 +437,31 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         fields: vars
     };
 
-    (remap, layout)
+    (remap, layout, storage_liveness)
 }
 
-fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>,
-                            block: BasicBlockData<'tcx>) {
-    mir.basic_blocks_mut().raw.insert(0, block);
+fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           mir: &mut Mir<'tcx>,
+                           cases: Vec<(u32, BasicBlock)>,
+                           transform: &TransformVisitor<'a, 'tcx>) {
+    let return_block = insert_return_block(mir);
+
+    let switch = TerminatorKind::SwitchInt {
+        discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
+        switch_ty: tcx.types.u32,
+        values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
+        targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
+    };
+
+    let source_info = source_info(mir);
+    mir.basic_blocks_mut().raw.insert(0, BasicBlockData {
+        statements: Vec::new(),
+        terminator: Some(Terminator {
+            source_info,
+            kind: switch,
+        }),
+        is_cleanup: false,
+    });
 
     let blocks = mir.basic_blocks_mut().iter_mut();
 
@@ -458,46 +533,16 @@ fn create_generator_drop_shim<'a, 'tcx>(
                 drop_clean: BasicBlock) -> Mir<'tcx> {
     let mut mir = mir.clone();
 
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
+    let source_info = source_info(&mir);
 
-    let return_block = BasicBlock::new(mir.basic_blocks().len());
-    mir.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: TerminatorKind::Return,
-        }),
-        is_cleanup: false,
-    });
-
-    let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(_, u), &s)| {
-        u.map(|d| (s, d))
-    }).collect();
+    let mut cases = create_cases(&mut mir, transform, |point| point.drop);
 
     cases.insert(0, (0, drop_clean));
 
-    // The poisoned state 1 falls through to the default case which is just to return
+    // The returned state (1) and the poisoned state (2) falls through to
+    // the default case which is just to return
 
-    let switch = TerminatorKind::SwitchInt {
-        discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
-        switch_ty: tcx.types.u32,
-        values: Cow::from(cases.iter().map(|&(i, _)| {
-                ConstInt::U32(i)
-            }).collect::<Vec<_>>()),
-        targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
-    };
-
-    insert_entry_point(&mut mir, BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: switch,
-        }),
-        is_cleanup: false,
-    });
+    insert_switch(tcx, &mut mir, cases, &transform);
 
     for block in mir.basic_blocks_mut() {
         let kind = &mut block.terminator_mut().kind;
@@ -507,11 +552,6 @@ fn create_generator_drop_shim<'a, 'tcx>(
     }
 
     // Replace the return variable
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
     mir.return_ty = tcx.mk_nil();
     mir.local_decls[RETURN_POINTER] = LocalDecl {
         mutability: Mutability::Mut,
@@ -548,8 +588,23 @@ fn create_generator_drop_shim<'a, 'tcx>(
     mir
 }
 
-fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        mir: &mut Mir<'tcx>) {
+fn insert_return_block<'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+    let return_block = BasicBlock::new(mir.basic_blocks().len());
+    let source_info = source_info(mir);
+    mir.basic_blocks_mut().push(BasicBlockData {
+        statements: Vec::new(),
+        terminator: Some(Terminator {
+            source_info,
+            kind: TerminatorKind::Return,
+        }),
+        is_cleanup: false,
+    });
+    return_block
+}
+
+fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                mir: &mut Mir<'tcx>,
+                                message: AssertMessage<'tcx>) -> BasicBlock {
     let assert_block = BasicBlock::new(mir.basic_blocks().len());
     let term = TerminatorKind::Assert {
         cond: Operand::Constant(box Constant {
@@ -563,16 +618,12 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             },
         }),
         expected: true,
-        msg: AssertMessage::GeneratorResumedAfterReturn,
+        msg: message,
         target: assert_block,
         cleanup: None,
     };
 
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
+    let source_info = source_info(mir);
     mir.basic_blocks_mut().push(BasicBlockData {
         statements: Vec::new(),
         terminator: Some(Terminator {
@@ -581,11 +632,13 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }),
         is_cleanup: false,
     });
+
+    assert_block
 }
 
 fn create_generator_resume_function<'a, 'tcx>(
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
-        mut transform: TransformVisitor<'a, 'tcx>,
+        transform: TransformVisitor<'a, 'tcx>,
         def_id: DefId,
         source: MirSource,
         mir: &mut Mir<'tcx>) {
@@ -597,61 +650,16 @@ fn create_generator_resume_function<'a, 'tcx>(
         }
     }
 
-    let source_info = SourceInfo {
-        span: mir.span,
-        scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
-
-    let poisoned_block = BasicBlock::new(mir.basic_blocks().len());
-
-    let term = TerminatorKind::Assert {
-        cond: Operand::Constant(box Constant {
-            span: mir.span,
-            ty: tcx.types.bool,
-            literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    val: ConstVal::Bool(false),
-                    ty: tcx.types.bool
-                }),
-            },
-        }),
-        expected: true,
-        msg: AssertMessage::GeneratorResumedAfterPanic,
-        target: transform.return_block,
-        cleanup: None,
-    };
-
-    mir.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: term,
-        }),
-        is_cleanup: false,
-    });
-
-    transform.bb_targets.insert((poisoned_block, None), 1);
+    let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
 
-    let switch = TerminatorKind::SwitchInt {
-        discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
-        switch_ty: tcx.types.u32,
-        values: Cow::from(transform.bb_targets.values().map(|&i| {
-                ConstInt::U32(i)
-            }).collect::<Vec<_>>()),
-        targets: transform.bb_targets.keys()
-            .map(|&(k, _)| k)
-            .chain(once(transform.return_block))
-            .collect(),
-    };
+    // Jump to the entry point on the 0 state
+    cases.insert(0, (0, BasicBlock::new(0)));
+    // Panic when resumed on the returned (1) state
+    cases.insert(1, (1, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterReturn)));
+    // Panic when resumed on the poisoned (2) state
+    cases.insert(2, (2, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterPanic)));
 
-    insert_entry_point(mir, BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: switch,
-        }),
-        is_cleanup: false,
-    });
+    insert_switch(tcx, mir, cases, &transform);
 
     make_generator_state_argument_indirect(tcx, def_id, mir);
 
@@ -664,21 +672,15 @@ fn create_generator_resume_function<'a, 'tcx>(
     dump_mir(tcx, None, "generator_resume", &0, source, mir);
 }
 
-fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
-    let source_info = SourceInfo {
+fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo {
+    SourceInfo {
         span: mir.span,
         scope: ARGUMENT_VISIBILITY_SCOPE,
-    };
+    }
+}
 
-    let return_block = BasicBlock::new(mir.basic_blocks().len());
-    mir.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator {
-            source_info,
-            kind: TerminatorKind::Return,
-        }),
-        is_cleanup: false,
-    });
+fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+    let return_block = insert_return_block(mir);
 
     // Create a block to destroy an unresumed generators. This can only destroy upvars.
     let drop_clean = BasicBlock::new(mir.basic_blocks().len());
@@ -687,6 +689,7 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
         target: return_block,
         unwind: None,
     };
+    let source_info = source_info(mir);
     mir.basic_blocks_mut().push(BasicBlockData {
         statements: Vec::new(),
         terminator: Some(Terminator {
@@ -699,6 +702,46 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
     drop_clean
 }
 
+fn create_cases<'a, 'tcx, F>(mir: &mut Mir<'tcx>,
+                          transform: &TransformVisitor<'a, 'tcx>,
+                          target: F) -> Vec<(u32, BasicBlock)>
+    where F: Fn(&SuspensionPoint) -> Option<BasicBlock> {
+    let source_info = source_info(mir);
+
+    transform.suspension_points.iter().filter_map(|point| {
+        // Find the target for this suspension point, if applicable
+        target(point).map(|target| {
+            let block = BasicBlock::new(mir.basic_blocks().len());
+            let mut statements = Vec::new();
+
+            // Create StorageLive instructions for locals with live storage
+            for i in 0..(mir.local_decls.len()) {
+                let l = Local::new(i);
+                if point.storage_liveness.contains(&l) && !transform.remap.contains_key(&l) {
+                    statements.push(Statement {
+                        source_info,
+                        kind: StatementKind::StorageLive(l),
+                    });
+                }
+            }
+
+            // Then jump to the real target
+            mir.basic_blocks_mut().push(BasicBlockData {
+                statements,
+                terminator: Some(Terminator {
+                    source_info,
+                    kind: TerminatorKind::Goto {
+                        target,
+                    },
+                }),
+                is_cleanup: false,
+            });
+
+            (point.state, block)
+        })
+    }).collect()
+}
+
 impl MirPass for StateTransform {
     fn run_pass<'a, 'tcx>(&self,
                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -736,16 +779,11 @@ fn run_pass<'a, 'tcx>(&self,
 
         // Extract locals which are live across suspension point into `layout`
         // `remap` gives a mapping from local indices onto generator struct indices
-        let (remap, layout) = compute_layout(tcx, source, interior, mir);
+        // `storage_liveness` tells us which locals have live storage at suspension points
+        let (remap, layout, storage_liveness) = compute_layout(tcx, source, interior, mir);
 
         let state_field = mir.upvar_decls.len();
 
-        let mut bb_targets = HashMap::new();
-
-        // If we jump to the entry point, we should go to the initial 0 generator state.
-        // FIXME: Could this result in the need for destruction for state 0?
-        bb_targets.insert((BasicBlock::new(0), None), 0);
-
         // Run the transformation which converts Lvalues from Local to generator struct
         // accesses for locals in `remap`.
         // It also rewrites `return x` and `yield y` as writing a new generator state and returning
@@ -755,14 +793,10 @@ fn run_pass<'a, 'tcx>(&self,
             state_adt_ref,
             state_substs,
             remap,
-            bb_target_count: 2,
-            bb_targets,
+            storage_liveness,
+            suspension_points: Vec::new(),
             new_ret_local,
             state_field,
-
-            // For returns we will resume execution at the next added basic block.
-            // This happens in `insert_panic_on_resume_after_return`
-            return_block: BasicBlock::new(mir.basic_blocks().len()),
         };
         transform.visit_mir(mir);
 
@@ -773,9 +807,6 @@ fn run_pass<'a, 'tcx>(&self,
         mir.spread_arg = None;
         mir.generator_layout = Some(layout);
 
-        // Panic if we resumed after returning
-        insert_panic_on_resume_after_return(tcx, mir);
-
         // Insert `drop(generator_struct)` which is used to drop upvars for generators in
         // the unresumed (0) state.
         // This is expanded to a drop ladder in `elaborate_generator_drops`.
index 72e1fc34789540b7e055f4f4ae66da7ff69521ba..68140011e7ec3843136fa75f8c601f57ccd5e0a3 100644 (file)
@@ -13,6 +13,7 @@
 use back::linker::LinkerInfo;
 use back::symbol_export::ExportedSymbols;
 use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
+use rustc::dep_graph::DepGraph;
 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
                              AllPasses, Sanitizer};
@@ -807,6 +808,7 @@ pub fn start_async_translation(sess: &Session,
 }
 
 fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
+                                              dep_graph: &DepGraph,
                                               compiled_modules: &CompiledModules,
                                               crate_output: &OutputFilenames) {
     if sess.opts.incremental.is_none() {
@@ -826,7 +828,11 @@ fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
             files.push((OutputType::Bitcode, path));
         }
 
-        save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
+        save_trans_partition(sess,
+                             dep_graph,
+                             &module.name,
+                             module.symbol_name_hash,
+                             &files);
     }
 }
 
@@ -1822,7 +1828,7 @@ pub struct OngoingCrateTranslation {
 }
 
 impl OngoingCrateTranslation {
-    pub fn join(self, sess: &Session) -> CrateTranslation {
+    pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
         self.shared_emitter_main.check(sess, true);
         let compiled_modules = match self.future.join() {
             Ok(compiled_modules) => compiled_modules,
@@ -1838,6 +1844,7 @@ pub fn join(self, sess: &Session) -> CrateTranslation {
         }
 
         copy_module_artifacts_into_incr_comp_cache(sess,
+                                                   dep_graph,
                                                    &compiled_modules,
                                                    &self.output_filenames);
         produce_final_output_artifacts(sess,
index d7ce5e262ce381b07cd0f412da0dff4b4ad80704..fd0167be2b98f4e57680b52f32ad9c48e4a7ae1b 100644 (file)
@@ -11,7 +11,6 @@
 use rustc_lint;
 use rustc_driver::{driver, target_features, abort_on_err};
 use rustc_driver::pretty::ReplaceBodyWithLoop;
-use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config};
 use rustc::hir::def_id::DefId;
 use rustc::hir::def::Def;
@@ -144,11 +143,9 @@ pub fn run_core(search_paths: SearchPaths,
                                                                false,
                                                                Some(codemap.clone()));
 
-    let dep_graph = DepGraph::new(false);
-    let _ignore = dep_graph.in_ignore();
     let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
-        sessopts, &dep_graph, cpath, diagnostic_handler, codemap
+        sessopts, cpath, diagnostic_handler, codemap,
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
index 49d4bd2324033dbaeb3c3d327aee8c6afd96e7eb..500b75ec659a19236460c0c3f0fd9af508a39aee 100644 (file)
 
 use serialize::json::{ToJson, Json, as_json};
 use syntax::{abi, ast};
-use syntax::feature_gate::UnstableFeatures;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
 use rustc::hir;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc::session::config::nightly_options::is_nightly_build;
 use rustc_data_structures::flock;
 
 use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability, Span};
@@ -1764,9 +1762,13 @@ fn render_markdown(w: &mut fmt::Formatter,
                    prefix: &str,
                    scx: &SharedContext)
                    -> fmt::Result {
-    let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
     // We only emit warnings if the user has opted-in to Pulldown rendering.
     let output = if render_type == RenderType::Pulldown {
+        // Save the state of USED_ID_MAP so it only gets updated once even
+        // though we're rendering twice.
+        let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
+        let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
+        USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
         let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
         let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
         differences.retain(|s| {
@@ -1787,7 +1789,7 @@ fn render_markdown(w: &mut fmt::Formatter,
 
         pulldown_output
     } else {
-        hoedown_output
+        format!("{}", Markdown(md_text, RenderType::Hoedown))
     };
 
     write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
@@ -2192,14 +2194,9 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
 
 fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                  f: &clean::Function) -> fmt::Result {
-    // FIXME(#24111): remove when `const_fn` is stabilized
-    let vis_constness = match UnstableFeatures::from_environment() {
-        UnstableFeatures::Allow => f.constness,
-        _ => hir::Constness::NotConst
-    };
     let name_len = format!("{}{}{}{:#}fn {}{:#}",
                            VisSpace(&it.visibility),
-                           ConstnessSpace(vis_constness),
+                           ConstnessSpace(f.constness),
                            UnsafetySpace(f.unsafety),
                            AbiSpace(f.abi),
                            it.name.as_ref().unwrap(),
@@ -2209,7 +2206,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     write!(w, "{vis}{constness}{unsafety}{abi}fn \
                {name}{generics}{decl}{where_clause}</pre>",
            vis = VisSpace(&it.visibility),
-           constness = ConstnessSpace(vis_constness),
+           constness = ConstnessSpace(f.constness),
            unsafety = UnsafetySpace(f.unsafety),
            abi = AbiSpace(f.abi),
            name = it.name.as_ref().unwrap(),
@@ -2591,14 +2588,8 @@ fn method(w: &mut fmt::Formatter,
                 href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
             }
         };
-        // FIXME(#24111): remove when `const_fn` is stabilized
-        let vis_constness = if is_nightly_build() {
-            constness
-        } else {
-            hir::Constness::NotConst
-        };
         let mut head_len = format!("{}{}{:#}fn {}{:#}",
-                                   ConstnessSpace(vis_constness),
+                                   ConstnessSpace(constness),
                                    UnsafetySpace(unsafety),
                                    AbiSpace(abi),
                                    name,
@@ -2611,7 +2602,7 @@ fn method(w: &mut fmt::Formatter,
         };
         write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
-               ConstnessSpace(vis_constness),
+               ConstnessSpace(constness),
                UnsafetySpace(unsafety),
                AbiSpace(abi),
                href = href,
index 9b76a713b1769541561b0727fd74b2d3c463b6b9..95c0f5f5d63645a0834fee8d0e7bd07290a4ac83 100644 (file)
@@ -22,7 +22,6 @@
 
 use testing;
 use rustc_lint;
-use rustc::dep_graph::DepGraph;
 use rustc::hir;
 use rustc::hir::intravisit;
 use rustc::session::{self, CompileIncomplete, config};
@@ -83,11 +82,9 @@ pub fn run(input: &str,
     let handler =
         errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
 
-    let dep_graph = DepGraph::new(false);
-    let _ignore = dep_graph.in_ignore();
     let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
-        sessopts, &dep_graph, Some(input_path.clone()), handler, codemap.clone()
+        sessopts, Some(input_path.clone()), handler, codemap.clone(),
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
@@ -100,7 +97,14 @@ pub fn run(input: &str,
     let krate = ReplaceBodyWithLoop::new().fold_crate(krate);
     let driver::ExpansionResult { defs, mut hir_forest, .. } = {
         phase_2_configure_and_expand(
-            &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
+            &sess,
+            &cstore,
+            krate,
+            None,
+            "rustdoc-test",
+            None,
+            MakeGlobMap::No,
+            |_| Ok(()),
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
     };
 
@@ -120,8 +124,6 @@ pub fn run(input: &str,
                                        render_type);
 
     {
-        let dep_graph = DepGraph::new(false);
-        let _ignore = dep_graph.in_ignore();
         let map = hir::map::map_crate(&mut hir_forest, defs);
         let krate = map.krate();
         let mut hir_collector = HirCollector {
@@ -237,10 +239,9 @@ fn drop(&mut self) {
     // Compile the code
     let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
 
-    let dep_graph = DepGraph::new(false);
     let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
-        sessopts, &dep_graph, None, diagnostic_handler, codemap
+        sessopts, None, diagnostic_handler, codemap,
     );
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
index 2e3fb785748f3f5345aa01515a11f17b1272fc44..461df49b468f94dca3cfc47f0ced18404da9b32a 100644 (file)
@@ -58,9 +58,8 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
     opts.maybe_sysroot = Some(sysroot);
 
     let descriptions = Registry::new(&rustc::DIAGNOSTICS);
-    let dep_graph = DepGraph::new(opts.build_dep_graph());
     let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
-    let sess = build_session(opts, &dep_graph, None, descriptions);
+    let sess = build_session(opts, None, descriptions);
     rustc_trans::init(&sess);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     (sess, cstore)
diff --git a/src/test/run-pass/generator/match-bindings.rs b/src/test/run-pass/generator/match-bindings.rs
new file mode 100644 (file)
index 0000000..9c6b057
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+#![feature(generators)]
+
+enum Enum {
+    A(String),
+    B
+}
+
+fn main() {
+    || {
+        loop {
+            if let true = true {
+                match Enum::A(String::new()) {
+                    Enum::A(_var) => {}
+                    Enum::B => {}
+                }
+            }
+            yield;
+        }
+    };
+}
\ No newline at end of file
diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs
new file mode 100644 (file)
index 0000000..c323681
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+#![feature(const_fn)]
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+/// foo
+pub const fn bar() -> usize {
+    2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method"]' 'const fn new()'
+pub struct Foo(usize);
+
+impl Foo {
+    pub const fn new() -> Foo { Foo(0) }
+}