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;
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};
pub mod wf;
pub mod util;
-mod contents;
mod context;
mod flags;
mod instance;
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,
}
}
/// 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()),
}
}
#[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
});
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]
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));
// 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...
// `&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);
}