]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #34975 - GuillaumeGomez:random_state_doc, r=steveklabnik
authorManish Goregaokar <manishsmail@gmail.com>
Sun, 24 Jul 2016 09:48:47 +0000 (15:18 +0530)
committerGitHub <noreply@github.com>
Sun, 24 Jul 2016 09:48:47 +0000 (15:18 +0530)
Add Random state doc

Last part of #29348.

r? @steveklabnik

43 files changed:
mk/tests.mk
src/bootstrap/lib.rs
src/bootstrap/step.rs
src/doc/book/loops.md
src/libcollections/btree/map.rs
src/libcollections/fmt.rs
src/libcollections/linked_list.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcore/fmt/mod.rs
src/libcore/option.rs
src/libpanic_unwind/dwarf/eh.rs
src/libpanic_unwind/gcc.rs
src/libpanic_unwind/lib.rs
src/libpanic_unwind/seh64_gnu.rs
src/librustc/session/config.rs
src/librustc_back/target/mips_unknown_linux_gnu.rs
src/librustc_const_eval/eval.rs
src/librustc_mir/pretty.rs
src/librustc_trans/base.rs
src/librustc_trans/intrinsic.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/static/rustdoc.css
src/libstd/collections/hash/map.rs
src/libstd/fs.rs
src/libstd/sync/mpsc/mod.rs
src/libsyntax/ext/quote.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax_pos/lib.rs
src/libunwind/libunwind.rs
src/test/codegen/internalize-closures.rs [new file with mode: 0644]
src/test/mir-opt/README.md [new file with mode: 0644]
src/test/mir-opt/return_an_array.rs [new file with mode: 0644]
src/test/mir-opt/simplify_if.rs [new file with mode: 0644]
src/test/run-pass/const-byte-str-cast.rs
src/test/run-pass/ifmt.rs
src/test/run-pass/macro-of-higher-order.rs
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs

index ed443147d466e3734bf5a209ff23aed0a7e166f8..201e4cae51d6d9a4e293d2eedfa276f477991cd3 100644 (file)
@@ -277,7 +277,8 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
        check-stage$(1)-T-$(2)-H-$(3)-ui-exec \
        check-stage$(1)-T-$(2)-H-$(3)-doc-exec \
        check-stage$(1)-T-$(2)-H-$(3)-doc-error-index-exec \
-       check-stage$(1)-T-$(2)-H-$(3)-pretty-exec
+       check-stage$(1)-T-$(2)-H-$(3)-pretty-exec \
+       check-stage$(1)-T-$(2)-H-$(3)-mir-opt-exec
 
 ifndef CFG_DISABLE_CODEGEN_TESTS
 check-stage$(1)-T-$(2)-H-$(3)-exec: \
@@ -458,6 +459,7 @@ UI_RS := $(call rwildcard,$(S)src/test/ui/,*.rs) \
          $(call rwildcard,$(S)src/test/ui/,*.stdout) \
          $(call rwildcard,$(S)src/test/ui/,*.stderr)
 RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs)
+MIR_OPT_RS := $(call rwildcard,$(S)src/test/mir-opt/,*.rs)
 
 RPASS_TESTS := $(RPASS_RS)
 RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS)
@@ -475,6 +477,7 @@ CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS)
 INCREMENTAL_TESTS := $(INCREMENTAL_RS)
 RMAKE_TESTS := $(RMAKE_RS)
 UI_TESTS := $(UI_RS)
+MIR_OPT_TESTS := $(MIR_OPT_RS)
 RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
 
 CTEST_SRC_BASE_rpass = run-pass
@@ -552,6 +555,11 @@ CTEST_BUILD_BASE_ui = ui
 CTEST_MODE_ui = ui
 CTEST_RUNTOOL_ui = $(CTEST_RUNTOOL)
 
+CTEST_SRC_BASE_mir-opt = mir-opt
+CTEST_BUILD_BASE_mir-opt = mir-opt
+CTEST_MODE_mir-opt = mir-opt
+CTEST_RUNTOOL_mir-opt = $(CTEST_RUNTOOL)
+
 CTEST_SRC_BASE_rustdocck = rustdoc
 CTEST_BUILD_BASE_rustdocck = rustdoc
 CTEST_MODE_rustdocck = rustdoc
@@ -684,6 +692,7 @@ CTEST_DEPS_incremental_$(1)-T-$(2)-H-$(3) = $$(INCREMENTAL_TESTS)
 CTEST_DEPS_rmake_$(1)-T-$(2)-H-$(3) = $$(RMAKE_TESTS) \
        $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
 CTEST_DEPS_ui_$(1)-T-$(2)-H-$(3) = $$(UI_TESTS)
+CTEST_DEPS_mir-opt_$(1)-T-$(2)-H-$(3) = $$(MIR_OPT_TESTS)
 CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
                $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
                $(S)src/etc/htmldocck.py
@@ -755,7 +764,7 @@ endef
 
 CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
        debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck incremental \
-       rmake ui
+       rmake ui mir-opt
 
 $(foreach host,$(CFG_HOST), \
  $(eval $(foreach target,$(CFG_TARGET), \
@@ -964,6 +973,7 @@ TEST_GROUPS = \
        pretty-rfail-full \
        pretty-rfail \
        pretty-pretty \
+       mir-opt \
        $(NULL)
 
 define DEF_CHECK_FOR_STAGE_AND_TARGET_AND_HOST
index caa6ea17ea0544d6f6a5c263239e4548ad469db4..367322e8816465d6f298c1e4a8fec8edcb7fd035 100644 (file)
@@ -388,6 +388,10 @@ pub fn build(&mut self) {
                     check::compiletest(self, &compiler, target.target,
                                        "pretty", "run-pass-valgrind");
                 }
+                CheckMirOpt { compiler } => {
+                    check::compiletest(self, &compiler, target.target,
+                                       "mir-opt", "mir-opt");
+                }
                 CheckCodegen { compiler } => {
                     check::compiletest(self, &compiler, target.target,
                                        "codegen", "codegen");
index 1ce8c73123244d92344468ffa7cc9f494528393e..f715ceb16d71b969313528ebd1a1510d3dfab688 100644 (file)
@@ -124,6 +124,7 @@ macro_rules! targets {
             (check_codegen_units, CheckCodegenUnits { compiler: Compiler<'a> }),
             (check_incremental, CheckIncremental { compiler: Compiler<'a> }),
             (check_ui, CheckUi { compiler: Compiler<'a> }),
+            (check_mir_opt, CheckMirOpt { compiler: Compiler<'a> }),
             (check_debuginfo, CheckDebuginfo { compiler: Compiler<'a> }),
             (check_rustdoc, CheckRustdoc { compiler: Compiler<'a> }),
             (check_docs, CheckDocs { compiler: Compiler<'a> }),
@@ -450,6 +451,7 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
                         self.check_pretty_rfail_full(compiler),
                         self.check_rpass_valgrind(compiler),
                         self.check_rmake(compiler),
+                        self.check_mir_opt(compiler),
 
                         // crates
                         self.check_crate_rustc(compiler),
@@ -477,6 +479,7 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
             Source::CheckTidy { stage } => {
                 vec![self.tool_tidy(stage)]
             }
+            Source::CheckMirOpt { compiler} |
             Source::CheckPrettyRPass { compiler } |
             Source::CheckPrettyRFail { compiler } |
             Source::CheckRFail { compiler } |
index e681d1bee06184549861f1045c1b765a1c2a0f7e..e4cb861d3b0f5299243fbd22f22a66ac91561dc3 100644 (file)
@@ -105,19 +105,19 @@ When you need to keep track of how many times you already looped, you can use th
 #### On ranges:
 
 ```rust
-for (i, j) in (5..10).enumerate() {
-    println!("i = {} and j = {}", i, j);
+for (index, value) in (5..10).enumerate() {
+    println!("index = {} and value = {}", index, value);
 }
 ```
 
 Outputs:
 
 ```text
-i = 0 and j = 5
-i = 1 and j = 6
-i = 2 and j = 7
-i = 3 and j = 8
-i = 4 and j = 9
+index = 0 and value = 5
+index = 1 and value = 6
+index = 2 and value = 7
+index = 3 and value = 8
+index = 4 and value = 9
 ```
 
 Don't forget to add the parentheses around the range.
index ef94aae78f4160b377737ebaa278655d9bf55cef..c3a7d4023754aac97d45a0539a9cf0e4a8cfe490 100644 (file)
@@ -313,6 +313,10 @@ pub struct RangeMut<'a, K: 'a, V: 'a> {
 }
 
 /// A view into a single entry in a map, which may either be vacant or occupied.
+/// This enum is constructed from the [`entry`] method on [`BTreeMap`].
+///
+/// [`BTreeMap`]: struct.BTreeMap.html
+/// [`entry`]: struct.BTreeMap.html#method.entry
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Entry<'a, K: 'a, V: 'a> {
     /// A vacant Entry
@@ -340,7 +344,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// A vacant Entry.
+/// A vacant Entry. It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct VacantEntry<'a, K: 'a, V: 'a> {
     key: K,
@@ -360,7 +366,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// An occupied Entry.
+/// An occupied Entry. It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
     handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
@@ -1890,6 +1898,17 @@ pub fn is_empty(&self) -> bool {
 impl<'a, K: Ord, V> Entry<'a, K, V> {
     /// Ensures a value is in the entry by inserting the default if empty, and returns
     /// a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn or_insert(self, default: V) -> &'a mut V {
         match self {
@@ -1900,6 +1919,19 @@ pub fn or_insert(self, default: V) -> &'a mut V {
 
     /// Ensures a value is in the entry by inserting the result of the default function if empty,
     /// and returns a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, String> = BTreeMap::new();
+    /// let s = "hoho".to_owned();
+    ///
+    /// map.entry("poneyland").or_insert_with(|| s);
+    ///
+    /// assert_eq!(map["poneyland"], "hoho".to_owned());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
         match self {
@@ -1909,6 +1941,15 @@ pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
     }
 
     /// Returns a reference to this entry's key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
     #[stable(feature = "map_entry_keys", since = "1.10.0")]
     pub fn key(&self) -> &K {
         match *self {
@@ -1921,12 +1962,36 @@ pub fn key(&self) -> &K {
 impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
     /// Gets a reference to the key that would be used when inserting a value
     /// through the VacantEntry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
     #[stable(feature = "map_entry_keys", since = "1.10.0")]
     pub fn key(&self) -> &K {
         &self.key
     }
 
     /// Take ownership of the key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_entry_recover_keys)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    ///
+    /// if let Entry::Vacant(v) = map.entry("poneyland") {
+    ///     v.into_key();
+    /// }
+    /// ```
     #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
     pub fn into_key(self) -> K {
         self.key
@@ -1934,6 +1999,21 @@ pub fn into_key(self) -> K {
 
     /// Sets the value of the entry with the VacantEntry's key,
     /// and returns a mutable reference to it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut count: BTreeMap<&str, usize> = BTreeMap::new();
+    ///
+    /// // count the number of occurrences of letters in the vec
+    /// for x in vec!["a","b","a","c","a","b"] {
+    ///     *count.entry(x).or_insert(0) += 1;
+    /// }
+    ///
+    /// assert_eq!(count["a"], 3);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(self, value: V) -> &'a mut V {
         *self.length += 1;
@@ -1979,30 +2059,106 @@ pub fn insert(self, value: V) -> &'a mut V {
 
 impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
     /// Gets a reference to the key in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
     #[stable(feature = "map_entry_keys", since = "1.10.0")]
     pub fn key(&self) -> &K {
         self.handle.reborrow().into_kv().0
     }
 
     /// Take ownership of the key and value from the map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_entry_recover_keys)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     // We delete the entry from the map.
+    ///     o.remove_pair();
+    /// }
+    ///
+    /// // If now try to get the value, it will panic:
+    /// // println!("{}", map["poneyland"]);
+    /// ```
     #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
     pub fn remove_pair(self) -> (K, V) {
         self.remove_kv()
     }
 
     /// Gets a reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     assert_eq!(o.get(), &12);
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get(&self) -> &V {
         self.handle.reborrow().into_kv().1
     }
 
     /// Gets a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+    ///      *o.get_mut() += 10;
+    /// }
+    /// assert_eq!(map["poneyland"], 22);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut(&mut self) -> &mut V {
         self.handle.kv_mut().1
     }
 
     /// Converts the entry into a mutable reference to its value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     *o.into_mut() += 10;
+    /// }
+    /// assert_eq!(map["poneyland"], 22);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_mut(self) -> &'a mut V {
         self.handle.into_kv_mut().1
@@ -2010,12 +2166,43 @@ pub fn into_mut(self) -> &'a mut V {
 
     /// Sets the value of the entry with the OccupiedEntry's key,
     /// and returns the entry's old value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+    ///     assert_eq!(o.insert(15), 12);
+    /// }
+    /// assert_eq!(map["poneyland"], 15);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, value: V) -> V {
         mem::replace(self.get_mut(), value)
     }
 
     /// Takes the value of the entry out of the map, and returns it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     assert_eq!(o.remove(), 12);
+    /// }
+    /// // If we try to get "poneyland"'s value, it'll panic:
+    /// // println!("{}", map["poneyland"]);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove(self) -> V {
         self.remove_kv().1
index 15de0dd802d99f0a067c6df18d086e1cdb3465b8..c5312d0d9bbd9ad27ee68432f46e40f8ff146842 100644 (file)
 //! ## Precision
 //!
 //! For non-numeric types, this can be considered a "maximum width". If the resulting string is
-//! longer than this width, then it is truncated down to this many characters and only those are
-//! emitted.
+//! longer than this width, then it is truncated down to this many characters and that truncated
+//! value is emitted with proper `fill`, `alignment` and `width` if those parameters are set.
 //!
 //! For integral types, this is ignored.
 //!
 //! ```
 //! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
 //! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
+//! println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
 //! ```
 //!
 //! print two significantly different things:
 //! ```text
 //! Hello, `1234.560` has 3 fractional digits
 //! Hello, `123` has 3 characters
+//! Hello, `     123` has 3 right-aligned characters
 //! ```
 //!
 //! # Escaping
index dbede94f0bf1b668a8fa37173858c44cb2fc757a..3d5c3125fae2489c460f1352aa4776a1017fdf33 100644 (file)
@@ -172,6 +172,14 @@ fn default() -> Self {
 
 impl<T> LinkedList<T> {
     /// Creates an empty `LinkedList`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::LinkedList;
+    ///
+    /// let list: LinkedList<u32> = LinkedList::new();
+    /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> Self {
@@ -226,6 +234,24 @@ pub fn append(&mut self, other: &mut Self) {
     }
 
     /// Provides a forward iterator.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::LinkedList;
+    ///
+    /// let mut list: LinkedList<u32> = LinkedList::new();
+    ///
+    /// list.push_back(0);
+    /// list.push_back(1);
+    /// list.push_back(2);
+    ///
+    /// let mut iter = list.iter();
+    /// assert_eq!(iter.next(), Some(&0));
+    /// assert_eq!(iter.next(), Some(&1));
+    /// assert_eq!(iter.next(), Some(&2));
+    /// assert_eq!(iter.next(), None);
+    /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter(&self) -> Iter<T> {
@@ -238,6 +264,28 @@ pub fn iter(&self) -> Iter<T> {
     }
 
     /// Provides a forward iterator with mutable references.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::LinkedList;
+    ///
+    /// let mut list: LinkedList<u32> = LinkedList::new();
+    ///
+    /// list.push_back(0);
+    /// list.push_back(1);
+    /// list.push_back(2);
+    ///
+    /// for element in list.iter_mut() {
+    ///     *element += 10;
+    /// }
+    ///
+    /// let mut iter = list.iter();
+    /// assert_eq!(iter.next(), Some(&10));
+    /// assert_eq!(iter.next(), Some(&11));
+    /// assert_eq!(iter.next(), Some(&12));
+    /// assert_eq!(iter.next(), None);
+    /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<T> {
@@ -289,7 +337,6 @@ pub fn is_empty(&self) -> bool {
     ///
     /// dl.push_back(3);
     /// assert_eq!(dl.len(), 3);
-    ///
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -316,7 +363,6 @@ pub fn len(&self) -> usize {
     /// dl.clear();
     /// assert_eq!(dl.len(), 0);
     /// assert_eq!(dl.front(), None);
-    ///
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -326,6 +372,23 @@ pub fn clear(&mut self) {
 
     /// Returns `true` if the `LinkedList` contains an element equal to the
     /// given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(linked_list_contains)]
+    ///
+    /// use std::collections::LinkedList;
+    ///
+    /// let mut list: LinkedList<u32> = LinkedList::new();
+    ///
+    /// list.push_back(0);
+    /// list.push_back(1);
+    /// list.push_back(2);
+    ///
+    /// assert_eq!(list.contains(&0), true);
+    /// assert_eq!(list.contains(&10), false);
+    /// ```
     #[unstable(feature = "linked_list_contains", reason = "recently added",
                issue = "32630")]
     pub fn contains(&self, x: &T) -> bool
@@ -347,7 +410,6 @@ pub fn contains(&self, x: &T) -> bool
     ///
     /// dl.push_front(1);
     /// assert_eq!(dl.front(), Some(&1));
-    ///
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -374,7 +436,6 @@ pub fn front(&self) -> Option<&T> {
     ///     Some(x) => *x = 5,
     /// }
     /// assert_eq!(dl.front(), Some(&5));
-    ///
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -395,7 +456,6 @@ pub fn front_mut(&mut self) -> Option<&mut T> {
     ///
     /// dl.push_back(1);
     /// assert_eq!(dl.back(), Some(&1));
-    ///
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -422,7 +482,6 @@ pub fn back(&self) -> Option<&T> {
     ///     Some(x) => *x = 5,
     /// }
     /// assert_eq!(dl.back(), Some(&5));
-    ///
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -446,7 +505,6 @@ pub fn back_mut(&mut self) -> Option<&mut T> {
     ///
     /// dl.push_front(1);
     /// assert_eq!(dl.front().unwrap(), &1);
-    ///
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_front(&mut self, elt: T) {
@@ -471,9 +529,7 @@ pub fn push_front(&mut self, elt: T) {
     /// assert_eq!(d.pop_front(), Some(3));
     /// assert_eq!(d.pop_front(), Some(1));
     /// assert_eq!(d.pop_front(), None);
-    ///
     /// ```
-    ///
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pop_front(&mut self) -> Option<T> {
         self.pop_front_node().map(Node::into_element)
index 8ba5c6ffbf2ebd2c13c5f43c4690849031d9ba0e..f91d8a5f4e1e84d506fd4562fa69f27d87b4c72d 100644 (file)
@@ -59,7 +59,7 @@
 use core::hash;
 use core::iter::FromIterator;
 use core::mem;
-use core::ops::{self, Add, Index, IndexMut};
+use core::ops::{self, Add, AddAssign, Index, IndexMut};
 use core::ptr;
 use core::str::pattern::Pattern;
 use rustc_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER};
@@ -1132,18 +1132,62 @@ pub fn insert(&mut self, idx: usize, ch: char) {
         assert!(idx <= len);
         assert!(self.is_char_boundary(idx));
         let bits = ch.encode_utf8();
-        let bits = bits.as_slice();
-        let amt = bits.len();
+
+        unsafe {
+            self.insert_bytes(idx, bits.as_slice());
+        }
+    }
+
+    unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
+        let len = self.len();
+        let amt = bytes.len();
         self.vec.reserve(amt);
 
+        ptr::copy(self.vec.as_ptr().offset(idx as isize),
+                  self.vec.as_mut_ptr().offset((idx + amt) as isize),
+                  len - idx);
+        ptr::copy(bytes.as_ptr(),
+                  self.vec.as_mut_ptr().offset(idx as isize),
+                  amt);
+        self.vec.set_len(len + amt);
+    }
+
+    /// Inserts a string into this `String` at a byte position.
+    ///
+    /// This is an `O(n)` operation as it requires copying every element in the
+    /// buffer.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `idx` is larger than the `String`'s length, or if it does not
+    /// lie on a [`char`] boundary.
+    ///
+    /// [`char`]: ../../std/primitive.char.html
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(insert_str)]
+    ///
+    /// let mut s = String::from("bar");
+    ///
+    /// s.insert_str(0, "foo");
+    ///
+    /// assert_eq!("foobar", s);
+    /// ```
+    #[inline]
+    #[unstable(feature = "insert_str",
+               reason = "recent addition",
+               issue = "0")]
+    pub fn insert_str(&mut self, idx: usize, string: &str) {
+        let len = self.len();
+        assert!(idx <= len);
+        assert!(self.is_char_boundary(idx));
+
         unsafe {
-            ptr::copy(self.vec.as_ptr().offset(idx as isize),
-                      self.vec.as_mut_ptr().offset((idx + amt) as isize),
-                      len - idx);
-            ptr::copy(bits.as_ptr(),
-                      self.vec.as_mut_ptr().offset(idx as isize),
-                      amt);
-            self.vec.set_len(len + amt);
+            self.insert_bytes(idx, string.as_bytes());
         }
     }
 
@@ -1565,6 +1609,14 @@ fn add(mut self, other: &str) -> String {
     }
 }
 
+#[stable(feature = "stringaddassign", since = "1.12.0")]
+impl<'a> AddAssign<&'a str> for String {
+    #[inline]
+    fn add_assign(&mut self, other: &str) {
+        self.push_str(other);
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Index<ops::Range<usize>> for String {
     type Output = str;
index 518b94b5031b436f8f2372d86a2006fb83cc1af0..2d77b38879b8eb8a959f4920b51abbf6bc66f57c 100644 (file)
@@ -541,6 +541,14 @@ pub fn truncate(&mut self, len: usize) {
     /// Extracts a slice containing the entire vector.
     ///
     /// Equivalent to `&s[..]`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{self, Write};
+    /// let buffer = vec![1, 2, 3, 5, 8];
+    /// io::sink().write(buffer.as_slice()).unwrap();
+    /// ```
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
     pub fn as_slice(&self) -> &[T] {
@@ -550,6 +558,14 @@ pub fn as_slice(&self) -> &[T] {
     /// Extracts a mutable slice of the entire vector.
     ///
     /// Equivalent to `&mut s[..]`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{self, Read};
+    /// let mut buffer = vec![0; 3];
+    /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap();
+    /// ```
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
     pub fn as_mut_slice(&mut self) -> &mut [T] {
@@ -565,9 +581,37 @@ pub fn as_mut_slice(&mut self) -> &mut [T] {
     /// # Examples
     ///
     /// ```
-    /// let mut v = vec![1, 2, 3, 4];
+    /// use std::ptr;
+    ///
+    /// let mut vec = vec!['r', 'u', 's', 't'];
+    ///
+    /// unsafe {
+    ///     ptr::drop_in_place(&mut vec[3]);
+    ///     vec.set_len(3);
+    /// }
+    /// assert_eq!(vec, ['r', 'u', 's']);
+    /// ```
+    ///
+    /// In this example, there is a memory leak since the memory locations
+    /// owned by the vector were not freed prior to the `set_len` call:
+    ///
+    /// ```
+    /// let mut vec = vec!['r', 'u', 's', 't'];
+    ///
+    /// unsafe {
+    ///     vec.set_len(0);
+    /// }
+    /// ```
+    ///
+    /// In this example, the vector gets expanded from zero to four items
+    /// without any memory allocations occurring, resulting in vector
+    /// values of unallocated memory:
+    ///
+    /// ```
+    /// let mut vec: Vec<char> = Vec::new();
+    ///
     /// unsafe {
-    ///     v.set_len(1);
+    ///     vec.set_len(4);
     /// }
     /// ```
     #[inline]
index 84a0bbbd24983468ce4b639a9c736db07b193364..9e4428ec57d50db1eaf6a1a95c725deeb921f28a 100644 (file)
@@ -365,12 +365,28 @@ unsafe fn handle_cap_increase(&mut self, old_cap: usize) {
 
 impl<T> VecDeque<T> {
     /// Creates an empty `VecDeque`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::VecDeque;
+    ///
+    /// let vector: VecDeque<u32> = VecDeque::new();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> VecDeque<T> {
         VecDeque::with_capacity(INITIAL_CAPACITY)
     }
 
     /// Creates an empty `VecDeque` with space for at least `n` elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::VecDeque;
+    ///
+    /// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(n: usize) -> VecDeque<T> {
         // +1 since the ringbuffer always leaves one space empty
@@ -696,6 +712,25 @@ pub fn iter_mut(&mut self) -> IterMut<T> {
 
     /// Returns a pair of slices which contain, in order, the contents of the
     /// `VecDeque`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut vector: VecDeque<u32> = VecDeque::new();
+    ///
+    /// vector.push_back(0);
+    /// vector.push_back(1);
+    /// vector.push_back(2);
+    ///
+    /// assert_eq!(vector.as_slices(), (&[0u32, 1, 2] as &[u32], &[] as &[u32]));
+    ///
+    /// vector.push_front(10);
+    /// vector.push_front(9);
+    ///
+    /// assert_eq!(vector.as_slices(), (&[9u32, 10] as &[u32], &[0u32, 1, 2] as &[u32]));
+    /// ```
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
     pub fn as_slices(&self) -> (&[T], &[T]) {
@@ -715,6 +750,24 @@ pub fn as_slices(&self) -> (&[T], &[T]) {
 
     /// Returns a pair of slices which contain, in order, the contents of the
     /// `VecDeque`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut vector: VecDeque<u32> = VecDeque::new();
+    ///
+    /// vector.push_back(0);
+    /// vector.push_back(1);
+    ///
+    /// vector.push_front(10);
+    /// vector.push_front(9);
+    ///
+    /// vector.as_mut_slices().0[0] = 42;
+    /// vector.as_mut_slices().1[0] = 24;
+    /// assert_eq!(vector.as_slices(), (&[42u32, 10] as &[u32], &[24u32, 1] as &[u32]));
+    /// ```
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
     pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
@@ -789,7 +842,7 @@ pub fn is_empty(&self) -> bool {
     ///
     /// ```
     /// use std::collections::VecDeque;
-
+    ///
     /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
     /// assert_eq!(vec![3].into_iter().collect::<VecDeque<_>>(), v.drain(2..).collect());
     /// assert_eq!(vec![1, 2].into_iter().collect::<VecDeque<_>>(), v);
@@ -875,6 +928,22 @@ pub fn clear(&mut self) {
 
     /// Returns `true` if the `VecDeque` contains an element equal to the
     /// given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_deque_contains)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut vector: VecDeque<u32> = VecDeque::new();
+    ///
+    /// vector.push_back(0);
+    /// vector.push_back(1);
+    ///
+    /// assert_eq!(vector.contains(&1), true);
+    /// assert_eq!(vector.contains(&10), false);
+    /// ```
     #[unstable(feature = "vec_deque_contains", reason = "recently added",
                issue = "32630")]
     pub fn contains(&self, x: &T) -> bool
@@ -1404,6 +1473,7 @@ pub fn insert(&mut self, index: usize, value: T) {
     /// Returns `None` if `index` is out of bounds.
     ///
     /// # Examples
+    ///
     /// ```
     /// use std::collections::VecDeque;
     ///
index 895a679fc3dccf76b1d7efae56248e31733b3f54..e5eb8f21382bebd55d1779d3be20fb0b8b868695 100644 (file)
@@ -980,15 +980,19 @@ pub fn pad(&mut self, s: &str) -> Result {
             return self.buf.write_str(s);
         }
         // The `precision` field can be interpreted as a `max-width` for the
-        // string being formatted
-        if let Some(max) = self.precision {
-            // If there's a maximum width and our string is longer than
-            // that, then we must always have truncation. This is the only
-            // case where the maximum length will matter.
+        // string being formatted.
+        let s = if let Some(max) = self.precision {
+            // If our string is longer that the precision, then we must have
+            // truncation. However other flags like `fill`, `width` and `align`
+            // must act as always.
             if let Some((i, _)) = s.char_indices().skip(max).next() {
-                return self.buf.write_str(&s[..i])
+                &s[..i]
+            } else {
+                &s
             }
-        }
+        } else {
+            &s
+        };
         // The `width` field is more of a `min-width` parameter at this point.
         match self.width {
             // If we're under the maximum length, and there's no minimum length
index 045c1f9feafc605d12a8e727e05f613dfa0873c1..fe508adb71380089d4e313114288410fcb6274eb 100644 (file)
 use self::Option::*;
 
 use clone::Clone;
+use convert::From;
 use default::Default;
 use iter::ExactSizeIterator;
 use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator};
@@ -754,6 +755,13 @@ fn into_iter(mut self) -> IterMut<'a, T> {
     }
 }
 
+#[stable(since = "1.12.0", feature = "option_from")]
+impl<T> From<T> for Option<T> {
+    fn from(val: T) -> Option<T> {
+        Some(val)
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // The Option Iterators
 /////////////////////////////////////////////////////////////////////////////
index 0ad6a74d1013c60b562ed1d9ff7467b2bedd5075..32fdf5c204801b168aa409c7de4972cb02dd87ba 100644 (file)
 pub const DW_EH_PE_indirect: u8 = 0x80;
 
 #[derive(Copy, Clone)]
-pub struct EHContext {
+pub struct EHContext<'a> {
     pub ip: usize, // Current instruction pointer
     pub func_start: usize, // Address of the current function
-    pub text_start: usize, // Address of the code section
-    pub data_start: usize, // Address of the data section
+    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
+    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
 }
 
-pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<usize> {
+pub enum EHAction {
+    None,
+    Cleanup(usize),
+    Catch(usize),
+    Terminate,
+}
+
+pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
+
+pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
     if lsda.is_null() {
-        return None;
+        return EHAction::None;
     }
 
     let func_start = context.func_start;
@@ -77,32 +86,62 @@ pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<u
     let call_site_encoding = reader.read::<u8>();
     let call_site_table_length = reader.read_uleb128();
     let action_table = reader.ptr.offset(call_site_table_length as isize);
-    // Return addresses point 1 byte past the call instruction, which could
-    // be in the next IP range.
-    let ip = context.ip - 1;
-
-    while reader.ptr < action_table {
-        let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_action = reader.read_uleb128();
-        // Callsite table is sorted by cs_start, so if we've passed the ip, we
-        // may stop searching.
-        if ip < func_start + cs_start {
-            break;
+    let ip = context.ip;
+
+    if !USING_SJLJ_EXCEPTIONS {
+        while reader.ptr < action_table {
+            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
+            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
+            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
+            let cs_action = reader.read_uleb128();
+            // Callsite table is sorted by cs_start, so if we've passed the ip, we
+            // may stop searching.
+            if ip < func_start + cs_start {
+                break;
+            }
+            if ip < func_start + cs_start + cs_len {
+                if cs_lpad == 0 {
+                    return EHAction::None;
+                } else {
+                    let lpad = lpad_base + cs_lpad;
+                    return interpret_cs_action(cs_action, lpad);
+                }
+            }
         }
-        if ip < func_start + cs_start + cs_len {
-            if cs_lpad != 0 {
-                return Some(lpad_base + cs_lpad);
-            } else {
-                return None;
+        // If ip is not present in the table, call terminate.  This is for
+        // a destructor inside a cleanup, or a library routine the compiler
+        // was not expecting to throw
+        EHAction::Terminate
+    } else {
+        // SjLj version:
+        // The "IP" is an index into the call-site table, with two exceptions:
+        // -1 means 'no-action', and 0 means 'terminate'.
+        match ip as isize {
+           -1 => return EHAction::None,
+            0 => return EHAction::Terminate,
+            _ => (),
+        }
+        let mut idx = ip;
+        loop {
+            let cs_lpad = reader.read_uleb128();
+            let cs_action = reader.read_uleb128();
+            idx -= 1;
+            if idx == 0 {
+                // Can never have null landing pad for sjlj -- that would have
+                // been indicated by a -1 call site index.
+                let lpad = (cs_lpad + 1) as usize;
+                return interpret_cs_action(cs_action, lpad);
             }
         }
     }
-    // IP range not found: gcc's C++ personality calls terminate() here,
-    // however the rest of the languages treat this the same as cs_lpad == 0.
-    // We follow this suit.
-    None
+}
+
+fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
+    if cs_action == 0 {
+        EHAction::Cleanup(lpad)
+    } else {
+        EHAction::Catch(lpad)
+    }
 }
 
 #[inline]
@@ -140,18 +179,16 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
         DW_EH_PE_absptr => 0,
         // relative to address of the encoded value, despite the name
         DW_EH_PE_pcrel => reader.ptr as usize,
-        DW_EH_PE_textrel => {
-            assert!(context.text_start != 0);
-            context.text_start
-        }
-        DW_EH_PE_datarel => {
-            assert!(context.data_start != 0);
-            context.data_start
-        }
         DW_EH_PE_funcrel => {
             assert!(context.func_start != 0);
             context.func_start
         }
+        DW_EH_PE_textrel => {
+            (*context.get_text_start)()
+        }
+        DW_EH_PE_datarel => {
+            (*context.get_data_start)()
+        }
         _ => panic!(),
     };
 
index 3c46072e17e1a7753aa3939c7676efb8e54ff2bd..cdf772ad3b825481231305ff6ae887bbb9048566 100644 (file)
@@ -106,117 +106,96 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
     0x4d4f5a_00_52555354
 }
 
-// We could implement our personality routine in Rust, however exception
-// info decoding is tedious.  More importantly, personality routines have to
-// handle various platform quirks, which are not fun to maintain.  For this
-// reason, we attempt to reuse personality routine of the C language:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each thread's stack.
-// So we have two versions of the personality routine:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-//   so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//
-// See also: rustc_trans::trans::intrinsic::trans_gnu_try
-
-#[cfg(all(not(target_arch = "arm"),
-          not(all(windows, target_arch = "x86_64"))))]
+// All targets, except ARM which uses a slightly different ABI (however, iOS goes here as it uses
+// SjLj unwinding).  Also, 64-bit Windows implementation lives in seh64_gnu.rs
+#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))]
 pub mod eabi {
     use unwind as uw;
-    use libc::c_int;
+    use libc::{c_int, uintptr_t};
+    use dwarf::eh::{EHContext, EHAction, find_eh_action};
 
-    extern "C" {
-        fn __gcc_personality_v0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-                                -> uw::_Unwind_Reason_Code;
-    }
+    // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
+    // and TargetLowering::getExceptionSelectorRegister() for each architecture,
+    // then mapped to DWARF register numbers via register definition tables
+    // (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
+    // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
 
-    #[lang = "eh_personality"]
-    #[no_mangle]
-    extern "C" fn rust_eh_personality(version: c_int,
-                                      actions: uw::_Unwind_Action,
-                                      exception_class: uw::_Unwind_Exception_Class,
-                                      ue_header: *mut uw::_Unwind_Exception,
-                                      context: *mut uw::_Unwind_Context)
-                                      -> uw::_Unwind_Reason_Code {
-        unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
-    }
+    #[cfg(target_arch = "x86")]
+    const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
 
-    #[lang = "eh_personality_catch"]
-    #[no_mangle]
-    pub extern "C" fn rust_eh_personality_catch(version: c_int,
-                                                actions: uw::_Unwind_Action,
-                                                exception_class: uw::_Unwind_Exception_Class,
-                                                ue_header: *mut uw::_Unwind_Exception,
-                                                context: *mut uw::_Unwind_Context)
-                                                -> uw::_Unwind_Reason_Code {
+    #[cfg(target_arch = "x86_64")]
+    const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
 
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
-            // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        } else {
-            // cleanup phase
-            unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
-        }
-    }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
+    #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+    const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
 
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-pub mod eabi {
-    use unwind as uw;
-    use libc::c_int;
+    #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+    const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
 
-    extern "C" {
-        fn __gcc_personality_sj0(version: c_int,
-                                 actions: uw::_Unwind_Action,
-                                 exception_class: uw::_Unwind_Exception_Class,
-                                 ue_header: *mut uw::_Unwind_Exception,
-                                 context: *mut uw::_Unwind_Context)
-                                 -> uw::_Unwind_Reason_Code;
-    }
+    #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+    const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
 
+    // Based on GCC's C and C++ personality routines.  For reference, see:
+    // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
+    // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
     #[lang = "eh_personality"]
     #[no_mangle]
-    pub extern "C" fn rust_eh_personality(version: c_int,
-                                          actions: uw::_Unwind_Action,
-                                          exception_class: uw::_Unwind_Exception_Class,
-                                          ue_header: *mut uw::_Unwind_Exception,
-                                          context: *mut uw::_Unwind_Context)
-                                          -> uw::_Unwind_Reason_Code {
-        unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
+    #[allow(unused)]
+    unsafe extern "C" fn rust_eh_personality(version: c_int,
+                                             actions: uw::_Unwind_Action,
+                                             exception_class: uw::_Unwind_Exception_Class,
+                                             exception_object: *mut uw::_Unwind_Exception,
+                                             context: *mut uw::_Unwind_Context)
+                                             -> uw::_Unwind_Reason_Code {
+        if version != 1 {
+            return uw::_URC_FATAL_PHASE1_ERROR;
+        }
+        let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
+        let mut ip_before_instr: c_int = 0;
+        let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
+        let eh_context = EHContext {
+            // The return address points 1 byte past the call instruction,
+            // which could be in the next IP range in LSDA range table.
+            ip: if ip_before_instr != 0 { ip } else { ip - 1 },
+            func_start: uw::_Unwind_GetRegionStart(context),
+            get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
+            get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
+        };
+        let eh_action = find_eh_action(lsda, &eh_context);
+
+        if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
+            match eh_action {
+                EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
+                EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
+                EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
+            }
+        } else {
+            match eh_action {
+                EHAction::None => return uw::_URC_CONTINUE_UNWIND,
+                EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
+                    uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
+                    uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
+                    uw::_Unwind_SetIP(context, lpad);
+                    return uw::_URC_INSTALL_CONTEXT;
+                }
+                EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
+            }
+        }
     }
 
+    #[cfg(stage0)]
     #[lang = "eh_personality_catch"]
     #[no_mangle]
-    pub extern "C" fn rust_eh_personality_catch(version: c_int,
-                                                actions: uw::_Unwind_Action,
-                                                exception_class: uw::_Unwind_Exception_Class,
-                                                ue_header: *mut uw::_Unwind_Exception,
-                                                context: *mut uw::_Unwind_Context)
-                                                -> uw::_Unwind_Reason_Code {
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
-            // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        } else {
-            // cleanup phase
-            unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
-        }
+    pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int,
+                                                       actions: uw::_Unwind_Action,
+                                                       exception_class: uw::_Unwind_Exception_Class,
+                                                       ue_header: *mut uw::_Unwind_Exception,
+                                                       context: *mut uw::_Unwind_Context)
+                                                       -> uw::_Unwind_Reason_Code {
+        rust_eh_personality(version, actions, exception_class, ue_header, context)
     }
 }
 
-
 // ARM EHABI uses a slightly different personality routine signature,
 // but otherwise works the same.
 #[cfg(all(target_arch = "arm", not(target_os = "ios")))]
index b765ee6f81cf9a70468f9e02cfe3849c73a8ff08..11dd9befe0a82e940da630f68317591ef960187b 100644 (file)
 // Entry point for raising an exception, just delegates to the platform-specific
 // implementation.
 #[no_mangle]
+#[unwind]
 pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
     imp::panic(mem::transmute(raw::TraitObject {
         data: data as *mut (),
index 56801e8cb6bcf3d5583a7ca409a2aac4a8db965d..7dc428871b387f2e83792d468706fa8b6c99675f 100644 (file)
@@ -19,7 +19,7 @@
 use core::any::Any;
 use core::intrinsics;
 use core::ptr;
-use dwarf::eh;
+use dwarf::eh::{EHContext, EHAction, find_eh_action};
 use windows as c;
 
 // Define our exception codes:
@@ -81,6 +81,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
 // This is considered acceptable, because the behavior of throwing exceptions
 // through a C ABI boundary is undefined.
 
+#[cfg(stage0)]
 #[lang = "eh_personality_catch"]
 #[cfg(not(test))]
 unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD,
@@ -132,11 +133,17 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
 }
 
 unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
-    let eh_ctx = eh::EHContext {
-        ip: dc.ControlPc as usize,
+    let eh_ctx = EHContext {
+        // The return address points 1 byte past the call instruction,
+        // which could be in the next IP range in LSDA range table.
+        ip: dc.ControlPc as usize - 1,
         func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
-        text_start: dc.ImageBase as usize,
-        data_start: 0,
+        get_text_start: &|| dc.ImageBase as usize,
+        get_data_start: &|| unimplemented!(),
     };
-    eh::find_landing_pad(dc.HandlerData, &eh_ctx)
+    match find_eh_action(dc.HandlerData, &eh_ctx) {
+        EHAction::None => None,
+        EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad),
+        EHAction::Terminate => intrinsics::abort(),
+    }
 }
index 65b97abfccbd75f5cb456115f24431e70340939a..a0c2416d24cff97d58815849830aec33e81ba55a 100644 (file)
@@ -747,6 +747,8 @@ fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
           "set the MIR optimization level (0-3)"),
     dump_mir: Option<String> = (None, parse_opt_string,
           "dump MIR state at various points in translation"),
+    dump_mir_dir: Option<String> = (None, parse_opt_string,
+          "the directory the MIR is dumped into"),
     orbit: bool = (false, parse_bool,
           "get MIR where it belongs - everywhere; most importantly, in orbit"),
 }
index 794e4d4996c9422ab649bd38e81be71e962aaf8c..ceb17e53a5552e41540b94e3d850f72d4d08b07c 100644 (file)
@@ -22,7 +22,7 @@ pub fn target() -> Target {
         target_vendor: "unknown".to_string(),
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
-            features: "+mips32r2,+soft-float".to_string(),
+            features: "+mips32r2".to_string(),
             max_atomic_width: 32,
             ..super::linux_base::opts()
         },
index a3c707e82a0ff45e45be5c74e951c184296f8cb5..4643686786be64c861c6a8a34140421928a7cc16 100644 (file)
@@ -1105,11 +1105,25 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty)
         Float(f) => cast_const_float(tcx, f, ty),
         Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
         Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
-        ByteStr(_) => match ty.sty {
+        ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
             },
-            ty::TyRef(..) => Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")),
+            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
+                ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
+                ty::TySlice(_) => {
+                    Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
+                },
+                _ => Err(CannotCast),
+            },
+            _ => Err(CannotCast),
+        },
+        Str(s) => match ty.sty {
+            ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
+            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
+                ty::TyStr => Ok(Str(s)),
+                _ => Err(CannotCast),
+            },
             _ => Err(CannotCast),
         },
         _ => Err(CannotCast),
index c9ca1a963a42a5a9d38c40ed335c51bf0409e0e0..d1b88ddda0c674987bb3e605b315b9cc20330b36 100644 (file)
@@ -19,6 +19,7 @@
 use std::fs;
 use std::io::{self, Write};
 use syntax::ast::NodeId;
+use std::path::{PathBuf, Path};
 
 const INDENT: &'static str = "    ";
 /// Alignment for lining up comments following MIR statements
@@ -66,9 +67,15 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         _ => String::new()
     };
 
+    let mut file_path = PathBuf::new();
+    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
+        let p = Path::new(file_dir);
+        file_path.push(p);
+    };
     let file_name = format!("rustc.node{}{}.{}.{}.mir",
                             node_id, promotion_id, pass_name, disambiguator);
-    let _ = fs::File::create(&file_name).and_then(|mut file| {
+    file_path.push(&file_name);
+    let _ = fs::File::create(&file_path).and_then(|mut file| {
         try!(writeln!(file, "// MIR for `{}`", node_path));
         try!(writeln!(file, "// node_id = {}", node_id));
         try!(writeln!(file, "// pass_name = {}", pass_name));
index c8b9fea15ba8b0e12cb4c3557411deddb8f3b056..ea8c248d0239fb2fd842c8f5af9e913f5fbf31d3 100644 (file)
 use Disr;
 use util::common::indenter;
 use util::sha2::Sha256;
-use util::nodemap::{NodeMap, NodeSet};
+use util::nodemap::{NodeMap, NodeSet, FnvHashSet};
 
 use arena::TypedArena;
 use libc::c_uint;
 use std::ffi::{CStr, CString};
+use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
 use std::ptr;
 use std::rc::Rc;
 use std::str;
@@ -2256,12 +2257,20 @@ fn write_metadata(cx: &SharedCrateContext,
 
 /// Find any symbols that are defined in one compilation unit, but not declared
 /// in any other compilation unit.  Give these symbols internal linkage.
-fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
+fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>,
+                                 symbol_map: &SymbolMap<'tcx>,
+                                 reachable: &FnvHashSet<&str>) {
+    let scx = ccxs.shared();
+    let tcx = scx.tcx();
+
+    // 'unsafe' because we are holding on to CStr's from the LLVM module within
+    // this block.
     unsafe {
-        let mut declared = HashSet::new();
+        let mut referenced_somewhere = FnvHashSet();
 
-        // Collect all external declarations in all compilation units.
-        for ccx in cx.iter() {
+        // Collect all symbols that need to stay externally visible because they
+        // are referenced via a declaration in some other codegen unit.
+        for ccx in ccxs.iter() {
             for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
                 let linkage = llvm::LLVMGetLinkage(val);
                 // We only care about external declarations (not definitions)
@@ -2270,39 +2279,67 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
                 let is_decl = llvm::LLVMIsDeclaration(val) != 0;
 
                 if is_decl || is_available_externally {
-                    let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
-                    declared.insert(name);
+                    let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val));
+                    referenced_somewhere.insert(symbol_name);
                 }
             }
         }
 
+        // Also collect all symbols for which we cannot adjust linkage, because
+        // it is fixed by some directive in the source code (e.g. #[no_mangle]).
+        let linkage_fixed_explicitly: FnvHashSet<_> = scx
+            .translation_items()
+            .borrow()
+            .iter()
+            .cloned()
+            .filter(|trans_item|{
+                let def_id = match *trans_item {
+                    TransItem::DropGlue(..) => {
+                        return false
+                    },
+                    TransItem::Fn(ref instance) => {
+                        instance.def
+                    }
+                    TransItem::Static(node_id) => {
+                        tcx.map.local_def_id(node_id)
+                    }
+                };
+
+                trans_item.explicit_linkage(tcx).is_some() ||
+                attr::contains_extern_indicator(tcx.sess.diagnostic(),
+                                                &tcx.get_attrs(def_id))
+            })
+            .map(|trans_item| symbol_map.get_or_compute(scx, trans_item))
+            .collect();
+
         // Examine each external definition.  If the definition is not used in
         // any other compilation unit, and is not reachable from other crates,
         // then give it internal linkage.
-        for ccx in cx.iter() {
+        for ccx in ccxs.iter() {
             for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
                 let linkage = llvm::LLVMGetLinkage(val);
 
                 let is_externally_visible = (linkage == llvm::ExternalLinkage as c_uint) ||
                                             (linkage == llvm::LinkOnceODRLinkage as c_uint) ||
                                             (linkage == llvm::WeakODRLinkage as c_uint);
-                let is_definition = llvm::LLVMIsDeclaration(val) != 0;
+                let is_definition = llvm::LLVMIsDeclaration(val) == 0;
 
                 // If this is a definition (as opposed to just a declaration)
                 // and externally visible, check if we can internalize it
                 if is_definition && is_externally_visible {
                     let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val));
                     let name_str = name_cstr.to_str().unwrap();
+                    let name_cow = Cow::Borrowed(name_str);
 
-                    let is_referenced_somewhere = declared.contains(&name_cstr);
-                    let is_reachable = reachable.contains(name_str);
+                    let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr);
+                    let is_reachable = reachable.contains(&name_str);
+                    let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow);
 
-                    if !is_referenced_somewhere && !is_reachable {
+                    if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage {
                         llvm::SetLinkage(val, llvm::InternalLinkage);
                         llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
                         llvm::UnsetComdat(val);
                     }
-
                 }
             }
         }
@@ -2616,8 +2653,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }));
     }
 
-    internalize_symbols(&crate_context_list,
-                        &reachable_symbols.iter().map(|x| &x[..]).collect());
+    time(shared_ccx.sess().time_passes(), "internalize symbols", || {
+        internalize_symbols(&crate_context_list,
+                            &symbol_map,
+                            &reachable_symbols.iter()
+                                              .map(|s| &s[..])
+                                              .collect())
+    });
 
     if sess.target.target.options.is_like_msvc &&
        sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
index a721361fce0e3aecbbd152edb8fd663507383df3..f033b278fe7f07230600e79b6793344d70a66ba2 100644 (file)
@@ -1193,11 +1193,17 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // managed by the standard library.
 
         attributes::emit_uwtable(bcx.fcx.llfn, true);
-        let catch_pers = match tcx.lang_items.eh_personality_catch() {
-            Some(did) => {
-                Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val
+        let target = &bcx.sess().target.target;
+        let catch_pers = if target.arch == "arm" && target.target_os != "ios" {
+            // Only ARM still uses a separate catch personality (for now)
+            match tcx.lang_items.eh_personality_catch() {
+                Some(did) => {
+                    Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val
+                }
+                None => bug!("eh_personality_catch not defined"),
             }
-            None => bug!("eh_personality_catch not defined"),
+        } else {
+            bcx.fcx.eh_personality()
         };
 
         let then = bcx.fcx.new_temp_block("then");
index 096e1ecc9ffb6a33a67b1dceb84a2b8837dd1d26..6cb79d6e8630f570d0ff065b37db361ed2c1795d 100644 (file)
@@ -233,6 +233,7 @@ fn write_token<W: Writer>(&mut self,
             token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi |
                 token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) |
                 token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) |
+                token::CloseDelim(token::NoDelim) |
                 token::Question => Class::None,
             token::Dollar => {
                 if self.lexer.peek().tok.is_ident() {
index 303cc671f4a230c79181cd8ad91ad8b66992b237..de0457592fc8834cfa5bbc62cf38bd2c1182f2fc 100644 (file)
@@ -636,8 +636,11 @@ span.since {
     margin-right: 5px;
 }
 
-.enum > .toggle-wrapper > .collapse-toggle, .struct > .toggle-wrapper > .collapse-toggle {
+.toggle-wrapper > .collapse-toggle {
     left: 0;
+}
+
+.variant + .toggle-wrapper > a {
     margin-top: 5px;
 }
 
index d4b09807e749b1b2eddf3f1f78196cef1fd0c3b9..ed5ac3bc0c1605773a46052603da33761f8582cc 100644 (file)
@@ -1351,6 +1351,20 @@ pub enum Entry<'a, K: 'a, V: 'a> {
     ),
 }
 
+#[stable(feature= "debug_hash_map", since = "1.12.0")]
+impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            Vacant(ref v) => f.debug_tuple("Entry")
+                              .field(v)
+                              .finish(),
+            Occupied(ref o) => f.debug_tuple("Entry")
+                                .field(o)
+                                .finish(),
+        }
+    }
+}
+
 /// A view into a single occupied location in a HashMap.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
@@ -1358,6 +1372,16 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
     elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
 }
 
+#[stable(feature= "debug_hash_map", since = "1.12.0")]
+impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("OccupiedEntry")
+         .field("key", self.key())
+         .field("value", self.get())
+         .finish()
+    }
+}
+
 /// A view into a single empty location in a HashMap.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct VacantEntry<'a, K: 'a, V: 'a> {
@@ -1366,6 +1390,15 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> {
     elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
 }
 
+#[stable(feature= "debug_hash_map", since = "1.12.0")]
+impl<'a, K: 'a + Debug, V: 'a> Debug for VacantEntry<'a, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_tuple("VacantEntry")
+         .field(self.key())
+         .finish()
+    }
+}
+
 /// Possible states of a VacantEntry.
 enum VacantEntryState<K, V, M> {
     /// The index is occupied, but the key to insert has precedence,
index 83439b3f132153eef1009c507e2bec78318aa408..c28f70b8692ad7a739e1b8a83e3564bac642ba07 100644 (file)
@@ -791,8 +791,8 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
 impl DirEntry {
     /// Returns the full path to the file that this entry represents.
     ///
-    /// The full path is created by joining the original path to `read_dir` or
-    /// `walk_dir` with the filename of this entry.
+    /// The full path is created by joining the original path to `read_dir`
+    /// with the filename of this entry.
     ///
     /// # Examples
     ///
index d96fd6228e62ebe57a1388159b8431699bfa1edc..11f785dffd16a6b1f67cc0f5e542c02aa23c937a 100644 (file)
@@ -311,6 +311,17 @@ pub struct Iter<'a, T: 'a> {
     rx: &'a Receiver<T>
 }
 
+/// An iterator that attempts to yield all pending values for a receiver.
+/// `None` will be returned when there are no pending values remaining or
+/// if the corresponding channel has hung up.
+///
+/// This Iterator will never block the caller in order to wait for data to
+/// become available. Instead, it will return `None`.
+#[unstable(feature = "receiver_try_iter", issue = "34931")]
+pub struct TryIter<'a, T: 'a> {
+    rx: &'a Receiver<T>
+}
+
 /// An owning iterator over messages on a receiver, this iterator will block
 /// whenever `next` is called, waiting for a new message, and `None` will be
 /// returned when the corresponding channel has hung up.
@@ -982,6 +993,16 @@ fn recv_max_until(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
     pub fn iter(&self) -> Iter<T> {
         Iter { rx: self }
     }
+
+    /// Returns an iterator that will attempt to yield all pending values.
+    /// It will return `None` if there are no more pending values or if the
+    /// channel has hung up. The iterator will never `panic!` or block the
+    /// user by waiting for values.
+    #[unstable(feature = "receiver_try_iter", issue = "34931")]
+    pub fn try_iter(&self) -> TryIter<T> {
+        TryIter { rx: self }
+    }
+
 }
 
 impl<T> select::Packet for Receiver<T> {
@@ -1077,6 +1098,13 @@ impl<'a, T> Iterator for Iter<'a, T> {
     fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
 }
 
+#[unstable(feature = "receiver_try_iter", issue = "34931")]
+impl<'a, T> Iterator for TryIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> { self.rx.try_recv().ok() }
+}
+
 #[stable(feature = "receiver_into_iter", since = "1.1.0")]
 impl<'a, T> IntoIterator for &'a Receiver<T> {
     type Item = T;
@@ -1814,6 +1842,34 @@ fn test_recv_iter_break() {
         assert_eq!(count_rx.recv().unwrap(), 4);
     }
 
+    #[test]
+    fn test_recv_try_iter() {
+        let (request_tx, request_rx) = channel();
+        let (response_tx, response_rx) = channel();
+
+        // Request `x`s until we have `6`.
+        let t = thread::spawn(move|| {
+            let mut count = 0;
+            loop {
+                for x in response_rx.try_iter() {
+                    count += x;
+                    if count == 6 {
+                        return count;
+                    }
+                }
+                request_tx.send(()).unwrap();
+            }
+        });
+
+        for _ in request_rx.iter() {
+            if response_tx.send(2).is_err() {
+                break;
+            }
+        }
+
+        assert_eq!(t.join().unwrap(), 6);
+    }
+
     #[test]
     fn test_recv_into_iter_owned() {
         let mut iter = {
index ffc950d76dd27f43047bb06e54def08e5f265266..b70e270df54d2a08ef7169bd34219a1077cf6e8f 100644 (file)
@@ -581,9 +581,10 @@ fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> {
 
 fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
     let name = match delim {
-        token::Paren     => "Paren",
-        token::Bracket   => "Bracket",
-        token::Brace     => "Brace",
+        token::Paren   => "Paren",
+        token::Bracket => "Bracket",
+        token::Brace   => "Brace",
+        token::NoDelim => "NoDelim",
     };
     mk_token_path(cx, sp, name)
 }
index 125f1abb062bf2966b17a31cb428edd4a8fe6620..c143e190c6fc16ce814c785d88aab8e0d5889974 100644 (file)
@@ -258,6 +258,7 @@ pub struct Parser<'a> {
     pub tokens_consumed: usize,
     pub restrictions: Restrictions,
     pub quote_depth: usize, // not (yet) related to the quasiquoter
+    parsing_token_tree: bool,
     pub reader: Box<Reader+'a>,
     /// The set of seen errors about obsolete syntax. Used to suppress
     /// extra detail when the same error is seen twice
@@ -374,6 +375,7 @@ pub fn new(sess: &'a ParseSess,
             tokens_consumed: 0,
             restrictions: Restrictions::empty(),
             quote_depth: 0,
+            parsing_token_tree: false,
             obsolete_set: HashSet::new(),
             mod_path_stack: Vec::new(),
             filename: filename,
@@ -2663,7 +2665,7 @@ fn parse_unquoted(&mut self) -> PResult<'a, TokenTree> {
     }
 
     pub fn check_unknown_macro_variable(&mut self) {
-        if self.quote_depth == 0 {
+        if self.quote_depth == 0 && !self.parsing_token_tree {
             match self.token {
                 token::SubstNt(name) =>
                     self.fatal(&format!("unknown macro variable `{}`", name)).emit(),
@@ -2723,6 +2725,7 @@ pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
                 Err(err)
             },
             token::OpenDelim(delim) => {
+                let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true);
                 // The span for beginning of the delimited section
                 let pre_span = self.span;
 
@@ -2787,6 +2790,7 @@ pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
                     _ => {}
                 }
 
+                self.parsing_token_tree = parsing_token_tree;
                 Ok(TokenTree::Delimited(span, Rc::new(Delimited {
                     delim: delim,
                     open_span: open_span,
index f0a6f8edeec73a241622a50a937b604c5896c6bd..6fdc9b714d34724202173d5417087ba1ea0bd4f3 100644 (file)
@@ -48,6 +48,8 @@ pub enum DelimToken {
     Bracket,
     /// A curly brace: `{` or `}`
     Brace,
+    /// An empty delimiter
+    NoDelim,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
index 8866ffc2575cca42176d10f1c77c1162d67d2446..a619da84b2d510529d679312641bf89b257b50e0 100644 (file)
@@ -242,6 +242,8 @@ pub fn token_to_string(tok: &Token) -> String {
         token::CloseDelim(token::Bracket) => "]".to_string(),
         token::OpenDelim(token::Brace) => "{".to_string(),
         token::CloseDelim(token::Brace) => "}".to_string(),
+        token::OpenDelim(token::NoDelim) => " ".to_string(),
+        token::CloseDelim(token::NoDelim) => " ".to_string(),
         token::Pound                => "#".to_string(),
         token::Dollar               => "$".to_string(),
         token::Question             => "?".to_string(),
@@ -1777,12 +1779,14 @@ pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
                 try!(self.head(""));
                 try!(self.bopen());
             }
+            token::NoDelim => {}
         }
         try!(self.print_tts(&m.node.tts));
         match delim {
             token::Paren => self.pclose(),
             token::Bracket => word(&mut self.s, "]"),
             token::Brace => self.bclose(m.span),
+            token::NoDelim => Ok(()),
         }
     }
 
index 7dfe19452a2a933a64cdd849e2a21ce535880f50..c96be8fec2b02abb4ffffecddaa0884187641303 100644 (file)
@@ -193,20 +193,6 @@ pub fn new() -> MultiSpan {
         }
     }
 
-    pub fn from_span(primary_span: Span) -> MultiSpan {
-        MultiSpan {
-            primary_spans: vec![primary_span],
-            span_labels: vec![]
-        }
-    }
-
-    pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
-        MultiSpan {
-            primary_spans: vec,
-            span_labels: vec![]
-        }
-    }
-
     pub fn push_span_label(&mut self, span: Span, label: String) {
         self.span_labels.push((span, label));
     }
@@ -254,7 +240,10 @@ pub fn span_labels(&self) -> Vec<SpanLabel> {
 
 impl From<Span> for MultiSpan {
     fn from(span: Span) -> MultiSpan {
-        MultiSpan::from_span(span)
+        MultiSpan {
+            primary_spans: vec![span],
+            span_labels: vec![]
+        }
     }
 }
 
index aadfe202afe796ba6d05257e5df80196e0aff51d..d9b6c9ed74dd21b4fec9ec88ebbce37b27990ea3 100644 (file)
@@ -58,6 +58,7 @@ pub enum _Unwind_Reason_Code {
 pub type _Unwind_Exception_Class = u64;
 
 pub type _Unwind_Word = libc::uintptr_t;
+pub type _Unwind_Ptr = libc::uintptr_t;
 
 pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void)
                                           -> _Unwind_Reason_Code;
@@ -156,6 +157,13 @@ pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
                              ip_before_insn: *mut libc::c_int)
                              -> libc::uintptr_t;
 
+    pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+    pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: libc::c_int, value: _Unwind_Ptr);
+    pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Ptr);
+
     #[cfg(all(not(target_os = "android"),
               not(all(target_os = "linux", target_arch = "arm"))))]
     pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void;
diff --git a/src/test/codegen/internalize-closures.rs b/src/test/codegen/internalize-closures.rs
new file mode 100644 (file)
index 0000000..90aafd6
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+pub fn main() {
+
+    // We want to make sure that closures get 'internal' linkage instead of
+    // 'weak_odr' when they are not shared between codegen units
+    // CHECK: define internal {{.*}}_ZN20internalize_closures4main{{.*}}$u7b$$u7b$closure$u7d$$u7d$
+    let c = |x:i32| { x + 1 };
+    let _ = c(1);
+}
diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md
new file mode 100644 (file)
index 0000000..9144e97
--- /dev/null
@@ -0,0 +1,44 @@
+This folder contains tests for MIR optimizations.
+
+The test format is:
+
+```
+(arbitrary rust code)
+// END RUST SOURCE
+// START $file_name_of_some_mir_dump_0
+//  $expected_line_0
+// ...
+// $expected_line_N
+// END $file_name_of_some_mir_dump_0
+// ...
+// START $file_name_of_some_mir_dump_N
+//  $expected_line_0
+// ...
+// $expected_line_N
+// END $file_name_of_some_mir_dump_N
+```
+
+All the test information is in comments so the test is runnable.
+
+For each $file_name, compiletest expects [$expected_line_0, ...,
+$expected_line_N] to appear in the dumped MIR in order.  Currently it allows
+other non-matched lines before, after and in-between.  
+
+Lines match ignoring whitespace, and the prefix "//" is removed.
+
+It also currently strips trailing comments -- partly because the full file path
+in "scope comments" is unpredictable and partly because tidy complains about
+the lines being too long.
+
+compiletest handles dumping the MIR before and after every pass for you.  The
+test writer only has to specify the file names of the dumped files (not the
+full path to the file) and what lines to expect.  I added an option to rustc
+that tells it to dump the mir into some directly (rather then always dumping to
+the current directory).  
+
+Lines match ignoring whitespace, and the prefix "//" is removed of course.
+
+It also currently strips trailing comments -- partly because the full file path
+in "scope comments" is unpredictable and partly because tidy complains about
+the lines being too long.
+
diff --git a/src/test/mir-opt/return_an_array.rs b/src/test/mir-opt/return_an_array.rs
new file mode 100644 (file)
index 0000000..4409f16
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// this tests move up progration, which is not yet implemented
+
+fn foo() -> [u8; 1024] {
+        let x = [0; 1024];
+        return x;
+}
+
+fn main() { }
\ No newline at end of file
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
new file mode 100644 (file)
index 0000000..dd6a857
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    if false {
+        println!("hello world!");
+    }
+}
+
+// END RUST SOURCE
+// START rustc.node4.SimplifyBranches.initial-before.mir
+// bb0: {
+//     if(const false) -> [true: bb1, false: bb2]; // scope 0 at simplify_if.rs:12:5: 14:6
+// }
+// END rustc.node4.SimplifyBranches.initial-before.mir
+// START rustc.node4.SimplifyBranches.initial-after.mir
+// bb0: {
+//     goto -> bb2;                     // scope 0 at simplify_if.rs:12:5: 14:6
+// }
+// END rustc.node4.SimplifyBranches.initial-after.mir
\ No newline at end of file
index 2f265b9112b9809be21c450095f950cead56a0bc..7297c71a6d668b7aa2844d4f9714858166f53cd3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -12,4 +12,7 @@
 
 pub fn main() {
     let _ = b"x" as &[u8];
+    let _ = b"y" as &[u8; 1];
+    let _ = b"z" as *const u8;
+    let _ = "รค" as *const str;
 }
index 0a69ccf47dd9f99959e154c3b12e949670a377c4..ed56519d23628c26ae4092151b490c923276ffce 100644 (file)
@@ -125,7 +125,7 @@ pub fn main() {
     t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
     t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
     t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "      aaaa");
     t!(format!("{:2.4}", "aaaaa"), "aaaa");
     t!(format!("{:2.4}", "aaaa"), "aaaa");
     t!(format!("{:2.4}", "aaa"), "aaa");
@@ -140,6 +140,7 @@ pub fn main() {
     t!(format!("{:a$}", "a", a=4), "a   ");
     t!(format!("{:-#}", "a"), "a");
     t!(format!("{:+#}", "a"), "a");
+    t!(format!("{:/^10.8}", "1234567890"), "/12345678/");
 
     // Some float stuff
     t!(format!("{:}", 1.0f32), "1");
index 52e19b37d7935659707399c89ba330b4b6a108c4..c982e8ac6f83e2927c8e81a63b11d4152786df34 100644 (file)
@@ -16,7 +16,16 @@ macro_rules! anon { $lhs => $rhs }
     });
 }
 
+macro_rules! outer {
+    ($x:expr; $fragment:ident) => {
+        macro_rules! inner { ($y:$fragment) => { $x + $y } }
+    }
+}
+
 fn main() {
     let val = higher_order!(subst ($x:expr, $y:expr, $foo:expr) => (($x + $y, $foo)));
     assert_eq!(val, (3, "foo"));
+
+    outer!(2; expr);
+    assert_eq!(inner!(3), 5);
 }
index 5ec62e06e37aea6bee989fb95e15229cf1b42b6e..2a35fab9676a71b9f45bea98a44a6409553df18a 100644 (file)
@@ -29,6 +29,7 @@ pub enum Mode {
     Incremental,
     RunMake,
     Ui,
+    MirOpt,
 }
 
 impl FromStr for Mode {
@@ -49,6 +50,7 @@ fn from_str(s: &str) -> Result<Mode, ()> {
           "incremental" => Ok(Incremental),
           "run-make" => Ok(RunMake),
           "ui" => Ok(Ui),
+          "mir-opt" => Ok(MirOpt),
           _ => Err(()),
         }
     }
@@ -71,6 +73,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             Incremental => "incremental",
             RunMake => "run-make",
             Ui => "ui",
+            MirOpt => "mir-opt",
         }, f)
     }
 }
index 6830f32bb2ce117bb522b0762ef4a57fdf04a15f..cefcc11486fe230c8659e989e3575d0233e7c47c 100644 (file)
@@ -86,7 +86,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
           reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
           reqopt("", "mode", "which sort of compile tests to run",
                  "(compile-fail|parse-fail|run-fail|run-pass|\
-                  run-pass-valgrind|pretty|debug-info|incremental)"),
+                  run-pass-valgrind|pretty|debug-info|incremental|mir-opt)"),
           optflag("", "ignored", "run tests marked as ignored"),
           optopt("", "runtool", "supervisor program to run tests under \
                                  (eg. emulator, valgrind)", "PROGRAM"),
index 577da5c5af11d2b012eed6d4f860731c3050a452..f2acfa517ced5b3e36aa75afa5537ac5cfbcbf1f 100644 (file)
@@ -11,7 +11,7 @@
 use common::Config;
 use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
 use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
-use common::{Incremental, RunMake, Ui};
+use common::{Incremental, RunMake, Ui, MirOpt};
 use errors::{self, ErrorKind, Error};
 use json;
 use header::TestProps;
@@ -117,6 +117,7 @@ fn run_revision(&self) {
             Incremental => self.run_incremental_test(),
             RunMake => self.run_rmake_test(),
             Ui => self.run_ui_test(),
+            MirOpt => self.run_mir_opt_test(),
         }
     }
 
@@ -1336,7 +1337,22 @@ fn make_compile_args(&self,
                                 .map(|s| s.to_string()));
                 }
             }
+            MirOpt => {
+                args.extend(["-Z",
+                             "dump-mir=all",
+                             "-Z"]
+                            .iter()
+                            .map(|s| s.to_string()));
 
+
+                let mir_dump_dir = self.get_mir_dump_dir();
+                self.create_dir_racy(mir_dump_dir.as_path());
+                let mut dir_opt = "dump-mir-dir=".to_string();
+                dir_opt.push_str(mir_dump_dir.to_str().unwrap());
+                debug!("dir_opt: {:?}", dir_opt);
+
+                args.push(dir_opt);
+            }
             RunFail |
             RunPass |
             RunPassValgrind |
@@ -2145,6 +2161,100 @@ fn run_ui_test(&self) {
         }
     }
 
+    fn run_mir_opt_test(&self) {
+        let proc_res = self.compile_test();
+
+        if !proc_res.status.success() {
+            self.fatal_proc_rec("compilation failed!", &proc_res);
+        }
+
+        let proc_res = self.exec_compiled_test();
+
+        if !proc_res.status.success() {
+            self.fatal_proc_rec("test run failed!", &proc_res);
+        }
+        self.check_mir_dump();
+    }
+
+    fn check_mir_dump(&self) {
+        let mut test_file_contents = String::new();
+        fs::File::open(self.testpaths.file.clone()).unwrap()
+                                                   .read_to_string(&mut test_file_contents)
+                                                   .unwrap();
+        if let Some(idx) =  test_file_contents.find("// END RUST SOURCE") {
+            let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len());
+            let tests_text_str = String::from(tests_text);
+            let mut curr_test : Option<&str> = None;
+            let mut curr_test_contents = Vec::new();
+            for l in tests_text_str.lines() {
+                debug!("line: {:?}", l);
+                if l.starts_with("// START ") {
+                    let (_, t) = l.split_at("// START ".len());
+                    curr_test = Some(t);
+                } else if l.starts_with("// END") {
+                    let (_, t) = l.split_at("// END ".len());
+                    if Some(t) != curr_test {
+                        panic!("mismatched START END test name");
+                    }
+                    self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents);
+                    curr_test = None;
+                    curr_test_contents.clear();
+                } else if l.is_empty() {
+                    // ignore
+                } else if l.starts_with("// ") {
+                    let (_, test_content) = l.split_at("// ".len());
+                    curr_test_contents.push(test_content);
+                }
+            }
+        }
+    }
+
+    fn compare_mir_test_output(&self, test_name: &str, expected_content: &Vec<&str>) {
+        let mut output_file = PathBuf::new();
+        output_file.push(self.get_mir_dump_dir());
+        output_file.push(test_name);
+        debug!("comparing the contests of: {:?}", output_file);
+        debug!("with: {:?}", expected_content);
+
+        let mut dumped_file = fs::File::open(output_file.clone()).unwrap();
+        let mut dumped_string = String::new();
+        dumped_file.read_to_string(&mut dumped_string).unwrap();
+        let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty());
+        let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty());
+
+        // We expect each non-empty line from expected_content to appear
+        // in the dump in order, but there may be extra lines interleaved
+        while let Some(expected_line) = expected_lines.next() {
+            let e_norm = normalize_mir_line(expected_line);
+            if e_norm.is_empty() {
+                continue;
+            };
+            let mut found = false;
+            while let Some(dumped_line) = dumped_lines.next() {
+                let d_norm = normalize_mir_line(dumped_line);
+                debug!("found: {:?}", d_norm);
+                debug!("expected: {:?}", e_norm);
+                if e_norm == d_norm {
+                    found = true;
+                    break;
+                };
+            }
+            if !found {
+                panic!("ran out of mir dump output to match against");
+            }
+        }
+    }
+
+    fn get_mir_dump_dir(&self) -> PathBuf {
+        let mut mir_dump_dir = PathBuf::from(self.config.build_base
+                                                    .as_path()
+                                                    .to_str()
+                                                    .unwrap());
+        debug!("input_file: {:?}", self.testpaths.file);
+        mir_dump_dir.push(self.testpaths.file.file_stem().unwrap().to_str().unwrap());
+        mir_dump_dir
+    }
+
     fn normalize_output(&self, output: &str) -> String {
         let parent_dir = self.testpaths.file.parent().unwrap();
         let parent_dir_str = parent_dir.display().to_string();
@@ -2274,3 +2384,12 @@ enum TargetLocation {
     ThisDirectory(PathBuf),
 }
 
+fn normalize_mir_line(line: &str) -> String {
+    let no_comments = if let Some(idx) = line.find("//") {
+        let (l, _) = line.split_at(idx);
+        l
+    } else {
+        line
+    };
+    no_comments.replace(char::is_whitespace, "")
+}