use ty::steal::Steal;
use ty::BindingMode;
use ty::CanonicalTy;
- use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap};
+ use util::nodemap::{DefIdSet, ItemLocalMap};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec;
use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
use std::sync::mpsc;
use std::sync::Arc;
use syntax::abi;
-use syntax::ast::{self, Name, NodeId};
+use syntax::ast::{self, NodeId};
use syntax::attr;
use syntax::codemap::MultiSpan;
use syntax::feature_gate;
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::{Symbol, keywords, InternedString};
use syntax_pos::Span;
use hir;
/// Used to prevent layout from recursing too deeply.
pub layout_depth: Cell<usize>,
- /// Map from function to the `#[derive]` mode that it's defining. Only used
- /// by `proc-macro` crates.
- pub derive_macros: RefCell<NodeMap<Symbol>>,
-
stability_interner: Lock<FxHashSet<&'tcx attr::Stability>>,
pub interpret_interner: InterpretInterner<'tcx>,
layout_interner: Lock<FxHashSet<&'tcx LayoutDetails>>,
- /// A vector of every trait accessible in the whole crate
- /// (i.e. including those from subcrates). This is used only for
- /// error reporting, and so is lazily initialized and generally
- /// shouldn't taint the common path (hence the RefCell).
- pub all_traits: RefCell<Option<Vec<DefId>>>,
-
/// A general purpose channel to throw data out the back towards LLVM worker
/// threads.
///
data_layout,
layout_interner: Lock::new(FxHashSet()),
layout_depth: Cell::new(0),
- derive_macros: RefCell::new(NodeMap()),
stability_interner: Lock::new(FxHashSet()),
interpret_interner: Default::default(),
- all_traits: RefCell::new(None),
tx_to_llvm_workers: Lock::new(tx),
output_filenames: Arc::new(output_filenames.clone()),
};
pub fn mk_param(self,
index: u32,
- name: Name) -> Ty<'tcx> {
+ name: InternedString) -> Ty<'tcx> {
self.mk_ty(TyParam(ParamTy { idx: index, name: name }))
}
pub fn mk_self_type(self) -> Ty<'tcx> {
- self.mk_param(0, keywords::SelfType.name())
+ self.mk_param(0, keywords::SelfType.name().as_str())
}
pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
pub use self::Primitive::*;
use session::{self, DataTypeKind, Session};
-use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};
+use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
use syntax::ast::{self, FloatTy, IntTy, UintTy};
use syntax::attr;
/// a maximum capacity of 2<sup>31</sup> - 1 or 2147483647.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct Align {
- abi: u8,
- pref: u8,
+ abi_pow2: u8,
+ pref_pow2: u8,
}
impl Align {
};
Ok(Align {
- abi: log2(abi)?,
- pref: log2(pref)?,
+ abi_pow2: log2(abi)?,
+ pref_pow2: log2(pref)?,
})
}
pub fn abi(self) -> u64 {
- 1 << self.abi
+ 1 << self.abi_pow2
}
pub fn pref(self) -> u64 {
- 1 << self.pref
+ 1 << self.pref_pow2
}
pub fn abi_bits(self) -> u64 {
pub fn min(self, other: Align) -> Align {
Align {
- abi: cmp::min(self.abi, other.abi),
- pref: cmp::min(self.pref, other.pref),
+ abi_pow2: cmp::min(self.abi_pow2, other.abi_pow2),
+ pref_pow2: cmp::min(self.pref_pow2, other.pref_pow2),
}
}
pub fn max(self, other: Align) -> Align {
Align {
- abi: cmp::max(self.abi, other.abi),
- pref: cmp::max(self.pref, other.pref),
+ abi_pow2: cmp::max(self.abi_pow2, other.abi_pow2),
+ pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2),
}
}
}
{
let (param_env, ty) = query.into_parts();
- let rec_limit = tcx.sess.recursion_limit.get();
+ let rec_limit = *tcx.sess.recursion_limit.get();
let depth = tcx.layout_depth.get();
if depth > rec_limit {
tcx.sess.fatal(
bug!("struct cannot be packed and aligned");
}
+ let pack = {
+ let pack = repr.pack as u64;
+ Align::from_bytes(pack, pack).unwrap()
+ };
+
let mut align = if packed {
dl.i8_align
} else {
let mut offsets = vec![Size::from_bytes(0); fields.len()];
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
- // Anything with repr(C) or repr(packed) doesn't optimize.
- let mut optimize = (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty();
+ let mut optimize = !repr.inhibit_struct_field_reordering_opt();
if let StructKind::Prefixed(_, align) = kind {
optimize &= align.abi() == 1;
}
fields.len()
};
let optimizing = &mut inverse_memory_index[..end];
+ let field_align = |f: &TyLayout| {
+ if packed { f.align.min(pack).abi() } else { f.align.abi() }
+ };
match kind {
StructKind::AlwaysSized |
StructKind::MaybeUnsized => {
// Place ZSTs first to avoid "interesting offsets",
// especially with only one or two non-ZST fields.
let f = &fields[x as usize];
- (!f.is_zst(), cmp::Reverse(f.align.abi()))
- })
+ (!f.is_zst(), cmp::Reverse(field_align(f)))
+ });
}
StructKind::Prefixed(..) => {
- optimizing.sort_by_key(|&x| fields[x as usize].align.abi());
+ optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
}
}
}
let mut offset = Size::from_bytes(0);
if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
- if !packed {
+ if packed {
+ let prefix_align = prefix_align.min(pack);
+ align = align.max(prefix_align);
+ } else {
align = align.max(prefix_align);
}
offset = prefix_size.abi_align(prefix_align);
}
// Invariant: offset < dl.obj_size_bound() <= 1<<61
- if !packed {
+ if packed {
+ let field_pack = field.align.min(pack);
+ offset = offset.abi_align(field_pack);
+ align = align.max(field_pack);
+ }
+ else {
offset = offset.abi_align(field.align);
align = align.max(field.align);
}
bug!("Union cannot be packed and aligned");
}
- let mut align = if def.repr.packed() {
+ let pack = {
+ let pack = def.repr.pack as u64;
+ Align::from_bytes(pack, pack).unwrap()
+ };
+
+ let mut align = if packed {
dl.i8_align
} else {
dl.aggregate_align
for field in &variants[0] {
assert!(!field.is_unsized());
- if !packed {
+ if packed {
+ let field_pack = field.align.min(pack);
+ align = align.max(field_pack);
+ } else {
align = align.max(field.align);
}
size = cmp::max(size, field.size);
// Find one non-ZST variant.
'variants: for (v, fields) in variants.iter().enumerate() {
+ if fields.iter().any(|f| f.abi == Abi::Uninhabited) {
+ continue 'variants;
+ }
for f in fields {
- if f.abi == Abi::Uninhabited {
- continue 'variants;
- }
if !f.is_zst() {
if dataful_variant.is_none() {
dataful_variant = Some(v);
fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
// (delay format until we actually need it)
- let record = |kind, opt_discr_size, variants| {
+ let record = |kind, packed, opt_discr_size, variants| {
let type_desc = format!("{:?}", layout.ty);
self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
layout.align,
layout.size,
+ packed,
opt_discr_size,
variants);
};
ty::TyClosure(..) => {
debug!("print-type-size t: `{:?}` record closure", layout.ty);
- record(DataTypeKind::Closure, None, vec![]);
+ record(DataTypeKind::Closure, false, None, vec![]);
return;
}
};
let adt_kind = adt_def.adt_kind();
+ let adt_packed = adt_def.repr.packed();
let build_variant_info = |n: Option<ast::Name>,
flds: &[ast::Name],
let fields: Vec<_> =
variant_def.fields.iter().map(|f| f.name).collect();
record(adt_kind.into(),
+ adt_packed,
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
} else {
// (This case arises for *empty* enums; so give it
// zero variants.)
- record(adt_kind.into(), None, vec![]);
+ record(adt_kind.into(), adt_packed, None, vec![]);
}
}
layout.for_variant(self, i))
})
.collect();
- record(adt_kind.into(), match layout.variants {
+ record(adt_kind.into(), adt_packed, match layout.variants {
Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)),
_ => None
}, variant_infos);
});
impl_stable_hash_for!(struct ::ty::layout::Align {
- abi,
- pref
+ abi_pow2,
+ pref_pow2
});
impl_stable_hash_for!(struct ::ty::layout::Size {
map: LockGuard<'_, QueryMap<$tcx, Self>>,
dep_node: DepNode)
-> Result<($V, DepNodeIndex), CycleError<$tcx>> {
- debug_assert!(!tcx.dep_graph.dep_node_exists(&dep_node));
+ // If the following assertion triggers, it can have two reasons:
+ // 1. Something is wrong with DepNode creation, either here or
+ // in DepGraph::try_mark_green()
+ // 2. Two distinct query keys get mapped to the same DepNode
+ // (see for example #48923)
+ assert!(!tcx.dep_graph.dep_node_exists(&dep_node),
+ "Forcing query with already existing DepNode.\n\
+ - query-key: {:?}\n\
+ - dep-node: {:?}",
+ key, dep_node);
profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin);
let res = Self::start_job(tcx,
}
DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); }
DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); }
+ DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); }
DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); }
DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); }
DepKind::CollectAndPartitionTranslationItems => {
let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro);
let has_default_lib_allocator =
attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator");
- let has_global_allocator = tcx.sess.has_global_allocator.get();
+ let has_global_allocator = *tcx.sess.has_global_allocator.get();
let root = self.lazy(&CrateRoot {
name: tcx.crate_name(LOCAL_CRATE),
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
let mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
// Bring everything into deterministic order for hashing
- all_impls.sort_unstable_by_key(|&(trait_def_id, _)| {
+ all_impls.sort_by_cached_key(|&(trait_def_id, _)| {
tcx.def_path_hash(trait_def_id)
});
.into_iter()
.map(|(trait_def_id, mut impls)| {
// Bring everything into deterministic order for hashing
- impls.sort_unstable_by_key(|&def_index| {
+ impls.sort_by_cached_key(|&def_index| {
tcx.hir.definitions().def_path_hash(def_index)
});
use std::str;
use std::sync::Arc;
use std::time::{Instant, Duration};
-use std::{i32, usize};
+use std::i32;
+use std::cmp;
use std::sync::mpsc;
use syntax_pos::Span;
use syntax_pos::symbol::InternedString;
/// users main function.
fn maybe_create_entry_wrapper(cx: &CodegenCx) {
let (main_def_id, span) = match *cx.sess().entry_fn.borrow() {
- Some((id, span)) => {
+ Some((id, span, _)) => {
(cx.tcx.hir.local_def_id(id), span)
}
None => return,
let main_llfn = callee::get_fn(cx, instance);
- let et = cx.sess().entry_type.get().unwrap();
+ let et = cx.sess().entry_fn.get().map(|e| e.2);
match et {
- config::EntryMain => create_entry_fn(cx, span, main_llfn, main_def_id, true),
- config::EntryStart => create_entry_fn(cx, span, main_llfn, main_def_id, false),
- config::EntryNone => {} // Do nothing.
+ Some(config::EntryMain) => create_entry_fn(cx, span, main_llfn, main_def_id, true),
+ Some(config::EntryStart) => create_entry_fn(cx, span, main_llfn, main_def_id, false),
+ None => {} // Do nothing.
}
fn create_entry_fn<'cx>(cx: &'cx CodegenCx,
source: ModuleSource::Translated(ModuleLlvm {
llcx: metadata_llcx,
llmod: metadata_llmod,
- tm: create_target_machine(tcx.sess),
+ tm: create_target_machine(tcx.sess, false),
}),
kind: ModuleKind::Metadata,
};
codegen_units.len());
// Translate an allocator shim, if any
- let allocator_module = if let Some(kind) = tcx.sess.allocator_kind.get() {
+ let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() {
unsafe {
let llmod_id = "allocator";
let (llcx, llmod) =
let modules = ModuleLlvm {
llmod,
llcx,
- tm: create_target_machine(tcx.sess),
+ tm: create_target_machine(tcx.sess, false),
};
time(tcx.sess, "write allocator module", || {
allocator::trans(tcx, &modules, kind)
// a bit more efficiently.
let codegen_units = {
let mut codegen_units = codegen_units;
- codegen_units.sort_by_key(|cgu| usize::MAX - cgu.size_estimate());
+ codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
codegen_units
};
let llvm_module = ModuleLlvm {
llcx: cx.llcx,
llmod: cx.llmod,
- tm: create_target_machine(cx.sess()),
+ tm: create_target_machine(cx.sess(), false),
};
ModuleTranslation {
use syntax_pos::{self, Span, Pos};
use syntax::ast;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, InternedString};
use rustc::ty::layout::{self, LayoutOf};
pub mod gdb;
let local_id = cx.tcx.hir.as_local_node_id(def_id);
match *cx.sess().entry_fn.borrow() {
- Some((id, _)) => {
+ Some((id, _, _)) => {
if local_id == Some(id) {
flags = flags | DIFlags::FlagMainSubprogram;
}
substs.types().zip(names).map(|(ty, name)| {
let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
- let name = CString::new(name.as_str().as_bytes()).unwrap();
+ let name = CString::new(name.as_bytes()).unwrap();
unsafe {
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
return create_DIArray(DIB(cx), &template_params[..]);
}
- fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec<ast::Name> {
+ fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec<InternedString> {
let mut names = generics.parent.map_or(vec![], |def_id| {
get_type_parameter_names(cx, cx.tcx.generics_of(def_id))
});
("x86", "pclmulqdq") => "pclmul",
("x86", "rdrand") => "rdrnd",
("x86", "bmi1") => "bmi",
+ ("aarch64", "fp") => "fp-armv8",
("aarch64", "fp16") => "fullfp16",
(_, s) => s,
}
}
pub fn target_features(sess: &Session) -> Vec<Symbol> {
- let target_machine = create_target_machine(sess);
+ let target_machine = create_target_machine(sess, true);
target_feature_whitelist(sess)
.iter()
.filter(|feature| {
pub(crate) fn print(req: PrintRequest, sess: &Session) {
require_inited();
- let tm = create_target_machine(sess);
+ let tm = create_target_machine(sess, true);
unsafe {
match req {
PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(warnings)]
#![feature(box_patterns)]
#![feature(box_syntax)]
/// that actually test that compilation succeeds without
/// reporting an error.
pub fn check_for_rustc_errors_attr(tcx: TyCtxt) {
- if let Some((id, span)) = *tcx.sess.entry_fn.borrow() {
+ if let Some((id, span, _)) = *tcx.sess.entry_fn.borrow() {
let main_def_id = tcx.hir.local_def_id(id);
if tcx.has_attr(main_def_id, "rustc_error") {
}
pub fn provide(providers: &mut Providers) {
+ method::provide(providers);
*providers = Providers {
typeck_item_bodies,
typeck_tables_of,
// Check that the main return type implements the termination trait.
if let Some(term_id) = fcx.tcx.lang_items().termination() {
- if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() {
+ if let Some((id, _, entry_type)) = *fcx.tcx.sess.entry_fn.borrow() {
if id == fn_id {
- match fcx.sess().entry_type.get() {
- Some(config::EntryMain) => {
+ match entry_type {
+ config::EntryMain => {
let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty)));
let trait_ref = ty::TraitRef::new(term_id, substs);
let return_ty_span = decl.output.span();
traits::Obligation::new(
cause, param_env, trait_ref.to_predicate()));
},
- _ => {},
+ config::EntryStart => {},
}
}
}
}
fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) {
- if tcx.adt_def(def_id).repr.packed() {
- if tcx.adt_def(def_id).repr.align > 0 {
+ let repr = tcx.adt_def(def_id).repr;
+ if repr.packed() {
+ for attr in tcx.get_attrs(def_id).iter() {
+ for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
+ if let attr::ReprPacked(pack) = r {
+ if pack != repr.pack {
+ struct_span_err!(tcx.sess, sp, E0634,
+ "type has conflicting packed representation hints").emit();
+ }
+ }
+ }
+ }
+ if repr.align > 0 {
struct_span_err!(tcx.sess, sp, E0587,
"type has conflicting packed and align representation hints").emit();
}
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(warnings)]
#![allow(non_camel_case_types)]
#![feature(crate_visibility_modifier)]
#![feature(from_ref)]
#![feature(exhaustive_patterns)]
-#![feature(option_filter)]
#![feature(quote)]
#![feature(refcell_replace_swap)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
+#![feature(slice_sort_by_cached_key)]
#![feature(dyn_trait)]
#[macro_use] extern crate log;
}
fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
- match tcx.sess.entry_type.get() {
- Some(config::EntryMain) => check_main_fn_ty(tcx, id, sp),
- Some(config::EntryStart) => check_start_fn_ty(tcx, id, sp),
- Some(config::EntryNone) => {}
- None => bug!("entry function without a type")
+ if let Some((id, sp, entry_type)) = *tcx.sess.entry_fn.borrow() {
+ match entry_type {
+ config::EntryMain => check_main_fn_ty(tcx, id, sp),
+ config::EntryStart => check_start_fn_ty(tcx, id, sp),
}
}
}