]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #41237 - frewsxcv:rollup, r=frewsxcv
authorbors <bors@rust-lang.org>
Wed, 12 Apr 2017 00:45:49 +0000 (00:45 +0000)
committerbors <bors@rust-lang.org>
Wed, 12 Apr 2017 00:45:49 +0000 (00:45 +0000)
Rollup of 8 pull requests

- Successful merges: #40377, #40559, #41173, #41202, #41204, #41209, #41216, #41231
- Failed merges:

33 files changed:
src/bootstrap/native.rs
src/ci/docker/run.sh
src/doc/unstable-book/src/SUMMARY.md
src/doc/unstable-book/src/manually-drop.md [new file with mode: 0644]
src/libcollections/lib.rs
src/libcollections/slice.rs
src/libcore/intrinsics.rs
src/libcore/iter/iterator.rs
src/libcore/mem.rs
src/libcore/slice/sort.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/ty/context.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc_data_structures/array_vec.rs
src/librustc_data_structures/lib.rs
src/librustc_driver/lib.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/mir/mod.rs
src/librustc_typeck/check/intrinsic.rs
src/librustdoc/html/markdown.rs
src/libstd/primitive_docs.rs
src/test/compile-fail/forget-init-unsafe.rs
src/test/run-pass/optimization-fuel-0.rs [new file with mode: 0644]
src/test/run-pass/optimization-fuel-1.rs [new file with mode: 0644]
src/test/run-pass/type-sizes.rs
src/test/ui/print-fuel/print-fuel.rs [new file with mode: 0644]
src/test/ui/print-fuel/print-fuel.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/nullable.stdout
src/test/ui/print_type_sizes/packed.stdout
src/test/ui/print_type_sizes/padding.stdout
src/tools/build-manifest/src/main.rs

index 62eed8be3ccb70764c9dacc9be320ddf855e2e8c..726e94e49a19ecf279e980438603df346dde52ab 100644 (file)
@@ -147,7 +147,7 @@ pub fn llvm(build: &Build, target: &str) {
     }
 
     if env::var_os("SCCACHE_ERROR_LOG").is_some() {
-        cfg.env("RUST_LOG", "sccache=debug");
+        cfg.env("RUST_LOG", "sccache=info");
     }
 
     // FIXME: we don't actually need to build all LLVM tools and all LLVM
index 71a4bfae3caf9424b930bf81aeba9a26b15e1a7e..59b93b784b2f6f27db319fc06d23c2fa93a4600c 100755 (executable)
@@ -38,7 +38,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then
     args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
     args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
     args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log"
-    args="$args --env SCCACHE_LOG_LEVEL=debug"
     args="$args --volume $objdir/tmp:/tmp/sccache"
 else
     mkdir -p $HOME/.cache/sccache
index 81c75e1326e412d7e2f7bc6b75168aff61553169..54e602a81db7389e93e2eb682e8c2371ce423223 100644 (file)
 - [loop_break_value](loop-break-value.md)
 - [macro_reexport](macro-reexport.md)
 - [main](main.md)
+- [manually_drop](manually-drop.md)
 - [map_entry_recover_keys](map-entry-recover-keys.md)
 - [mpsc_select](mpsc-select.md)
 - [n16](n16.md)
diff --git a/src/doc/unstable-book/src/manually-drop.md b/src/doc/unstable-book/src/manually-drop.md
new file mode 100644 (file)
index 0000000..e69de29
index 5360804f9e1d7a896a0b215385667eeff922be5c..99afd08e81183eb451df419c93a633b43456bb9c 100644 (file)
@@ -44,6 +44,7 @@
 #![feature(heap_api)]
 #![feature(inclusive_range)]
 #![feature(lang_items)]
+#![feature(manually_drop)]
 #![feature(nonzero)]
 #![feature(pattern)]
 #![feature(placement_in)]
index 6cff315a6ccd9eb28083d2b1f5b2afa9e8dc2430..3069adb12e92cd127c5bd29d03d266da23d49df4 100644 (file)
@@ -1558,7 +1558,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             //    performance than with the 2nd method.
             //
             // All methods were benchmarked, and the 3rd showed best results. So we chose that one.
-            let mut tmp = NoDrop { value: ptr::read(&v[0]) };
+            let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
 
             // Intermediate state of the insertion process is always tracked by `hole`, which
             // serves two purposes:
@@ -1571,13 +1571,13 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
             // initially held exactly once.
             let mut hole = InsertionHole {
-                src: &mut tmp.value,
+                src: &mut *tmp,
                 dest: &mut v[1],
             };
             ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
 
             for i in 2..v.len() {
-                if !is_less(&v[i], &tmp.value) {
+                if !is_less(&v[i], &*tmp) {
                     break;
                 }
                 ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1);
@@ -1587,12 +1587,6 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
         }
     }
 
-    // Holds a value, but never drops it.
-    #[allow(unions_with_drop_fields)]
-    union NoDrop<T> {
-        value: T
-    }
-
     // When dropped, copies from `src` into `dest`.
     struct InsertionHole<T> {
         src: *mut T,
index e0a4707ff665f58c0bdedbb8fed6f6e29bc897be..b0287631585125a9febd3fb903e5d51e2358ae8e 100644 (file)
     /// initialize memory previous set to the result of `uninit`.
     pub fn uninit<T>() -> T;
 
-    /// Moves a value out of scope without running drop glue.
-    pub fn forget<T>(_: T) -> ();
-
     /// Reinterprets the bits of a value of one type as another type.
     ///
     /// Both types must have the same size. Neither the original, nor the result,
index 618edf48abd04370a43073368ac33bedb3129754..8bf641e37fe467c2120defd6b1a90afc79b0674c 100644 (file)
@@ -1532,14 +1532,18 @@ fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
     /// Stopping at the first `true`:
     ///
     /// ```
-    /// let a = [1, 2, 3];
+    /// let a = [1, 2, 3, 4];
     ///
     /// let mut iter = a.iter();
     ///
-    /// assert_eq!(iter.position(|&x| x == 2), Some(1));
+    /// assert_eq!(iter.position(|&x| x >= 2), Some(1));
     ///
     /// // we can still use `iter`, as there are more elements.
     /// assert_eq!(iter.next(), Some(&3));
+    ///
+    /// // The returned index depends on iterator state
+    /// assert_eq!(iter.position(|&x| x == 4), Some(0));
+    ///
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
index f5cf3724d0711d8183e685a02d08878f37ad3e95..7be927b28ed7eb7ecfef5fcc8da2ab1d0cdc9410 100644 (file)
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn forget<T>(t: T) {
-    unsafe { intrinsics::forget(t) }
+    ManuallyDrop::new(t);
 }
 
 /// Returns the size of a type in bytes.
@@ -736,3 +736,121 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
     }
 }
 
+
+/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
+///
+/// This wrapper is 0-cost.
+///
+/// # Examples
+///
+/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
+/// the type:
+///
+/// ```rust
+/// # #![feature(manually_drop)]
+/// use std::mem::ManuallyDrop;
+/// struct Peach;
+/// struct Banana;
+/// struct Melon;
+/// struct FruitBox {
+///     // Immediately clear there’s something non-trivial going on with these fields.
+///     peach: ManuallyDrop<Peach>,
+///     melon: Melon, // Field that’s independent of the other two.
+///     banana: ManuallyDrop<Banana>,
+/// }
+///
+/// impl Drop for FruitBox {
+///     fn drop(&mut self) {
+///         unsafe {
+///             // Explicit ordering in which field destructors are run specified in the intuitive
+///             // location – the destructor of the structure containing the fields.
+///             // Moreover, one can now reorder fields within the struct however much they want.
+///             ManuallyDrop::drop(&mut self.peach);
+///             ManuallyDrop::drop(&mut self.banana);
+///         }
+///         // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
+///         // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
+///     }
+/// }
+/// ```
+#[unstable(feature = "manually_drop", issue = "40673")]
+#[allow(unions_with_drop_fields)]
+pub union ManuallyDrop<T>{ value: T }
+
+impl<T> ManuallyDrop<T> {
+    /// Wrap a value to be manually dropped.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # #![feature(manually_drop)]
+    /// use std::mem::ManuallyDrop;
+    /// ManuallyDrop::new(Box::new(()));
+    /// ```
+    #[unstable(feature = "manually_drop", issue = "40673")]
+    #[inline]
+    pub fn new(value: T) -> ManuallyDrop<T> {
+        ManuallyDrop { value: value }
+    }
+
+    /// Extract the value from the ManuallyDrop container.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # #![feature(manually_drop)]
+    /// use std::mem::ManuallyDrop;
+    /// let x = ManuallyDrop::new(Box::new(()));
+    /// let _: Box<()> = ManuallyDrop::into_inner(x);
+    /// ```
+    #[unstable(feature = "manually_drop", issue = "40673")]
+    #[inline]
+    pub fn into_inner(slot: ManuallyDrop<T>) -> T {
+        unsafe {
+            slot.value
+        }
+    }
+
+    /// Manually drops the contained value.
+    ///
+    /// # Unsafety
+    ///
+    /// This function runs the destructor of the contained value and thus the wrapped value
+    /// now represents uninitialized data. It is up to the user of this method to ensure the
+    /// uninitialized data is not actually used.
+    #[unstable(feature = "manually_drop", issue = "40673")]
+    #[inline]
+    pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
+        ptr::drop_in_place(&mut slot.value)
+    }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T> ::ops::Deref for ManuallyDrop<T> {
+    type Target = T;
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe {
+            &self.value
+        }
+    }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T> ::ops::DerefMut for ManuallyDrop<T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe {
+            &mut self.value
+        }
+    }
+}
+
+#[unstable(feature = "manually_drop", issue = "40673")]
+impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> {
+    fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result {
+        unsafe {
+            fmt.debug_tuple("ManuallyDrop").field(&self.value).finish()
+        }
+    }
+}
index 7065fdb79fc4040a6ca225634408141e1871a830..6f9f2915dfe102c1fe6022d660816e69279152ed 100644 (file)
 use mem;
 use ptr;
 
-/// Holds a value, but never drops it.
-#[allow(unions_with_drop_fields)]
-union NoDrop<T> {
-    value: T
-}
-
 /// When dropped, copies from `src` into `dest`.
 struct CopyOnDrop<T> {
     src: *mut T,
@@ -49,15 +43,15 @@ fn shift_head<T, F>(v: &mut [T], is_less: &mut F)
             // Read the first element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) };
+            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
             let mut hole = CopyOnDrop {
-                src: &mut tmp.value,
+                src: &mut *tmp,
                 dest: v.get_unchecked_mut(1),
             };
             ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1);
 
             for i in 2..len {
-                if !is_less(v.get_unchecked(i), &tmp.value) {
+                if !is_less(v.get_unchecked(i), &*tmp) {
                     break;
                 }
 
@@ -81,15 +75,15 @@ fn shift_tail<T, F>(v: &mut [T], is_less: &mut F)
             // Read the last element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) };
+            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
             let mut hole = CopyOnDrop {
-                src: &mut tmp.value,
+                src: &mut *tmp,
                 dest: v.get_unchecked_mut(len - 2),
             };
             ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1);
 
             for i in (0..len-2).rev() {
-                if !is_less(&tmp.value, v.get_unchecked(i)) {
+                if !is_less(&*tmp, v.get_unchecked(i)) {
                     break;
                 }
 
@@ -403,12 +397,12 @@ fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
 
         // Read the pivot into a stack-allocated variable for efficiency. If a following comparison
         // operation panics, the pivot will be automatically written back into the slice.
-        let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
+        let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
         let _pivot_guard = CopyOnDrop {
-            src: unsafe { &mut tmp.value },
+            src: &mut *tmp,
             dest: pivot,
         };
-        let pivot = unsafe { &tmp.value };
+        let pivot = &*tmp;
 
         // Find the first pair of out-of-order elements.
         let mut l = 0;
@@ -452,12 +446,12 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
 
     // Read the pivot into a stack-allocated variable for efficiency. If a following comparison
     // operation panics, the pivot will be automatically written back into the slice.
-    let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
+    let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
     let _pivot_guard = CopyOnDrop {
-        src: unsafe { &mut tmp.value },
+        src: &mut *tmp,
         dest: pivot,
     };
-    let pivot = unsafe { &tmp.value };
+    let pivot = &*tmp;
 
     // Now partition the slice.
     let mut l = 0;
index ef825a6854cec9b4ad7ea1f30e8c66206f05a2ec..b9a974045bced110527e953ebffe296dccceb6b6 100644 (file)
@@ -643,6 +643,8 @@ mod $mod_desc {
             Some("one of: `address`, `leak`, `memory` or `thread`");
         pub const parse_linker_flavor: Option<&'static str> =
             Some(::rustc_back::LinkerFlavor::one_of());
+        pub const parse_optimization_fuel: Option<&'static str> =
+            Some("crate=integer");
     }
 
     #[allow(dead_code)]
@@ -787,6 +789,21 @@ fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> boo
             }
             true
         }
+
+        fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+            match v {
+                None => false,
+                Some(s) => {
+                    let parts = s.split('=').collect::<Vec<_>>();
+                    if parts.len() != 2 { return false; }
+                    let crate_name = parts[0].to_string();
+                    let fuel = parts[1].parse::<u64>();
+                    if fuel.is_err() { return false; }
+                    *slot = Some((crate_name, fuel.unwrap()));
+                    true
+                }
+            }
+        }
     }
 ) }
 
@@ -991,6 +1008,10 @@ fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> boo
                                    "Use a sanitizer"),
     linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
                                            "Linker flavor"),
+    fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
+        "Set the optimization fuel quota for a crate."),
+    print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
+        "Make Rustc print the total optimization fuel used by a crate."),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -1784,11 +1805,13 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
 
     impl_dep_tracking_hash_via_hash!(bool);
     impl_dep_tracking_hash_via_hash!(usize);
+    impl_dep_tracking_hash_via_hash!(u64);
     impl_dep_tracking_hash_via_hash!(String);
     impl_dep_tracking_hash_via_hash!(lint::Level);
     impl_dep_tracking_hash_via_hash!(Option<bool>);
     impl_dep_tracking_hash_via_hash!(Option<usize>);
     impl_dep_tracking_hash_via_hash!(Option<String>);
+    impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
@@ -1810,6 +1833,7 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
                                                  Option<cstore::NativeLibraryKind>));
+    impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
     impl DepTrackingHash for SearchPaths {
         fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
             let mut elems: Vec<_> = self
index 70b2809ccbed2ba0ada1744a840cb35605350101..039db3d9ee9117484aa69847768089bbfcdf608b 100644 (file)
@@ -123,6 +123,20 @@ pub struct Session {
     pub code_stats: RefCell<CodeStats>,
 
     next_node_id: Cell<ast::NodeId>,
+
+    /// If -zfuel=crate=n is specified, Some(crate).
+    optimization_fuel_crate: Option<String>,
+    /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
+    optimization_fuel_limit: Cell<u64>,
+    /// We're rejecting all further optimizations.
+    out_of_fuel: Cell<bool>,
+
+    // The next two are public because the driver needs to read them.
+
+    /// If -zprint-fuel=crate, Some(crate).
+    pub print_fuel_crate: Option<String>,
+    /// Always set to zero and incremented so that we can print fuel expended by a crate.
+    pub print_fuel: Cell<u64>,
 }
 
 pub struct PerfStats {
@@ -507,6 +521,32 @@ pub fn print_perf_stats(&self) {
         println!("Total time spent decoding DefPath tables:      {}",
                  duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
     }
+
+    /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
+    /// This expends fuel if applicable, and records fuel if applicable.
+    pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
+        let mut ret = true;
+        match self.optimization_fuel_crate {
+            Some(ref c) if c == crate_name => {
+                let fuel = self.optimization_fuel_limit.get();
+                ret = fuel != 0;
+                if fuel == 0 && !self.out_of_fuel.get() {
+                    println!("optimization-fuel-exhausted: {}", msg());
+                    self.out_of_fuel.set(true);
+                } else if fuel > 0 {
+                    self.optimization_fuel_limit.set(fuel-1);
+                }
+            }
+            _ => {}
+        }
+        match self.print_fuel_crate {
+            Some(ref c) if c == crate_name=> {
+                self.print_fuel.set(self.print_fuel.get()+1);
+            },
+            _ => {}
+        }
+        ret
+    }
 }
 
 pub fn build_session(sopts: config::Options,
@@ -602,6 +642,12 @@ pub fn build_session_(sopts: config::Options,
         }
     );
 
+    let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
+    let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
+        .map(|i| i.1).unwrap_or(0));
+    let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
+    let print_fuel = Cell::new(0);
+
     let sess = Session {
         dep_graph: dep_graph.clone(),
         target: target_cfg,
@@ -643,6 +689,11 @@ pub fn build_session_(sopts: config::Options,
             decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
         },
         code_stats: RefCell::new(CodeStats::new()),
+        optimization_fuel_crate: optimization_fuel_crate,
+        optimization_fuel_limit: optimization_fuel_limit,
+        print_fuel_crate: print_fuel_crate,
+        print_fuel: print_fuel,
+        out_of_fuel: Cell::new(false),
     };
 
     init_llvm(&sess);
index da56514ea82fbf9e485c3f1f761ff9253f9b54cc..8b7438c0bfad2ed5f73efbfece42ffbbd22978d4 100644 (file)
@@ -732,6 +732,11 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        }, f)
     }
+
+    pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
+        let cname = self.crate_name(LOCAL_CRATE).as_str();
+        self.sess.consider_optimizing(&cname, msg)
+    }
 }
 
 impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
index 54e5de3909086d55728f54d8c35d6884b5ebda32..d7a4b3fda63bb84054d49fde393e1f2ef62e9fe3 100644 (file)
@@ -580,7 +580,6 @@ enum StructKind {
 }
 
 impl<'a, 'gcx, 'tcx> Struct {
-    // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
     fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
                   repr: &ReprOptions, kind: StructKind,
                   scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
@@ -598,12 +597,8 @@ fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
         // Neither do  1-member and 2-member structs.
         // In addition, code in trans assume that 2-element structs can become pairs.
         // It's easier to just short-circuit here.
-        let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
-            && ! (repr.c || repr.packed);
-
-        // Disable field reordering until we can decide what to do.
-        // The odd pattern here avoids a warning about the value never being read.
-        if can_optimize { can_optimize = false; }
+        let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
+            && !(repr.c || repr.packed || repr.linear || repr.simd);
 
         let (optimize, sort_ascending) = match kind {
             StructKind::AlwaysSizedUnivariant => (can_optimize, false),
index 292e30e3d41f19403353bfdd2a055ac4c1066daf..a2c356c20db09d563afa0e532dc964c39f139138 100644 (file)
@@ -1411,13 +1411,16 @@ pub struct ReprOptions {
     pub packed: bool,
     pub simd: bool,
     pub int: Option<attr::IntType>,
+    // Internal only for now. If true, don't reorder fields.
+    pub linear: bool,
 }
 
 impl_stable_hash_for!(struct ReprOptions {
     c,
     packed,
     simd,
-    int
+    int,
+    linear
 });
 
 impl ReprOptions {
@@ -1440,6 +1443,9 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
             ret.simd = true;
         }
 
+        // This is here instead of layout because the choice must make it into metadata.
+        ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}",
+            tcx.item_path_str(did)));
         ret
     }
 
index 29fbcb70756ba08adeca9c87caff42d202225183..adb22197226023fcb80731626f1ecc97255275f7 100644 (file)
 use std::mem;
 use std::collections::range::RangeArgument;
 use std::collections::Bound::{Excluded, Included, Unbounded};
+use std::mem::ManuallyDrop;
 
 pub unsafe trait Array {
     type Element;
-    type PartialStorage: Default + Unsize<[ManuallyDrop<Self::Element>]>;
+    type PartialStorage: Unsize<[ManuallyDrop<Self::Element>]>;
     const LEN: usize;
 }
 
@@ -66,7 +67,7 @@ impl<A: Array> ArrayVec<A> {
     pub fn new() -> Self {
         ArrayVec {
             count: 0,
-            values: Default::default(),
+            values: unsafe { ::std::mem::uninitialized() },
         }
     }
 
@@ -81,7 +82,7 @@ pub unsafe fn set_len(&mut self, len: usize) {
     /// Panics when the stack vector is full.
     pub fn push(&mut self, el: A::Element) {
         let arr = &mut self.values as &mut [ManuallyDrop<_>];
-        arr[self.count] = ManuallyDrop { value: el };
+        arr[self.count] = ManuallyDrop::new(el);
         self.count += 1;
     }
 
@@ -90,8 +91,8 @@ pub fn pop(&mut self) -> Option<A::Element> {
             let arr = &mut self.values as &mut [ManuallyDrop<_>];
             self.count -= 1;
             unsafe {
-                let value = ptr::read(&arr[self.count]);
-                Some(value.value)
+                let value = ptr::read(&*arr[self.count]);
+                Some(value)
             }
         } else {
             None
@@ -210,7 +211,7 @@ impl<A: Array> Iterator for Iter<A> {
     fn next(&mut self) -> Option<A::Element> {
         let arr = &self.store as &[ManuallyDrop<_>];
         unsafe {
-            self.indices.next().map(|i| ptr::read(&arr[i]).value)
+            self.indices.next().map(|i| ptr::read(&*arr[i]))
         }
     }
 
@@ -233,7 +234,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> {
 
     #[inline]
     fn next(&mut self) -> Option<A::Element> {
-        self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value })
+        self.iter.next().map(|elt| unsafe { ptr::read(&**elt) })
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
@@ -295,25 +296,3 @@ fn into_iter(self) -> Self::IntoIter {
         self.iter_mut()
     }
 }
-
-// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758.
-#[allow(unions_with_drop_fields)]
-pub union ManuallyDrop<T> {
-    value: T,
-    #[allow(dead_code)]
-    empty: (),
-}
-
-impl<T> ManuallyDrop<T> {
-    fn new() -> ManuallyDrop<T> {
-        ManuallyDrop {
-            empty: ()
-        }
-    }
-}
-
-impl<T> Default for ManuallyDrop<T> {
-    fn default() -> Self {
-        ManuallyDrop::new()
-    }
-}
index c1735b4a4ec9a588156757293152deb775fa1129..72c533a74618b8185eae1cb22807539ef56cdb4f 100644 (file)
@@ -39,6 +39,7 @@
 #![feature(conservative_impl_trait)]
 #![feature(discriminant_value)]
 #![feature(specialization)]
+#![feature(manually_drop)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
index c90dde3a5f6e0232694ae37dec7e11e70c91b446..1a892b73aa5d771c86f6f2dd1c09796763647997 100644 (file)
@@ -517,6 +517,16 @@ fn build_controller(&mut self,
             control.make_glob_map = resolve::MakeGlobMap::Yes;
         }
 
+        if sess.print_fuel_crate.is_some() {
+            let old_callback = control.compilation_done.callback;
+            control.compilation_done.callback = box move |state| {
+                old_callback(state);
+                let sess = state.session;
+                println!("Fuel used by {}: {}",
+                    sess.print_fuel_crate.as_ref().unwrap(),
+                    sess.print_fuel.get());
+            }
+        }
         control
     }
 }
index 5e7d612d17f82e21eb12904140b5b21cabaa9b36..7077eade61182af2387119e8dd0801d8e3b48062 100644 (file)
@@ -16,7 +16,7 @@
 use llvm::{ValueRef};
 use abi::{Abi, FnType};
 use adt;
-use mir::lvalue::LvalueRef;
+use mir::lvalue::{LvalueRef, Alignment};
 use base::*;
 use common::*;
 use declare;
@@ -36,8 +36,6 @@
 use std::cmp::Ordering;
 use std::iter;
 
-use mir::lvalue::Alignment;
-
 fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
     let llvm_name = match name {
         "sqrtf32" => "llvm.sqrt.f32",
@@ -188,7 +186,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             C_nil(ccx)
         }
         // Effectively no-ops
-        "uninit" | "forget" => {
+        "uninit" => {
             C_nil(ccx)
         }
         "needs_drop" => {
@@ -622,7 +620,10 @@ fn modify_as_needed<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
 
                     for i in 0..elems.len() {
                         let val = bcx.extract_value(val, i);
-                        bcx.store(val, bcx.struct_gep(llresult, i), None);
+                        let lval = LvalueRef::new_sized_ty(llresult, ret_ty,
+                                                           Alignment::AbiAligned);
+                        let (dest, align) = lval.trans_field_ptr(bcx, i);
+                        bcx.store(val, dest, align.to_align());
                     }
                     C_nil(ccx)
                 }
index c8d15d28708f4e3b9a8b926bc272afd174e9c778..f4c9a136ace3c9516e9857fb20651f1976455e3a 100644 (file)
@@ -386,7 +386,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
 
             let lvalue = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index));
             for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
-                let dst = bcx.struct_gep(lvalue.llval, i);
+                let (dst, _) = lvalue.trans_field_ptr(bcx, i);
                 let arg = &mircx.fn_ty.args[idx];
                 idx += 1;
                 if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) {
index 2861fd288326b001f639e03bbf4fd7bb7f61a140..cd58fcd4806da62d104e61679c7a9527ae71bad6 100644 (file)
@@ -124,7 +124,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             "rustc_peek" => (1, vec![param(0)], param(0)),
             "init" => (1, Vec::new(), param(0)),
             "uninit" => (1, Vec::new(), param(0)),
-            "forget" => (1, vec![ param(0) ], tcx.mk_nil()),
             "transmute" => (2, vec![ param(0) ], param(1)),
             "move_val_init" => {
                 (1,
index 1e687d63f58755d732d1e71878c4ca45262d90df..c59101cc779968eea9f7f7f3e772f3359ac6e401 100644 (file)
@@ -469,22 +469,28 @@ fn parse(string: &str) -> LangString {
         );
 
         for token in tokens {
-            match token {
+            match token.trim() {
                 "" => {},
-                "should_panic" => { data.should_panic = true; seen_rust_tags = true; },
-                "no_run" => { data.no_run = true; seen_rust_tags = true; },
-                "ignore" => { data.ignore = true; seen_rust_tags = true; },
-                "rust" => { data.rust = true; seen_rust_tags = true; },
-                "test_harness" => { data.test_harness = true; seen_rust_tags = true; },
+                "should_panic" => {
+                    data.should_panic = true;
+                    seen_rust_tags = seen_other_tags == false;
+                }
+                "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; }
+                "ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; }
+                "rust" => { data.rust = true; seen_rust_tags = true; }
+                "test_harness" => {
+                    data.test_harness = true;
+                    seen_rust_tags = !seen_other_tags || seen_rust_tags;
+                }
                 "compile_fail" if allow_compile_fail => {
                     data.compile_fail = true;
-                    seen_rust_tags = true;
+                    seen_rust_tags = !seen_other_tags || seen_rust_tags;
                     data.no_run = true;
                 }
                 x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => {
                     if let Ok(_) = x[1..].parse::<u32>() {
                         data.error_codes.push(x.to_owned());
-                        seen_rust_tags = true;
+                        seen_rust_tags = !seen_other_tags || seen_rust_tags;
                     } else {
                         seen_other_tags = true;
                     }
@@ -670,9 +676,11 @@ fn t(s: &str,
         t("test_harness",          false,        false,  false,  true,  true,  false, Vec::new());
         t("compile_fail",          false,        true,   false,  true,  false, true,  Vec::new());
         t("{.no_run .example}",    false,        true,   false,  true,  false, false, Vec::new());
-        t("{.sh .should_panic}",   true,         false,  false,  true,  false, false, Vec::new());
+        t("{.sh .should_panic}",   true,         false,  false,  false, false, false, Vec::new());
         t("{.example .rust}",      false,        false,  false,  true,  false, false, Vec::new());
         t("{.test_harness .rust}", false,        false,  false,  true,  true,  false, Vec::new());
+        t("text, no_run",          false,        true,   false,  false, false, false, Vec::new());
+        t("text,no_run",           false,        true,   false,  false, false, false, Vec::new());
     }
 
     #[test]
index 5b2053e929a10317d645126fcbd16e163dd0cc10..052340a0f253a11cf43e257c5da563b62c7585f8 100644 (file)
@@ -277,7 +277,7 @@ mod prim_pointer { }
 /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if
 /// the element type allows it:
 ///
-/// - [`Clone`][clone] (only if `T: [Copy][copy]`)
+/// - [`Clone`][clone] (only if `T: `[`Copy`][copy])
 /// - [`Debug`][debug]
 /// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`)
 /// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord]
index 521f122f8af0b57eec342d14cadd72fee2904610..48c9fda31e8c80707674537252d6a2fe4306d0a9 100644 (file)
 
 #![feature(core_intrinsics)]
 
-use std::intrinsics::{init, forget};
+use std::intrinsics::{init};
 
 // Test that the `forget` and `init` intrinsics are really unsafe
 pub fn main() {
     let stuff = init::<isize>(); //~ ERROR call to unsafe function requires unsafe
-    forget(stuff);             //~ ERROR call to unsafe function requires unsafe
 }
diff --git a/src/test/run-pass/optimization-fuel-0.rs b/src/test/run-pass/optimization-fuel-0.rs
new file mode 100644 (file)
index 0000000..3832c04
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="foo"]
+
+use std::mem::size_of;
+
+// compile-flags: -Z fuel=foo=0
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+
+fn main() {
+    assert_eq!(size_of::<S1>(), 6);
+    assert_eq!(size_of::<S2>(), 6);
+}
+
diff --git a/src/test/run-pass/optimization-fuel-1.rs b/src/test/run-pass/optimization-fuel-1.rs
new file mode 100644 (file)
index 0000000..5f294e2
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="foo"]
+
+use std::mem::size_of;
+
+// compile-flags: -Z fuel=foo=1
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+
+fn main() {
+    let optimized = (size_of::<S1>() == 4) as usize
+        +(size_of::<S2>() == 4) as usize;
+    assert_eq!(optimized, 1);
+}
+
+
index bbb01eaaf46b9b43afbdbf4bdbf4c7ebfbf4aa61..2f50e63153ea4bf8722b3bec2458aaa40d6168be 100644 (file)
@@ -31,6 +31,17 @@ enum e3 {
     a([u16; 0], u8), b
 }
 
+struct ReorderedStruct {
+    a: u8,
+    b: u16,
+    c: u8
+}
+
+enum ReorderedEnum {
+    A(u8, u16, u8),
+    B(u8, u16, u8),
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -54,4 +65,6 @@ pub fn main() {
     assert_eq!(size_of::<e1>(), 8 as usize);
     assert_eq!(size_of::<e2>(), 8 as usize);
     assert_eq!(size_of::<e3>(), 4 as usize);
+    assert_eq!(size_of::<ReorderedStruct>(), 4);
+    assert_eq!(size_of::<ReorderedEnum>(), 6);
 }
diff --git a/src/test/ui/print-fuel/print-fuel.rs b/src/test/ui/print-fuel/print-fuel.rs
new file mode 100644 (file)
index 0000000..0d9e243
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+#![crate_name="foo"]
+#![allow(dead_code)]
+
+// compile-flags: -Z print-fuel=foo
+
+struct S1(u8, u16, u8);
+struct S2(u8, u16, u8);
+struct S3(u8, u16, u8);
+
+fn main() {
+}
diff --git a/src/test/ui/print-fuel/print-fuel.stdout b/src/test/ui/print-fuel/print-fuel.stdout
new file mode 100644 (file)
index 0000000..cc88cc0
--- /dev/null
@@ -0,0 +1 @@
+Fuel used by foo: 3
index dd999c4a5e4c779d1e30f105926d4a4ef4e07eda..830678f174f88cf38e0d76836bac2cc7c9a9ee96 100644 (file)
@@ -1,25 +1,22 @@
-print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
-print-type-size     field `.pre`: 1 bytes
-print-type-size     padding: 3 bytes
-print-type-size     field `.nested`: 12 bytes, alignment: 4 bytes
+print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.nested`: 8 bytes
 print-type-size     field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
-print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
-print-type-size     variant `Some`: 20 bytes
-print-type-size         field `.0`: 20 bytes
-print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
-print-type-size     variant `Record`: 10 bytes
-print-type-size         field `.pre`: 1 bytes
-print-type-size         padding: 3 bytes
-print-type-size         field `.val`: 4 bytes, alignment: 4 bytes
-print-type-size         field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
-print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
 print-type-size     field `.pre`: 1 bytes
-print-type-size     padding: 3 bytes
-print-type-size     field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size     end padding: 1 bytes
+print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
+print-type-size     variant `Some`: 12 bytes
+print-type-size         field `.0`: 12 bytes
+print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
+print-type-size     variant `Record`: 7 bytes
+print-type-size         field `.val`: 4 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size         field `.pre`: 1 bytes
+print-type-size     end padding: 1 bytes
+print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.val`: 4 bytes
 print-type-size     field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
+print-type-size     field `.pre`: 1 bytes
+print-type-size     end padding: 1 bytes
 print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
 print-type-size     variant `Some`: 4 bytes
 print-type-size         field `.0`: 4 bytes
index 1278a7d7c92c67836d9e74db7eefd791ef4b3b23..83fd333c9c7fc45dba547de22add55c477521ef9 100644 (file)
@@ -1,13 +1,11 @@
-print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
+print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.g`: 4 bytes
+print-type-size     field `.h`: 2 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
-print-type-size     padding: 2 bytes
-print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
 print-type-size     field `.c`: 1 bytes
-print-type-size     padding: 1 bytes
-print-type-size     field `.h`: 2 bytes, alignment: 2 bytes
 print-type-size     field `.d`: 1 bytes
-print-type-size     end padding: 3 bytes
+print-type-size     end padding: 2 bytes
 print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
index bb95f790bd9e471bdd740e5f9817faf8af8d4f54..0eaff7118b35c38a528dab7052d2cd498acb15aa 100644 (file)
@@ -1,10 +1,12 @@
 print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
-print-type-size     discriminant: 4 bytes
-print-type-size     variant `A`: 5 bytes
-print-type-size         field `.0`: 4 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `A`: 7 bytes
 print-type-size         field `.1`: 1 bytes
-print-type-size     variant `B`: 8 bytes
-print-type-size         field `.0`: 8 bytes
+print-type-size         padding: 2 bytes
+print-type-size         field `.0`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `B`: 11 bytes
+print-type-size         padding: 3 bytes
+print-type-size         field `.0`: 8 bytes, alignment: 4 bytes
 print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `A`: 7 bytes
@@ -15,7 +17,7 @@ print-type-size     variant `B`: 11 bytes
 print-type-size         padding: 3 bytes
 print-type-size         field `.0`: 8 bytes, alignment: 4 bytes
 print-type-size type: `S`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.g`: 4 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
-print-type-size     padding: 2 bytes
-print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
+print-type-size     end padding: 2 bytes
index adddd7b7e89b047030eeb63a0b32cb2aa18c017d..a7a43e6858ef9dd267695177cafb36a21d8ea1f9 100644 (file)
@@ -11,7 +11,7 @@
 extern crate toml;
 extern crate rustc_serialize;
 
-use std::collections::{BTreeMap, HashMap};
+use std::collections::BTreeMap;
 use std::env;
 use std::fs::File;
 use std::io::{self, Read, Write};
 struct Manifest {
     manifest_version: String,
     date: String,
-    pkg: HashMap<String, Package>,
+    pkg: BTreeMap<String, Package>,
 }
 
 #[derive(RustcEncodable)]
 struct Package {
     version: String,
-    target: HashMap<String, Target>,
+    target: BTreeMap<String, Target>,
 }
 
 #[derive(RustcEncodable)]
@@ -138,7 +138,7 @@ struct Builder {
     input: PathBuf,
     output: PathBuf,
     gpg_passphrase: String,
-    digests: HashMap<String, String>,
+    digests: BTreeMap<String, String>,
     s3_address: String,
     date: String,
     rust_version: String,
@@ -162,7 +162,7 @@ fn main() {
         input: input,
         output: output,
         gpg_passphrase: passphrase,
-        digests: HashMap::new(),
+        digests: BTreeMap::new(),
         s3_address: s3_address,
         date: date,
         rust_version: String::new(),
@@ -214,7 +214,7 @@ fn build_manifest(&mut self) -> Manifest {
         let mut manifest = Manifest {
             manifest_version: "2".to_string(),
             date: self.date.to_string(),
-            pkg: HashMap::new(),
+            pkg: BTreeMap::new(),
         };
 
         self.package("rustc", &mut manifest.pkg, HOSTS);
@@ -230,7 +230,7 @@ fn build_manifest(&mut self) -> Manifest {
 
         let mut pkg = Package {
             version: self.cached_version("rust").to_string(),
-            target: HashMap::new(),
+            target: BTreeMap::new(),
         };
         for host in HOSTS {
             let filename = self.filename("rust", host);
@@ -299,7 +299,7 @@ fn build_manifest(&mut self) -> Manifest {
 
     fn package(&mut self,
                pkgname: &str,
-               dst: &mut HashMap<String, Package>,
+               dst: &mut BTreeMap<String, Package>,
                targets: &[&str]) {
         let targets = targets.iter().map(|name| {
             let filename = self.filename(pkgname, name);