]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #39999 - bitshifter:struct_align, r=eddyb
authorbors <bors@rust-lang.org>
Sat, 22 Apr 2017 11:50:40 +0000 (11:50 +0000)
committerbors <bors@rust-lang.org>
Sat, 22 Apr 2017 11:50:40 +0000 (11:50 +0000)
Implementation of repr struct alignment RFC 1358.

The main changes around rustc::ty::Layout::struct:
* Added abi_align field which stores abi alignment before repr align is applied
* align field contains transitive repr alignment
* Added padding vec which stores padding required after fields

The main user of this information is rustc_trans::adt::struct_llfields
which determines the LLVM fields to be used by LLVM, including padding
fields.

A possible future optimisation would be to put the padding Vec in an Option, since it will be unused unless you are using repr align.

1  2 
src/librustc/ty/mod.rs
src/librustc_trans/abi.rs

diff --combined src/librustc/ty/mod.rs
index 5c0889976c21a7bd8f462030899ac58b51429368,db8b093e369e02075a2b7f19ba81be3c4cd55d46..5be73542b931dd5a73c17c4c761ba2a8e4b7fe9e
@@@ -37,6 -37,7 +37,7 @@@ use serialize::{self, Encodable, Encode
  use std::borrow::Cow;
  use std::cell::{Cell, RefCell, Ref};
  use std::collections::BTreeMap;
+ use std::cmp;
  use std::hash::{Hash, Hasher};
  use std::ops::Deref;
  use std::rc::Rc;
@@@ -71,6 -72,7 +72,6 @@@ pub use self::sty::InferTy::*
  pub use self::sty::Region::*;
  pub use self::sty::TypeVariants::*;
  
 -pub use self::contents::TypeContents;
  pub use self::context::{TyCtxt, GlobalArenas, tls};
  pub use self::context::{Lift, TypeckTables};
  
@@@ -98,6 -100,7 +99,6 @@@ pub mod walk
  pub mod wf;
  pub mod util;
  
 -mod contents;
  mod context;
  mod flags;
  mod instance;
@@@ -423,10 -426,6 +424,10 @@@ bitflags! 
          const IS_SIZED          = 1 << 17,
          const MOVENESS_CACHED   = 1 << 18,
          const MOVES_BY_DEFAULT  = 1 << 19,
 +        const FREEZENESS_CACHED = 1 << 20,
 +        const IS_FREEZE         = 1 << 21,
 +        const NEEDS_DROP_CACHED = 1 << 22,
 +        const NEEDS_DROP        = 1 << 23,
      }
  }
  
@@@ -1183,9 -1182,6 +1184,9 @@@ pub struct ParameterEnvironment<'tcx> 
  
      /// A cache for `type_is_sized`
      pub is_sized_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
 +
 +    /// A cache for `type_is_freeze`
 +    pub is_freeze_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
  }
  
  impl<'a, 'tcx> ParameterEnvironment<'tcx> {
              free_id_outlive: self.free_id_outlive,
              is_copy_cache: RefCell::new(FxHashMap()),
              is_sized_cache: RefCell::new(FxHashMap()),
 +            is_freeze_cache: RefCell::new(FxHashMap()),
          }
      }
  
@@@ -1470,10 -1465,12 +1471,12 @@@ impl_stable_hash_for!(struct ReprFlags 
  #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
  pub struct ReprOptions {
      pub int: Option<attr::IntType>,
+     pub align: u16,
      pub flags: ReprFlags,
  }
  
  impl_stable_hash_for!(struct ReprOptions {
+     align,
      int,
      flags
  });
@@@ -1482,7 -1479,7 +1485,7 @@@ impl ReprOptions 
      pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
          let mut flags = ReprFlags::empty();
          let mut size = None;
+         let mut max_align = 0;
          for attr in tcx.get_attrs(did).iter() {
              for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
                  flags.insert(match r {
                          size = Some(i);
                          ReprFlags::empty()
                      },
+                     attr::ReprAlign(align) => {
+                         max_align = cmp::max(align, max_align);
+                         ReprFlags::empty()
+                     },
                  });
              }
          }
          if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) {
              flags.insert(ReprFlags::IS_LINEAR);
          }
-         ReprOptions { int: size, flags: flags }
+         ReprOptions { int: size, align: max_align, flags: flags }
      }
  
      #[inline]
@@@ -2381,6 -2382,40 +2388,6 @@@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '
          Some(self.item_mir(did))
      }
  
 -    /// If `type_needs_drop` returns true, then `ty` is definitely
 -    /// non-copy and *might* have a destructor attached; if it returns
 -    /// false, then `ty` definitely has no destructor (i.e. no drop glue).
 -    ///
 -    /// (Note that this implies that if `ty` has a destructor attached,
 -    /// then `type_needs_drop` will definitely return `true` for `ty`.)
 -    pub fn type_needs_drop_given_env(self,
 -                                     ty: Ty<'gcx>,
 -                                     param_env: &ty::ParameterEnvironment<'gcx>) -> bool {
 -        // Issue #22536: We first query type_moves_by_default.  It sees a
 -        // normalized version of the type, and therefore will definitely
 -        // know whether the type implements Copy (and thus needs no
 -        // cleanup/drop/zeroing) ...
 -        let tcx = self.global_tcx();
 -        let implements_copy = !ty.moves_by_default(tcx, param_env, DUMMY_SP);
 -
 -        if implements_copy { return false; }
 -
 -        // ... (issue #22536 continued) but as an optimization, still use
 -        // prior logic of asking if the `needs_drop` bit is set; we need
 -        // not zero non-Copy types if they have no destructor.
 -
 -        // FIXME(#22815): Note that calling `ty::type_contents` is a
 -        // conservative heuristic; it may report that `needs_drop` is set
 -        // when actual type does not actually have a destructor associated
 -        // with it. But since `ty` absolutely did not have the `Copy`
 -        // bound attached (see above), it is sound to treat it as having a
 -        // destructor (e.g. zero its memory on move).
 -
 -        let contents = ty.type_contents(tcx);
 -        debug!("type_needs_drop ty={:?} contents={:?}", ty, contents);
 -        contents.needs_drop(tcx)
 -    }
 -
      /// Get the attributes of a definition.
      pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> {
          if let Some(id) = self.hir.as_local_node_id(did) {
              free_id_outlive: free_id_outlive,
              is_copy_cache: RefCell::new(FxHashMap()),
              is_sized_cache: RefCell::new(FxHashMap()),
 +            is_freeze_cache: RefCell::new(FxHashMap()),
          }
      }
  
              free_id_outlive: free_id_outlive,
              is_copy_cache: RefCell::new(FxHashMap()),
              is_sized_cache: RefCell::new(FxHashMap()),
 +            is_freeze_cache: RefCell::new(FxHashMap()),
          };
  
          let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
index e0a75f3caa7b36976e003b274603bc5749bdf513,efe4acfa9e072296727d65acfae0d14b3c8f58a2..998e392b1f9078ac78dc68e4746666e8d0309e2e
@@@ -553,7 -553,7 +553,7 @@@ impl<'a, 'tcx> ArgType<'tcx> 
                  //   bitcasting to the struct type yields invalid cast errors.
  
                  // We instead thus allocate some scratch space...
-                 let llscratch = bcx.alloca(ty, "abi_cast");
+                 let llscratch = bcx.alloca(ty, "abi_cast", None);
                  base::Lifetime::Start.call(bcx, llscratch);
  
                  // ...where we first store the value...
@@@ -746,13 -746,13 +746,13 @@@ impl<'a, 'tcx> FnType<'tcx> 
                  // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
                  // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
                  // on memory dependencies rather than pointer equality
 -                let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
 +                let is_freeze = ccx.shared().type_is_freeze(mt.ty);
  
 -                if mt.mutbl != hir::MutMutable && !interior_unsafe {
 +                if mt.mutbl != hir::MutMutable && is_freeze {
                      arg.attrs.set(ArgAttribute::NoAlias);
                  }
  
 -                if mt.mutbl == hir::MutImmutable && !interior_unsafe {
 +                if mt.mutbl == hir::MutImmutable && is_freeze {
                      arg.attrs.set(ArgAttribute::ReadOnly);
                  }