Importing rustc-1.36.0
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 3486167..38d4b7e 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -2,8 +2,8 @@
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::type_::Type;
-use crate::type_of::{LayoutLlvmExt, PointerKind};
use crate::value::Value;
+use crate::type_of::{LayoutLlvmExt};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::mir::operand::OperandValue;
@@ -11,9 +11,9 @@
use rustc_codegen_ssa::traits::*;
-use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
-use rustc::ty::{self, Ty, Instance};
-use rustc::ty::layout;
+use rustc_target::abi::{HasDataLayout, LayoutOf};
+use rustc::ty::{Ty};
+use rustc::ty::layout::{self};
use libc::c_uint;
@@ -294,23 +294,7 @@
}
}
-pub trait FnTypeExt<'tcx> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self;
- fn new(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self;
- fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self;
- fn new_internal(
- cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>],
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
- ) -> Self;
- fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'ll, 'tcx>,
- abi: Abi);
+pub trait FnTypeLlvmExt<'tcx> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
@@ -318,356 +302,7 @@
fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
}
-impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
- let sig = instance.fn_sig(cx.tcx);
- let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- FnType::new(cx, sig, &[])
- }
-
- fn new(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
- FnType::new_internal(cx, sig, extra_args, |ty, _| {
- ArgType::new(cx.layout_of(ty))
- })
- }
-
- fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
- FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
- let mut layout = cx.layout_of(ty);
- // Don't pass the vtable, it's not an argument of the virtual fn.
- // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
- // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
- if arg_idx == Some(0) {
- let fat_pointer_ty = if layout.is_unsized() {
- // unsized `self` is passed as a pointer to `self`
- // FIXME (mikeyhew) change this to use &own if it is ever added to the language
- cx.tcx.mk_mut_ptr(layout.ty)
- } else {
- match layout.abi {
- LayoutAbi::ScalarPair(..) => (),
- _ => bug!("receiver type has unsupported layout: {:?}", layout)
- }
-
- // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
- // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
- // elsewhere in the compiler as a method on a `dyn Trait`.
- // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
- // get a built-in pointer type
- let mut fat_pointer_layout = layout;
- 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
- && !fat_pointer_layout.ty.is_region_ptr()
- {
- 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
- let field_layout = fat_pointer_layout.field(cx, i);
-
- if !field_layout.is_zst() {
- fat_pointer_layout = field_layout;
- continue 'descend_newtypes
- }
- }
-
- bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
- }
-
- fat_pointer_layout.ty
- };
-
- // we now have a type like `*mut RcBox<dyn Trait>`
- // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
- // this is understood as a special case elsewhere in the compiler
- let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit());
- layout = cx.layout_of(unit_pointer_ty);
- layout.ty = fat_pointer_ty;
- }
- ArgType::new(layout)
- })
- }
-
- fn new_internal(
- cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>],
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
- ) -> Self {
- debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
-
- use self::Abi::*;
- let conv = match cx.sess().target.target.adjust_abi(sig.abi) {
- RustIntrinsic | PlatformIntrinsic |
- Rust | RustCall => Conv::C,
-
- // It's the ABI's job to select this, not ours.
- System => bug!("system abi should be selected elsewhere"),
-
- Stdcall => Conv::X86Stdcall,
- Fastcall => Conv::X86Fastcall,
- Vectorcall => Conv::X86VectorCall,
- Thiscall => Conv::X86ThisCall,
- C => Conv::C,
- Unadjusted => Conv::C,
- Win64 => Conv::X86_64Win64,
- SysV64 => Conv::X86_64SysV,
- Aapcs => Conv::ArmAapcs,
- PtxKernel => Conv::PtxKernel,
- Msp430Interrupt => Conv::Msp430Intr,
- X86Interrupt => Conv::X86Intr,
- AmdGpuKernel => Conv::AmdGpuKernel,
-
- // These API constants ought to be more specific...
- Cdecl => Conv::C,
- };
-
- let mut inputs = sig.inputs();
- let extra_args = if sig.abi == RustCall {
- assert!(!sig.c_variadic && extra_args.is_empty());
-
- match sig.inputs().last().unwrap().sty {
- ty::Tuple(ref tupled_arguments) => {
- inputs = &sig.inputs()[0..sig.inputs().len() - 1];
- tupled_arguments
- }
- _ => {
- bug!("argument to function with \"rust-call\" ABI \
- is not a tuple");
- }
- }
- } else {
- assert!(sig.c_variadic || extra_args.is_empty());
- extra_args
- };
-
- let target = &cx.sess().target.target;
- let win_x64_gnu = target.target_os == "windows"
- && target.arch == "x86_64"
- && target.target_env == "gnu";
- let linux_s390x = target.target_os == "linux"
- && target.arch == "s390x"
- && target.target_env == "gnu";
- let linux_sparc64 = target.target_os == "linux"
- && target.arch == "sparc64"
- && target.target_env == "gnu";
- let rust_abi = match sig.abi {
- RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
- _ => false
- };
-
- // Handle safe Rust thin and fat pointers.
- let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
- scalar: &layout::Scalar,
- layout: TyLayout<'tcx, Ty<'tcx>>,
- offset: Size,
- is_return: bool| {
- // Booleans are always an i1 that needs to be zero-extended.
- if scalar.is_bool() {
- attrs.set(ArgAttribute::ZExt);
- return;
- }
-
- // Only pointer types handled below.
- if scalar.value != layout::Pointer {
- return;
- }
-
- if scalar.valid_range.start() < scalar.valid_range.end() {
- if *scalar.valid_range.start() > 0 {
- attrs.set(ArgAttribute::NonNull);
- }
- }
-
- if let Some(pointee) = layout.pointee_info_at(cx, offset) {
- if let Some(kind) = pointee.safe {
- attrs.pointee_size = pointee.size;
- attrs.pointee_align = Some(pointee.align);
-
- // `Box` pointer parameters never alias because ownership is transferred
- // `&mut` pointer parameters never alias other parameters,
- // or mutable global data
- //
- // `&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 no_alias = match kind {
- PointerKind::Shared => false,
- PointerKind::UniqueOwned => true,
- PointerKind::Frozen |
- PointerKind::UniqueBorrowed => !is_return
- };
- if no_alias {
- attrs.set(ArgAttribute::NoAlias);
- }
-
- if kind == PointerKind::Frozen && !is_return {
- attrs.set(ArgAttribute::ReadOnly);
- }
- }
- }
- };
-
- // Store the index of the last argument. This is useful for working with
- // C-compatible variadic arguments.
- let last_arg_idx = if sig.inputs().is_empty() {
- None
- } else {
- Some(sig.inputs().len() - 1)
- };
-
- let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
- let is_return = arg_idx.is_none();
- let mut arg = mk_arg_type(ty, arg_idx);
- if arg.layout.is_zst() {
- // For some forsaken reason, x86_64-pc-windows-gnu
- // doesn't ignore zero-sized struct arguments.
- // The same is true for s390x-unknown-linux-gnu
- // and sparc64-unknown-linux-gnu.
- if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
- arg.mode = PassMode::Ignore(IgnoreMode::Zst);
- }
- }
-
- // If this is a C-variadic function, this is not the return value,
- // and there is one or more fixed arguments; ensure that the `VaList`
- // is ignored as an argument.
- if sig.c_variadic {
- match (last_arg_idx, arg_idx) {
- (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
- let va_list_did = match cx.tcx.lang_items().va_list() {
- Some(did) => did,
- None => bug!("`va_list` lang item required for C-variadic functions"),
- };
- match ty.sty {
- ty::Adt(def, _) if def.did == va_list_did => {
- // This is the "spoofed" `VaList`. Set the arguments mode
- // so that it will be ignored.
- arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
- },
- _ => (),
- }
- }
- _ => {}
- }
- }
-
- // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
- if !is_return && rust_abi {
- if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
- let mut a_attrs = ArgAttributes::new();
- let mut b_attrs = ArgAttributes::new();
- adjust_for_rust_scalar(&mut a_attrs,
- a,
- arg.layout,
- Size::ZERO,
- false);
- adjust_for_rust_scalar(&mut b_attrs,
- b,
- arg.layout,
- a.value.size(cx).align_to(b.value.align(cx).abi),
- false);
- arg.mode = PassMode::Pair(a_attrs, b_attrs);
- return arg;
- }
- }
-
- if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
- if let PassMode::Direct(ref mut attrs) = arg.mode {
- adjust_for_rust_scalar(attrs,
- scalar,
- arg.layout,
- Size::ZERO,
- is_return);
- }
- }
-
- arg
- };
-
- let mut fn_ty = FnType {
- ret: arg_of(sig.output(), None),
- args: inputs.iter().chain(extra_args).enumerate().map(|(i, ty)| {
- arg_of(ty, Some(i))
- }).collect(),
- c_variadic: sig.c_variadic,
- conv,
- };
- fn_ty.adjust_for_abi(cx, sig.abi);
- fn_ty
- }
-
- fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'ll, 'tcx>,
- abi: Abi) {
- if abi == Abi::Unadjusted { return }
-
- if abi == Abi::Rust || abi == Abi::RustCall ||
- abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
- let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
- if arg.is_ignore() { return; }
-
- match arg.layout.abi {
- layout::Abi::Aggregate { .. } => {}
-
- // This is a fun case! The gist of what this is doing is
- // that we want callers and callees to always agree on the
- // ABI of how they pass SIMD arguments. If we were to *not*
- // make these arguments indirect then they'd be immediates
- // in LLVM, which means that they'd used whatever the
- // appropriate ABI is for the callee and the caller. That
- // means, for example, if the caller doesn't have AVX
- // enabled but the callee does, then passing an AVX argument
- // across this boundary would cause corrupt data to show up.
- //
- // This problem is fixed by unconditionally passing SIMD
- // arguments through memory between callers and callees
- // which should get them all to agree on ABI regardless of
- // target feature sets. Some more information about this
- // issue can be found in #44367.
- //
- // Note that the platform intrinsic ABI is exempt here as
- // that's how we connect up to LLVM and it's unstable
- // anyway, we control all calls to it in libstd.
- layout::Abi::Vector { .. }
- if abi != Abi::PlatformIntrinsic &&
- cx.sess().target.target.options.simd_types_indirect =>
- {
- arg.make_indirect();
- return
- }
-
- _ => return
- }
-
- let size = arg.layout.size;
- if arg.layout.is_unsized() || size > layout::Pointer.size(cx) {
- arg.make_indirect();
- } else {
- // We want to pass small aggregates as immediates, but using
- // a LLVM aggregate type for this leads to bad optimizations,
- // so we pick an appropriately sized integer type instead.
- arg.cast_to(Reg {
- kind: RegKind::Integer,
- size
- });
- }
- };
- fixup(&mut self.ret);
- for arg in &mut self.args {
- fixup(arg);
- }
- if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
- attrs.set(ArgAttribute::StructRet);
- }
- return;
- }
-
- if let Err(msg) = self.adjust_for_cabi(cx, abi) {
- cx.sess().fatal(&msg);
- }
- }
-
+impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
let args_capacity: usize = self.args.iter().map(|arg|
if arg.pad.is_some() { 1 } else { 0 } +
@@ -836,22 +471,6 @@
}
}
-impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> {
- fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> {
- FnType::new(&self, sig, extra_args)
- }
- fn new_vtable(
- &self,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]
- ) -> FnType<'tcx, Ty<'tcx>> {
- FnType::new_vtable(&self, sig, extra_args)
- }
- fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> {
- FnType::of_instance(&self, instance)
- }
-}
-
impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn apply_attrs_callsite(
&mut self,
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 77fa34e..f26684d 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -104,7 +104,7 @@
}
// probestack doesn't play nice either with pgo-gen.
- if cx.sess().opts.debugging_opts.pgo_gen.is_some() {
+ if cx.sess().opts.debugging_opts.pgo_gen.enabled() {
return;
}
@@ -321,12 +321,12 @@
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
Lrc::new(llvm_util::all_known_features()
- .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string())))
+ .map(|(a, b)| (a.to_string(), b))
.collect())
} else {
Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
.iter()
- .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string())))
+ .map(|&(a, b)| (a.to_string(), b))
.collect())
}
};
diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs
index 3fb9d4b..e0e26e9 100644
--- a/src/librustc_codegen_llvm/back/archive.rs
+++ b/src/librustc_codegen_llvm/back/archive.rs
@@ -7,14 +7,13 @@
use std::ptr;
use std::str;
-use crate::back::bytecode::RLIB_BYTECODE_EXTENSION;
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind};
-use crate::metadata::METADATA_FILENAME;
-use rustc_codegen_ssa::back::archive::find_library;
+use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
+use rustc_codegen_ssa::back::archive::{ArchiveBuilder, find_library};
use rustc::session::Session;
-pub struct ArchiveConfig<'a> {
+struct ArchiveConfig<'a> {
pub sess: &'a Session,
pub dst: PathBuf,
pub src: Option<PathBuf>,
@@ -23,7 +22,7 @@
/// Helper for adding many files to an archive.
#[must_use = "must call build() to finish building the archive"]
-pub struct ArchiveBuilder<'a> {
+pub struct LlvmArchiveBuilder<'a> {
config: ArchiveConfig<'a>,
removals: Vec<String>,
additions: Vec<Addition>,
@@ -49,11 +48,26 @@
}
}
-impl<'a> ArchiveBuilder<'a> {
+fn archive_config<'a>(sess: &'a Session,
+ output: &Path,
+ input: Option<&Path>) -> ArchiveConfig<'a> {
+ use rustc_codegen_ssa::back::link::archive_search_paths;
+ ArchiveConfig {
+ sess,
+ dst: output.to_path_buf(),
+ src: input.map(|p| p.to_path_buf()),
+ lib_search_paths: archive_search_paths(sess),
+ }
+}
+
+impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
/// Creates a new static archive, ready for modifying the archive specified
/// by `config`.
- pub fn new(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> {
- ArchiveBuilder {
+ fn new(sess: &'a Session,
+ output: &Path,
+ input: Option<&Path>) -> LlvmArchiveBuilder<'a> {
+ let config = archive_config(sess, output, input);
+ LlvmArchiveBuilder {
config,
removals: Vec::new(),
additions: Vec::new(),
@@ -63,12 +77,12 @@
}
/// Removes a file from this archive
- pub fn remove_file(&mut self, file: &str) {
+ fn remove_file(&mut self, file: &str) {
self.removals.push(file.to_string());
}
/// Lists all files in an archive
- pub fn src_files(&mut self) -> Vec<String> {
+ fn src_files(&mut self) -> Vec<String> {
if self.src_archive().is_none() {
return Vec::new()
}
@@ -84,18 +98,9 @@
.collect()
}
- fn src_archive(&mut self) -> Option<&ArchiveRO> {
- if let Some(ref a) = self.src_archive {
- return a.as_ref()
- }
- let src = self.config.src.as_ref()?;
- self.src_archive = Some(ArchiveRO::open(src).ok());
- self.src_archive.as_ref().unwrap().as_ref()
- }
-
/// Adds all of the contents of a native library to this archive. This will
/// search in the relevant locations for a library named `name`.
- pub fn add_native_library(&mut self, name: &str) {
+ fn add_native_library(&mut self, name: &str) {
let location = find_library(name, &self.config.lib_search_paths,
self.config.sess);
self.add_archive(&location, |_| false).unwrap_or_else(|e| {
@@ -109,7 +114,7 @@
///
/// This ignores adding the bytecode from the rlib, and if LTO is enabled
/// then the object file also isn't added.
- pub fn add_rlib(&mut self,
+ fn add_rlib(&mut self,
rlib: &Path,
name: &str,
lto: bool,
@@ -141,6 +146,44 @@
})
}
+ /// Adds an arbitrary file to this archive
+ fn add_file(&mut self, file: &Path) {
+ let name = file.file_name().unwrap().to_str().unwrap();
+ self.additions.push(Addition::File {
+ path: file.to_path_buf(),
+ name_in_archive: name.to_owned(),
+ });
+ }
+
+ /// Indicate that the next call to `build` should update all symbols in
+ /// the archive (equivalent to running 'ar s' over it).
+ fn update_symbols(&mut self) {
+ self.should_update_symbols = true;
+ }
+
+ /// Combine the provided files, rlibs, and native libraries into a single
+ /// `Archive`.
+ fn build(mut self) {
+ let kind = self.llvm_archive_kind().unwrap_or_else(|kind|
+ self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", kind)));
+
+ if let Err(e) = self.build_with_llvm(kind) {
+ self.config.sess.fatal(&format!("failed to build archive: {}", e));
+ }
+
+ }
+}
+
+impl<'a> LlvmArchiveBuilder<'a> {
+ fn src_archive(&mut self) -> Option<&ArchiveRO> {
+ if let Some(ref a) = self.src_archive {
+ return a.as_ref()
+ }
+ let src = self.config.src.as_ref()?;
+ self.src_archive = Some(ArchiveRO::open(src).ok());
+ self.src_archive.as_ref().unwrap().as_ref()
+ }
+
fn add_archive<F>(&mut self, archive: &Path, skip: F)
-> io::Result<()>
where F: FnMut(&str) -> bool + 'static
@@ -156,33 +199,6 @@
Ok(())
}
- /// Adds an arbitrary file to this archive
- pub fn add_file(&mut self, file: &Path) {
- let name = file.file_name().unwrap().to_str().unwrap();
- self.additions.push(Addition::File {
- path: file.to_path_buf(),
- name_in_archive: name.to_owned(),
- });
- }
-
- /// Indicate that the next call to `build` should update all symbols in
- /// the archive (equivalent to running 'ar s' over it).
- pub fn update_symbols(&mut self) {
- self.should_update_symbols = true;
- }
-
- /// Combine the provided files, rlibs, and native libraries into a single
- /// `Archive`.
- pub fn build(&mut self) {
- let kind = self.llvm_archive_kind().unwrap_or_else(|kind|
- self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", kind)));
-
- if let Err(e) = self.build_with_llvm(kind) {
- self.config.sess.fatal(&format!("failed to build archive: {}", e));
- }
-
- }
-
fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
let kind = &*self.config.sess.target.target.options.archive_format;
kind.parse().map_err(|_| kind)
diff --git a/src/librustc_codegen_llvm/back/bytecode.rs b/src/librustc_codegen_llvm/back/bytecode.rs
index 8b288c4..397cdec 100644
--- a/src/librustc_codegen_llvm/back/bytecode.rs
+++ b/src/librustc_codegen_llvm/back/bytecode.rs
@@ -37,8 +37,6 @@
// The version number this compiler will write to bytecode objects in rlibs
pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2;
-pub const RLIB_BYTECODE_EXTENSION: &str = "bc.z";
-
pub fn encode(identifier: &str, bytecode: &[u8]) -> Vec<u8> {
let mut encoded = Vec::new();
diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs
deleted file mode 100644
index 19419a7..0000000
--- a/src/librustc_codegen_llvm/back/link.rs
+++ /dev/null
@@ -1,1494 +0,0 @@
-use super::archive::{ArchiveBuilder, ArchiveConfig};
-use super::bytecode::RLIB_BYTECODE_EXTENSION;
-use super::rpath::RPathConfig;
-use super::rpath;
-use crate::back::wasm;
-use crate::metadata::METADATA_FILENAME;
-use crate::context::get_reloc_model;
-use crate::llvm;
-use rustc_codegen_ssa::back::linker::Linker;
-use rustc_codegen_ssa::back::link::{remove, ignored_for_lto, each_linked_rlib, linker_and_flavor,
- get_linker};
-use rustc_codegen_ssa::back::command::Command;
-use rustc::session::config::{self, DebugInfo, OutputFilenames, OutputType, PrintRequest};
-use rustc::session::config::{RUST_CGU_EXT, Lto, Sanitizer};
-use rustc::session::filesearch;
-use rustc::session::search_paths::PathKind;
-use rustc::session::Session;
-use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind};
-use rustc::middle::dependency_format::Linkage;
-use rustc_codegen_ssa::CodegenResults;
-use rustc::util::common::{time, time_ext};
-use rustc_fs_util::fix_windows_verbatim_for_gcc;
-use rustc::hir::def_id::CrateNum;
-use tempfile::{Builder as TempFileBuilder, TempDir};
-use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor};
-use rustc_data_structures::fx::FxHashSet;
-
-use std::ascii;
-use std::char;
-use std::env;
-use std::fmt;
-use std::fs;
-use std::io;
-use std::iter;
-use std::path::{Path, PathBuf};
-use std::process::{Output, Stdio};
-use std::str;
-use syntax::attr;
-
-pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
- invalid_output_for_target, filename_for_metadata,
- out_filename, check_file_is_writeable};
-
-
-/// Performs the linkage portion of the compilation phase. This will generate all
-/// of the requested outputs for this compilation session.
-pub(crate) fn link_binary(sess: &Session,
- codegen_results: &CodegenResults,
- outputs: &OutputFilenames,
- crate_name: &str) -> Vec<PathBuf> {
- let mut out_filenames = Vec::new();
- for &crate_type in sess.crate_types.borrow().iter() {
- // Ignore executable crates if we have -Z no-codegen, as they will error.
- let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
- if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) &&
- !output_metadata &&
- crate_type == config::CrateType::Executable {
- continue;
- }
-
- if invalid_output_for_target(sess, crate_type) {
- bug!("invalid output type `{:?}` for target os `{}`",
- crate_type, sess.opts.target_triple);
- }
- let out_files = link_binary_output(sess,
- codegen_results,
- crate_type,
- outputs,
- crate_name);
- out_filenames.extend(out_files);
- }
-
- // Remove the temporary object file and metadata if we aren't saving temps
- if !sess.opts.cg.save_temps {
- if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) {
- for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
- remove(sess, obj);
- }
- }
- for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
- remove(sess, obj);
- }
- if let Some(ref obj) = codegen_results.metadata_module.object {
- remove(sess, obj);
- }
- if let Some(ref allocator) = codegen_results.allocator_module {
- if let Some(ref obj) = allocator.object {
- remove(sess, obj);
- }
- if let Some(ref bc) = allocator.bytecode_compressed {
- remove(sess, bc);
- }
- }
- }
-
- out_filenames
-}
-
-/// Returns a boolean indicating whether we should preserve the object files on
-/// the filesystem for their debug information. This is often useful with
-/// split-dwarf like schemes.
-fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
- // If the objects don't have debuginfo there's nothing to preserve.
- if sess.opts.debuginfo == DebugInfo::None {
- return false
- }
-
- // If we're only producing artifacts that are archives, no need to preserve
- // the objects as they're losslessly contained inside the archives.
- let output_linked = sess.crate_types.borrow()
- .iter()
- .any(|&x| x != config::CrateType::Rlib && x != config::CrateType::Staticlib);
- if !output_linked {
- return false
- }
-
- // If we're on OSX then the equivalent of split dwarf is turned on by
- // default. The final executable won't actually have any debug information
- // except it'll have pointers to elsewhere. Historically we've always run
- // `dsymutil` to "link all the dwarf together" but this is actually sort of
- // a bummer for incremental compilation! (the whole point of split dwarf is
- // that you don't do this sort of dwarf link).
- //
- // Basically as a result this just means that if we're on OSX and we're
- // *not* running dsymutil then the object files are the only source of truth
- // for debug information, so we must preserve them.
- if sess.target.target.options.is_like_osx {
- match sess.opts.debugging_opts.run_dsymutil {
- // dsymutil is not being run, preserve objects
- Some(false) => return true,
-
- // dsymutil is being run, no need to preserve the objects
- Some(true) => return false,
-
- // The default historical behavior was to always run dsymutil, so
- // we're preserving that temporarily, but we're likely to switch the
- // default soon.
- None => return false,
- }
- }
-
- false
-}
-
-fn link_binary_output(sess: &Session,
- codegen_results: &CodegenResults,
- crate_type: config::CrateType,
- outputs: &OutputFilenames,
- crate_name: &str) -> Vec<PathBuf> {
- for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
- check_file_is_writeable(obj, sess);
- }
-
- let mut out_filenames = vec![];
-
- if outputs.outputs.contains_key(&OutputType::Metadata) {
- let out_filename = filename_for_metadata(sess, crate_name, outputs);
- // To avoid races with another rustc process scanning the output directory,
- // we need to write the file somewhere else and atomically move it to its
- // final destination, with a `fs::rename` call. In order for the rename to
- // always succeed, the temporary file needs to be on the same filesystem,
- // which is why we create it inside the output directory specifically.
- let metadata_tmpdir = TempFileBuilder::new()
- .prefix("rmeta")
- .tempdir_in(out_filename.parent().unwrap())
- .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
- let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir);
- if let Err(e) = fs::rename(metadata, &out_filename) {
- sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
- }
- out_filenames.push(out_filename);
- }
-
- let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
- sess.fatal(&format!("couldn't create a temp dir: {}", err)));
-
- if outputs.outputs.should_codegen() {
- let out_filename = out_filename(sess, crate_type, outputs, crate_name);
- match crate_type {
- config::CrateType::Rlib => {
- link_rlib(sess,
- codegen_results,
- RlibFlavor::Normal,
- &out_filename,
- &tmpdir).build();
- }
- config::CrateType::Staticlib => {
- link_staticlib(sess, codegen_results, &out_filename, &tmpdir);
- }
- _ => {
- link_natively(sess, crate_type, &out_filename, codegen_results, tmpdir.path());
- }
- }
- out_filenames.push(out_filename);
- }
-
- if sess.opts.cg.save_temps {
- let _ = tmpdir.into_path();
- }
-
- out_filenames
-}
-
-fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
- sess.target_filesearch(PathKind::Native).search_path_dirs()
-}
-
-fn archive_config<'a>(sess: &'a Session,
- output: &Path,
- input: Option<&Path>) -> ArchiveConfig<'a> {
- ArchiveConfig {
- sess,
- dst: output.to_path_buf(),
- src: input.map(|p| p.to_path_buf()),
- lib_search_paths: archive_search_paths(sess),
- }
-}
-
-/// We use a temp directory here to avoid races between concurrent rustc processes,
-/// such as builds in the same directory using the same filename for metadata while
-/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
-/// directory being searched for `extern crate` (observing an incomplete file).
-/// The returned path is the temporary file containing the complete metadata.
-fn emit_metadata<'a>(
- sess: &'a Session,
- codegen_results: &CodegenResults,
- tmpdir: &TempDir
-) -> PathBuf {
- let out_filename = tmpdir.path().join(METADATA_FILENAME);
- let result = fs::write(&out_filename, &codegen_results.metadata.raw_data);
-
- if let Err(e) = result {
- sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
- }
-
- out_filename
-}
-
-enum RlibFlavor {
- Normal,
- StaticlibBase,
-}
-
-// Create an 'rlib'
-//
-// An rlib in its current incarnation is essentially a renamed .a file. The
-// rlib primarily contains the object file of the crate, but it also contains
-// all of the object files from native libraries. This is done by unzipping
-// native libraries and inserting all of the contents into this archive.
-fn link_rlib<'a>(sess: &'a Session,
- codegen_results: &CodegenResults,
- flavor: RlibFlavor,
- out_filename: &Path,
- tmpdir: &TempDir) -> ArchiveBuilder<'a> {
- info!("preparing rlib to {:?}", out_filename);
- let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None));
-
- for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
- ab.add_file(obj);
- }
-
- // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
- // we may not be configured to actually include a static library if we're
- // adding it here. That's because later when we consume this rlib we'll
- // decide whether we actually needed the static library or not.
- //
- // To do this "correctly" we'd need to keep track of which libraries added
- // which object files to the archive. We don't do that here, however. The
- // #[link(cfg(..))] feature is unstable, though, and only intended to get
- // liblibc working. In that sense the check below just indicates that if
- // there are any libraries we want to omit object files for at link time we
- // just exclude all custom object files.
- //
- // Eventually if we want to stabilize or flesh out the #[link(cfg(..))]
- // feature then we'll need to figure out how to record what objects were
- // loaded from the libraries found here and then encode that into the
- // metadata of the rlib we're generating somehow.
- for lib in codegen_results.crate_info.used_libraries.iter() {
- match lib.kind {
- NativeLibraryKind::NativeStatic => {}
- NativeLibraryKind::NativeStaticNobundle |
- NativeLibraryKind::NativeFramework |
- NativeLibraryKind::NativeUnknown => continue,
- }
- if let Some(name) = lib.name {
- ab.add_native_library(&name.as_str());
- }
- }
-
- // After adding all files to the archive, we need to update the
- // symbol table of the archive.
- ab.update_symbols();
-
- // Note that it is important that we add all of our non-object "magical
- // files" *after* all of the object files in the archive. The reason for
- // this is as follows:
- //
- // * When performing LTO, this archive will be modified to remove
- // objects from above. The reason for this is described below.
- //
- // * When the system linker looks at an archive, it will attempt to
- // determine the architecture of the archive in order to see whether its
- // linkable.
- //
- // The algorithm for this detection is: iterate over the files in the
- // archive. Skip magical SYMDEF names. Interpret the first file as an
- // object file. Read architecture from the object file.
- //
- // * As one can probably see, if "metadata" and "foo.bc" were placed
- // before all of the objects, then the architecture of this archive would
- // not be correctly inferred once 'foo.o' is removed.
- //
- // Basically, all this means is that this code should not move above the
- // code above.
- match flavor {
- RlibFlavor::Normal => {
- // Instead of putting the metadata in an object file section, rlibs
- // contain the metadata in a separate file.
- ab.add_file(&emit_metadata(sess, codegen_results, tmpdir));
-
- // For LTO purposes, the bytecode of this library is also inserted
- // into the archive.
- for bytecode in codegen_results
- .modules
- .iter()
- .filter_map(|m| m.bytecode_compressed.as_ref())
- {
- ab.add_file(bytecode);
- }
-
- // After adding all files to the archive, we need to update the
- // symbol table of the archive. This currently dies on macOS (see
- // #11162), and isn't necessary there anyway
- if !sess.target.target.options.is_like_osx {
- ab.update_symbols();
- }
- }
-
- RlibFlavor::StaticlibBase => {
- let obj = codegen_results.allocator_module
- .as_ref()
- .and_then(|m| m.object.as_ref());
- if let Some(obj) = obj {
- ab.add_file(obj);
- }
- }
- }
-
- ab
-}
-
-// Create a static archive
-//
-// This is essentially the same thing as an rlib, but it also involves adding
-// all of the upstream crates' objects into the archive. This will slurp in
-// all of the native libraries of upstream dependencies as well.
-//
-// Additionally, there's no way for us to link dynamic libraries, so we warn
-// about all dynamic library dependencies that they're not linked in.
-//
-// There's no need to include metadata in a static archive, so ensure to not
-// link in the metadata object file (and also don't prepare the archive with a
-// metadata file).
-fn link_staticlib(sess: &Session,
- codegen_results: &CodegenResults,
- out_filename: &Path,
- tempdir: &TempDir) {
- let mut ab = link_rlib(sess,
- codegen_results,
- RlibFlavor::StaticlibBase,
- out_filename,
- tempdir);
- let mut all_native_libs = vec![];
-
- let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
- let name = &codegen_results.crate_info.crate_name[&cnum];
- let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
-
- // Here when we include the rlib into our staticlib we need to make a
- // decision whether to include the extra object files along the way.
- // These extra object files come from statically included native
- // libraries, but they may be cfg'd away with #[link(cfg(..))].
- //
- // This unstable feature, though, only needs liblibc to work. The only
- // use case there is where musl is statically included in liblibc.rlib,
- // so if we don't want the included version we just need to skip it. As
- // a result the logic here is that if *any* linked library is cfg'd away
- // we just skip all object files.
- //
- // Clearly this is not sufficient for a general purpose feature, and
- // we'd want to read from the library's metadata to determine which
- // object files come from where and selectively skip them.
- let skip_object_files = native_libs.iter().any(|lib| {
- lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
- });
- ab.add_rlib(path,
- &name.as_str(),
- are_upstream_rust_objects_already_included(sess) &&
- !ignored_for_lto(sess, &codegen_results.crate_info, cnum),
- skip_object_files).unwrap();
-
- all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
- });
- if let Err(e) = res {
- sess.fatal(&e);
- }
-
- ab.update_symbols();
- ab.build();
-
- if !all_native_libs.is_empty() {
- if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) {
- print_native_static_libs(sess, &all_native_libs);
- }
- }
-}
-
-fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
- let lib_args: Vec<_> = all_native_libs.iter()
- .filter(|l| relevant_lib(sess, l))
- .filter_map(|lib| {
- let name = lib.name?;
- match lib.kind {
- NativeLibraryKind::NativeStaticNobundle |
- NativeLibraryKind::NativeUnknown => {
- if sess.target.target.options.is_like_msvc {
- Some(format!("{}.lib", name))
- } else {
- Some(format!("-l{}", name))
- }
- },
- NativeLibraryKind::NativeFramework => {
- // ld-only syntax, since there are no frameworks in MSVC
- Some(format!("-framework {}", name))
- },
- // These are included, no need to print them
- NativeLibraryKind::NativeStatic => None,
- }
- })
- .collect();
- if !lib_args.is_empty() {
- sess.note_without_error("Link against the following native artifacts when linking \
- against this static library. The order and any duplication \
- can be significant on some platforms.");
- // Prefix for greppability
- sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" ")));
- }
-}
-
-fn get_file_path(sess: &Session, name: &str) -> PathBuf {
- let fs = sess.target_filesearch(PathKind::Native);
- let file_path = fs.get_lib_path().join(name);
- if file_path.exists() {
- return file_path
- }
- for search_path in fs.search_paths() {
- let file_path = search_path.dir.join(name);
- if file_path.exists() {
- return file_path
- }
- }
- PathBuf::from(name)
-}
-
-// Create a dynamic library or executable
-//
-// This will invoke the system linker/cc to create the resulting file. This
-// links to all upstream files as well.
-fn link_natively(sess: &Session,
- crate_type: config::CrateType,
- out_filename: &Path,
- codegen_results: &CodegenResults,
- tmpdir: &Path) {
- info!("preparing {:?} to {:?}", crate_type, out_filename);
- let (linker, flavor) = linker_and_flavor(sess);
-
- // The invocations of cc share some flags across platforms
- let (pname, mut cmd) = get_linker(sess, &linker, flavor);
-
- if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
- cmd.args(args);
- }
- if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
- if sess.crt_static() {
- cmd.args(args);
- }
- }
- if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
- cmd.args(args);
- }
- cmd.args(&sess.opts.debugging_opts.pre_link_arg);
-
- if sess.target.target.options.is_like_fuchsia {
- let prefix = match sess.opts.debugging_opts.sanitizer {
- Some(Sanitizer::Address) => "asan/",
- _ => "",
- };
- cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
- }
-
- let pre_link_objects = if crate_type == config::CrateType::Executable {
- &sess.target.target.options.pre_link_objects_exe
- } else {
- &sess.target.target.options.pre_link_objects_dll
- };
- for obj in pre_link_objects {
- cmd.arg(get_file_path(sess, obj));
- }
-
- if crate_type == config::CrateType::Executable && sess.crt_static() {
- for obj in &sess.target.target.options.pre_link_objects_exe_crt {
- cmd.arg(get_file_path(sess, obj));
- }
- }
-
- if sess.target.target.options.is_like_emscripten {
- cmd.arg("-s");
- cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
- "DISABLE_EXCEPTION_CATCHING=1"
- } else {
- "DISABLE_EXCEPTION_CATCHING=0"
- });
- }
-
- {
- let target_cpu = crate::llvm_util::target_cpu(sess);
- let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu);
- link_args(&mut *linker, flavor, sess, crate_type, tmpdir,
- out_filename, codegen_results);
- cmd = linker.finalize();
- }
- if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
- cmd.args(args);
- }
- for obj in &sess.target.target.options.post_link_objects {
- cmd.arg(get_file_path(sess, obj));
- }
- if sess.crt_static() {
- for obj in &sess.target.target.options.post_link_objects_crt {
- cmd.arg(get_file_path(sess, obj));
- }
- }
- if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
- cmd.args(args);
- }
- for &(ref k, ref v) in &sess.target.target.options.link_env {
- cmd.env(k, v);
- }
-
- if sess.opts.debugging_opts.print_link_args {
- println!("{:?}", &cmd);
- }
-
- // May have not found libraries in the right formats.
- sess.abort_if_errors();
-
- // Invoke the system linker
- //
- // Note that there's a terribly awful hack that really shouldn't be present
- // in any compiler. Here an environment variable is supported to
- // automatically retry the linker invocation if the linker looks like it
- // segfaulted.
- //
- // Gee that seems odd, normally segfaults are things we want to know about!
- // Unfortunately though in rust-lang/rust#38878 we're experiencing the
- // linker segfaulting on Travis quite a bit which is causing quite a bit of
- // pain to land PRs when they spuriously fail due to a segfault.
- //
- // The issue #38878 has some more debugging information on it as well, but
- // this unfortunately looks like it's just a race condition in macOS's linker
- // with some thread pool working in the background. It seems that no one
- // currently knows a fix for this so in the meantime we're left with this...
- info!("{:?}", &cmd);
- let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
- let mut prog;
- let mut i = 0;
- loop {
- i += 1;
- prog = time(sess, "running linker", || {
- exec_linker(sess, &mut cmd, out_filename, tmpdir)
- });
- let output = match prog {
- Ok(ref output) => output,
- Err(_) => break,
- };
- if output.status.success() {
- break
- }
- let mut out = output.stderr.clone();
- out.extend(&output.stdout);
- let out = String::from_utf8_lossy(&out);
-
- // Check to see if the link failed with "unrecognized command line option:
- // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
- // reperform the link step without the -no-pie option. This is safe because
- // if the linker doesn't support -no-pie then it should not default to
- // linking executables as pie. Different versions of gcc seem to use
- // different quotes in the error message so don't check for them.
- if sess.target.target.options.linker_is_gnu &&
- flavor != LinkerFlavor::Ld &&
- (out.contains("unrecognized command line option") ||
- out.contains("unknown argument")) &&
- out.contains("-no-pie") &&
- cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") {
- info!("linker output: {:?}", out);
- warn!("Linker does not support -no-pie command line option. Retrying without.");
- for arg in cmd.take_args() {
- if arg.to_string_lossy() != "-no-pie" {
- cmd.arg(arg);
- }
- }
- info!("{:?}", &cmd);
- continue;
- }
- if !retry_on_segfault || i > 3 {
- break
- }
- let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11";
- let msg_bus = "clang: error: unable to execute command: Bus error: 10";
- if !(out.contains(msg_segv) || out.contains(msg_bus)) {
- break
- }
-
- warn!(
- "looks like the linker segfaulted when we tried to call it, \
- automatically retrying again. cmd = {:?}, out = {}.",
- cmd,
- out,
- );
- }
-
- match prog {
- Ok(prog) => {
- fn escape_string(s: &[u8]) -> String {
- str::from_utf8(s).map(|s| s.to_owned())
- .unwrap_or_else(|_| {
- let mut x = "Non-UTF-8 output: ".to_string();
- x.extend(s.iter()
- .flat_map(|&b| ascii::escape_default(b))
- .map(char::from));
- x
- })
- }
- if !prog.status.success() {
- let mut output = prog.stderr.clone();
- output.extend_from_slice(&prog.stdout);
- sess.struct_err(&format!("linking with `{}` failed: {}",
- pname.display(),
- prog.status))
- .note(&format!("{:?}", &cmd))
- .note(&escape_string(&output))
- .emit();
- sess.abort_if_errors();
- }
- info!("linker stderr:\n{}", escape_string(&prog.stderr));
- info!("linker stdout:\n{}", escape_string(&prog.stdout));
- },
- Err(e) => {
- let linker_not_found = e.kind() == io::ErrorKind::NotFound;
-
- let mut linker_error = {
- if linker_not_found {
- sess.struct_err(&format!("linker `{}` not found", pname.display()))
- } else {
- sess.struct_err(&format!("could not exec the linker `{}`", pname.display()))
- }
- };
-
- linker_error.note(&e.to_string());
-
- if !linker_not_found {
- linker_error.note(&format!("{:?}", &cmd));
- }
-
- linker_error.emit();
-
- if sess.target.target.options.is_like_msvc && linker_not_found {
- sess.note_without_error("the msvc targets depend on the msvc linker \
- but `link.exe` was not found");
- sess.note_without_error("please ensure that VS 2013, VS 2015 or VS 2017 \
- was installed with the Visual C++ option");
- }
- sess.abort_if_errors();
- }
- }
-
-
- // On macOS, debuggers need this utility to get run to do some munging of
- // the symbols. Note, though, that if the object files are being preserved
- // for their debug information there's no need for us to run dsymutil.
- if sess.target.target.options.is_like_osx &&
- sess.opts.debuginfo != DebugInfo::None &&
- !preserve_objects_for_their_debuginfo(sess)
- {
- if let Err(e) = Command::new("dsymutil").arg(out_filename).output() {
- sess.fatal(&format!("failed to run dsymutil: {}", e))
- }
- }
-
- if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" {
- wasm::add_producer_section(
- &out_filename,
- &sess.edition().to_string(),
- option_env!("CFG_VERSION").unwrap_or("unknown"),
- );
- }
-}
-
-fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path)
- -> io::Result<Output>
-{
- // When attempting to spawn the linker we run a risk of blowing out the
- // size limits for spawning a new process with respect to the arguments
- // we pass on the command line.
- //
- // Here we attempt to handle errors from the OS saying "your list of
- // arguments is too big" by reinvoking the linker again with an `@`-file
- // that contains all the arguments. The theory is that this is then
- // accepted on all linkers and the linker will read all its options out of
- // there instead of looking at the command line.
- if !cmd.very_likely_to_exceed_some_spawn_limit() {
- match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
- Ok(child) => {
- let output = child.wait_with_output();
- flush_linked_file(&output, out_filename)?;
- return output;
- }
- Err(ref e) if command_line_too_big(e) => {
- info!("command line to linker was too big: {}", e);
- }
- Err(e) => return Err(e)
- }
- }
-
- info!("falling back to passing arguments to linker via an @-file");
- let mut cmd2 = cmd.clone();
- let mut args = String::new();
- for arg in cmd2.take_args() {
- args.push_str(&Escape {
- arg: arg.to_str().unwrap(),
- is_like_msvc: sess.target.target.options.is_like_msvc,
- }.to_string());
- args.push_str("\n");
- }
- let file = tmpdir.join("linker-arguments");
- let bytes = if sess.target.target.options.is_like_msvc {
- let mut out = Vec::with_capacity((1 + args.len()) * 2);
- // start the stream with a UTF-16 BOM
- for c in iter::once(0xFEFF).chain(args.encode_utf16()) {
- // encode in little endian
- out.push(c as u8);
- out.push((c >> 8) as u8);
- }
- out
- } else {
- args.into_bytes()
- };
- fs::write(&file, &bytes)?;
- cmd2.arg(format!("@{}", file.display()));
- info!("invoking linker {:?}", cmd2);
- let output = cmd2.output();
- flush_linked_file(&output, out_filename)?;
- return output;
-
- #[cfg(unix)]
- fn flush_linked_file(_: &io::Result<Output>, _: &Path) -> io::Result<()> {
- Ok(())
- }
-
- #[cfg(windows)]
- fn flush_linked_file(command_output: &io::Result<Output>, out_filename: &Path)
- -> io::Result<()>
- {
- // On Windows, under high I/O load, output buffers are sometimes not flushed,
- // even long after process exit, causing nasty, non-reproducible output bugs.
- //
- // File::sync_all() calls FlushFileBuffers() down the line, which solves the problem.
- //
- // А full writeup of the original Chrome bug can be found at
- // randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp
-
- if let &Ok(ref out) = command_output {
- if out.status.success() {
- if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) {
- of.sync_all()?;
- }
- }
- }
-
- Ok(())
- }
-
- #[cfg(unix)]
- fn command_line_too_big(err: &io::Error) -> bool {
- err.raw_os_error() == Some(::libc::E2BIG)
- }
-
- #[cfg(windows)]
- fn command_line_too_big(err: &io::Error) -> bool {
- const ERROR_FILENAME_EXCED_RANGE: i32 = 206;
- err.raw_os_error() == Some(ERROR_FILENAME_EXCED_RANGE)
- }
-
- struct Escape<'a> {
- arg: &'a str,
- is_like_msvc: bool,
- }
-
- impl<'a> fmt::Display for Escape<'a> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if self.is_like_msvc {
- // This is "documented" at
- // https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx
- //
- // Unfortunately there's not a great specification of the
- // syntax I could find online (at least) but some local
- // testing showed that this seemed sufficient-ish to catch
- // at least a few edge cases.
- write!(f, "\"")?;
- for c in self.arg.chars() {
- match c {
- '"' => write!(f, "\\{}", c)?,
- c => write!(f, "{}", c)?,
- }
- }
- write!(f, "\"")?;
- } else {
- // This is documented at https://linux.die.net/man/1/ld, namely:
- //
- // > Options in file are separated by whitespace. A whitespace
- // > character may be included in an option by surrounding the
- // > entire option in either single or double quotes. Any
- // > character (including a backslash) may be included by
- // > prefixing the character to be included with a backslash.
- //
- // We put an argument on each line, so all we need to do is
- // ensure the line is interpreted as one whole argument.
- for c in self.arg.chars() {
- match c {
- '\\' | ' ' => write!(f, "\\{}", c)?,
- c => write!(f, "{}", c)?,
- }
- }
- }
- Ok(())
- }
- }
-}
-
-fn link_args(cmd: &mut dyn Linker,
- flavor: LinkerFlavor,
- sess: &Session,
- crate_type: config::CrateType,
- tmpdir: &Path,
- out_filename: &Path,
- codegen_results: &CodegenResults) {
-
- // Linker plugins should be specified early in the list of arguments
- cmd.linker_plugin_lto();
-
- // The default library location, we need this to find the runtime.
- // The location of crates will be determined as needed.
- let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
-
- // target descriptor
- let t = &sess.target.target;
-
- cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
- for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
- cmd.add_object(obj);
- }
- cmd.output_filename(out_filename);
-
- if crate_type == config::CrateType::Executable &&
- sess.target.target.options.is_like_windows {
- if let Some(ref s) = codegen_results.windows_subsystem {
- cmd.subsystem(s);
- }
- }
-
- // If we're building a dynamic library then some platforms need to make sure
- // that all symbols are exported correctly from the dynamic library.
- if crate_type != config::CrateType::Executable ||
- sess.target.target.options.is_like_emscripten {
- cmd.export_symbols(tmpdir, crate_type);
- }
-
- // When linking a dynamic library, we put the metadata into a section of the
- // executable. This metadata is in a separate object file from the main
- // object file, so we link that in here.
- if crate_type == config::CrateType::Dylib ||
- crate_type == config::CrateType::ProcMacro {
- if let Some(obj) = codegen_results.metadata_module.object.as_ref() {
- cmd.add_object(obj);
- }
- }
-
- let obj = codegen_results.allocator_module
- .as_ref()
- .and_then(|m| m.object.as_ref());
- if let Some(obj) = obj {
- cmd.add_object(obj);
- }
-
- // Try to strip as much out of the generated object by removing unused
- // sections if possible. See more comments in linker.rs
- if !sess.opts.cg.link_dead_code {
- let keep_metadata = crate_type == config::CrateType::Dylib;
- cmd.gc_sections(keep_metadata);
- }
-
- let used_link_args = &codegen_results.crate_info.link_args;
-
- if crate_type == config::CrateType::Executable {
- let mut position_independent_executable = false;
-
- if t.options.position_independent_executables {
- let empty_vec = Vec::new();
- let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
- let more_args = &sess.opts.cg.link_arg;
- let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
-
- if get_reloc_model(sess) == llvm::RelocMode::PIC
- && !sess.crt_static() && !args.any(|x| *x == "-static") {
- position_independent_executable = true;
- }
- }
-
- if position_independent_executable {
- cmd.position_independent_executable();
- } else {
- // recent versions of gcc can be configured to generate position
- // independent executables by default. We have to pass -no-pie to
- // explicitly turn that off. Not applicable to ld.
- if sess.target.target.options.linker_is_gnu
- && flavor != LinkerFlavor::Ld {
- cmd.no_position_independent_executable();
- }
- }
- }
-
- let relro_level = match sess.opts.debugging_opts.relro_level {
- Some(level) => level,
- None => t.options.relro_level,
- };
- match relro_level {
- RelroLevel::Full => {
- cmd.full_relro();
- },
- RelroLevel::Partial => {
- cmd.partial_relro();
- },
- RelroLevel::Off => {
- cmd.no_relro();
- },
- RelroLevel::None => {
- },
- }
-
- // Pass optimization flags down to the linker.
- cmd.optimize();
-
- // Pass debuginfo flags down to the linker.
- cmd.debuginfo();
-
- // We want to, by default, prevent the compiler from accidentally leaking in
- // any system libraries, so we may explicitly ask linkers to not link to any
- // libraries by default. Note that this does not happen for windows because
- // windows pulls in some large number of libraries and I couldn't quite
- // figure out which subset we wanted.
- //
- // This is all naturally configurable via the standard methods as well.
- if !sess.opts.cg.default_linker_libraries.unwrap_or(false) &&
- t.options.no_default_libraries
- {
- cmd.no_default_libraries();
- }
-
- // Take careful note of the ordering of the arguments we pass to the linker
- // here. Linkers will assume that things on the left depend on things to the
- // right. Things on the right cannot depend on things on the left. This is
- // all formally implemented in terms of resolving symbols (libs on the right
- // resolve unknown symbols of libs on the left, but not vice versa).
- //
- // For this reason, we have organized the arguments we pass to the linker as
- // such:
- //
- // 1. The local object that LLVM just generated
- // 2. Local native libraries
- // 3. Upstream rust libraries
- // 4. Upstream native libraries
- //
- // The rationale behind this ordering is that those items lower down in the
- // list can't depend on items higher up in the list. For example nothing can
- // depend on what we just generated (e.g., that'd be a circular dependency).
- // Upstream rust libraries are not allowed to depend on our local native
- // libraries as that would violate the structure of the DAG, in that
- // scenario they are required to link to them as well in a shared fashion.
- //
- // Note that upstream rust libraries may contain native dependencies as
- // well, but they also can't depend on what we just started to add to the
- // link line. And finally upstream native libraries can't depend on anything
- // in this DAG so far because they're only dylibs and dylibs can only depend
- // on other dylibs (e.g., other native deps).
- add_local_native_libraries(cmd, sess, codegen_results);
- add_upstream_rust_crates(cmd, sess, codegen_results, crate_type, tmpdir);
- add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
-
- // Tell the linker what we're doing.
- if crate_type != config::CrateType::Executable {
- cmd.build_dylib(out_filename);
- }
- if crate_type == config::CrateType::Executable && sess.crt_static() {
- cmd.build_static_executable();
- }
-
- if sess.opts.debugging_opts.pgo_gen.is_some() {
- cmd.pgo_gen();
- }
-
- // FIXME (#2397): At some point we want to rpath our guesses as to
- // where extern libraries might live, based on the
- // addl_lib_search_paths
- if sess.opts.cg.rpath {
- let target_triple = sess.opts.target_triple.triple();
- let mut get_install_prefix_lib_path = || {
- let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");
- let tlib = filesearch::relative_target_lib_path(&sess.sysroot, target_triple);
- let mut path = PathBuf::from(install_prefix);
- path.push(&tlib);
-
- path
- };
- let mut rpath_config = RPathConfig {
- used_crates: &codegen_results.crate_info.used_crates_dynamic,
- out_filename: out_filename.to_path_buf(),
- has_rpath: sess.target.target.options.has_rpath,
- is_like_osx: sess.target.target.options.is_like_osx,
- linker_is_gnu: sess.target.target.options.linker_is_gnu,
- get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
- };
- cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
- }
-
- // Finally add all the linker arguments provided on the command line along
- // with any #[link_args] attributes found inside the crate
- if let Some(ref args) = sess.opts.cg.link_args {
- cmd.args(args);
- }
- cmd.args(&sess.opts.cg.link_arg);
- cmd.args(&used_link_args);
-}
-
-// # Native library linking
-//
-// User-supplied library search paths (-L on the command line). These are
-// the same paths used to find Rust crates, so some of them may have been
-// added already by the previous crate linking code. This only allows them
-// to be found at compile time so it is still entirely up to outside
-// forces to make sure that library can be found at runtime.
-//
-// Also note that the native libraries linked here are only the ones located
-// in the current crate. Upstream crates with native library dependencies
-// may have their native library pulled in above.
-fn add_local_native_libraries(cmd: &mut dyn Linker,
- sess: &Session,
- codegen_results: &CodegenResults) {
- let filesearch = sess.target_filesearch(PathKind::All);
- for search_path in filesearch.search_paths() {
- match search_path.kind {
- PathKind::Framework => { cmd.framework_path(&search_path.dir); }
- _ => { cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)); }
- }
- }
-
- let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| {
- relevant_lib(sess, l)
- });
-
- let search_path = archive_search_paths(sess);
- for lib in relevant_libs {
- let name = match lib.name {
- Some(ref l) => l,
- None => continue,
- };
- match lib.kind {
- NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
- NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
- NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()),
- NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(),
- &search_path)
- }
- }
-}
-
-// # Rust Crate linking
-//
-// Rust crates are not considered at all when creating an rlib output. All
-// dependencies will be linked when producing the final output (instead of
-// the intermediate rlib version)
-fn add_upstream_rust_crates(cmd: &mut dyn Linker,
- sess: &Session,
- codegen_results: &CodegenResults,
- crate_type: config::CrateType,
- tmpdir: &Path) {
- // All of the heavy lifting has previously been accomplished by the
- // dependency_format module of the compiler. This is just crawling the
- // output of that module, adding crates as necessary.
- //
- // Linking to a rlib involves just passing it to the linker (the linker
- // will slurp up the object files inside), and linking to a dynamic library
- // involves just passing the right -l flag.
-
- let formats = sess.dependency_formats.borrow();
- let data = formats.get(&crate_type).unwrap();
-
- // Invoke get_used_crates to ensure that we get a topological sorting of
- // crates.
- let deps = &codegen_results.crate_info.used_crates_dynamic;
-
- // There's a few internal crates in the standard library (aka libcore and
- // libstd) which actually have a circular dependence upon one another. This
- // currently arises through "weak lang items" where libcore requires things
- // like `rust_begin_unwind` but libstd ends up defining it. To get this
- // circular dependence to work correctly in all situations we'll need to be
- // sure to correctly apply the `--start-group` and `--end-group` options to
- // GNU linkers, otherwise if we don't use any other symbol from the standard
- // library it'll get discarded and the whole application won't link.
- //
- // In this loop we're calculating the `group_end`, after which crate to
- // pass `--end-group` and `group_start`, before which crate to pass
- // `--start-group`. We currently do this by passing `--end-group` after
- // the first crate (when iterating backwards) that requires a lang item
- // defined somewhere else. Once that's set then when we've defined all the
- // necessary lang items we'll pass `--start-group`.
- //
- // Note that this isn't amazing logic for now but it should do the trick
- // for the current implementation of the standard library.
- let mut group_end = None;
- let mut group_start = None;
- let mut end_with = FxHashSet::default();
- let info = &codegen_results.crate_info;
- for &(cnum, _) in deps.iter().rev() {
- if let Some(missing) = info.missing_lang_items.get(&cnum) {
- end_with.extend(missing.iter().cloned());
- if end_with.len() > 0 && group_end.is_none() {
- group_end = Some(cnum);
- }
- }
- end_with.retain(|item| info.lang_item_to_crate.get(item) != Some(&cnum));
- if end_with.len() == 0 && group_end.is_some() {
- group_start = Some(cnum);
- break
- }
- }
-
- // If we didn't end up filling in all lang items from upstream crates then
- // we'll be filling it in with our crate. This probably means we're the
- // standard library itself, so skip this for now.
- if group_end.is_some() && group_start.is_none() {
- group_end = None;
- }
-
- let mut compiler_builtins = None;
-
- for &(cnum, _) in deps.iter() {
- if group_start == Some(cnum) {
- cmd.group_start();
- }
-
- // We may not pass all crates through to the linker. Some crates may
- // appear statically in an existing dylib, meaning we'll pick up all the
- // symbols from the dylib.
- let src = &codegen_results.crate_info.used_crate_source[&cnum];
- match data[cnum.as_usize() - 1] {
- _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
- add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
- }
- _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) => {
- link_sanitizer_runtime(cmd, sess, codegen_results, tmpdir, cnum);
- }
- // compiler-builtins are always placed last to ensure that they're
- // linked correctly.
- _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => {
- assert!(compiler_builtins.is_none());
- compiler_builtins = Some(cnum);
- }
- Linkage::NotLinked |
- Linkage::IncludedFromDylib => {}
- Linkage::Static => {
- add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
- }
- Linkage::Dynamic => {
- add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0)
- }
- }
-
- if group_end == Some(cnum) {
- cmd.group_end();
- }
- }
-
- // compiler-builtins are always placed last to ensure that they're
- // linked correctly.
- // We must always link the `compiler_builtins` crate statically. Even if it
- // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
- // is used)
- if let Some(cnum) = compiler_builtins {
- add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
- }
-
- // Converts a library file-stem into a cc -l argument
- fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str {
- if stem.starts_with("lib") && !config.target.options.is_like_windows {
- &stem[3..]
- } else {
- stem
- }
- }
-
- // We must link the sanitizer runtime using -Wl,--whole-archive but since
- // it's packed in a .rlib, it contains stuff that are not objects that will
- // make the linker error. So we must remove those bits from the .rlib before
- // linking it.
- fn link_sanitizer_runtime(cmd: &mut dyn Linker,
- sess: &Session,
- codegen_results: &CodegenResults,
- tmpdir: &Path,
- cnum: CrateNum) {
- let src = &codegen_results.crate_info.used_crate_source[&cnum];
- let cratepath = &src.rlib.as_ref().unwrap().0;
-
- if sess.target.target.options.is_like_osx {
- // On Apple platforms, the sanitizer is always built as a dylib, and
- // LLVM will link to `@rpath/*.dylib`, so we need to specify an
- // rpath to the library as well (the rpath should be absolute, see
- // PR #41352 for details).
- //
- // FIXME: Remove this logic into librustc_*san once Cargo supports it
- let rpath = cratepath.parent().unwrap();
- let rpath = rpath.to_str().expect("non-utf8 component in path");
- cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]);
- }
-
- let dst = tmpdir.join(cratepath.file_name().unwrap());
- let cfg = archive_config(sess, &dst, Some(cratepath));
- let mut archive = ArchiveBuilder::new(cfg);
- archive.update_symbols();
-
- for f in archive.src_files() {
- if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
- archive.remove_file(&f);
- }
- }
-
- archive.build();
-
- cmd.link_whole_rlib(&dst);
- }
-
- // Adds the static "rlib" versions of all crates to the command line.
- // There's a bit of magic which happens here specifically related to LTO and
- // dynamic libraries. Specifically:
- //
- // * For LTO, we remove upstream object files.
- // * For dylibs we remove metadata and bytecode from upstream rlibs
- //
- // When performing LTO, almost(*) all of the bytecode from the upstream
- // libraries has already been included in our object file output. As a
- // result we need to remove the object files in the upstream libraries so
- // the linker doesn't try to include them twice (or whine about duplicate
- // symbols). We must continue to include the rest of the rlib, however, as
- // it may contain static native libraries which must be linked in.
- //
- // (*) Crates marked with `#![no_builtins]` don't participate in LTO and
- // their bytecode wasn't included. The object files in those libraries must
- // still be passed to the linker.
- //
- // When making a dynamic library, linkers by default don't include any
- // object files in an archive if they're not necessary to resolve the link.
- // We basically want to convert the archive (rlib) to a dylib, though, so we
- // *do* want everything included in the output, regardless of whether the
- // linker thinks it's needed or not. As a result we must use the
- // --whole-archive option (or the platform equivalent). When using this
- // option the linker will fail if there are non-objects in the archive (such
- // as our own metadata and/or bytecode). All in all, for rlibs to be
- // entirely included in dylibs, we need to remove all non-object files.
- //
- // Note, however, that if we're not doing LTO or we're not producing a dylib
- // (aka we're making an executable), we can just pass the rlib blindly to
- // the linker (fast) because it's fine if it's not actually included as
- // we're at the end of the dependency chain.
- fn add_static_crate(cmd: &mut dyn Linker,
- sess: &Session,
- codegen_results: &CodegenResults,
- tmpdir: &Path,
- crate_type: config::CrateType,
- cnum: CrateNum) {
- let src = &codegen_results.crate_info.used_crate_source[&cnum];
- let cratepath = &src.rlib.as_ref().unwrap().0;
-
- // See the comment above in `link_staticlib` and `link_rlib` for why if
- // there's a static library that's not relevant we skip all object
- // files.
- let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
- let skip_native = native_libs.iter().any(|lib| {
- lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
- });
-
- if (!are_upstream_rust_objects_already_included(sess) ||
- ignored_for_lto(sess, &codegen_results.crate_info, cnum)) &&
- crate_type != config::CrateType::Dylib &&
- !skip_native {
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
- return
- }
-
- let dst = tmpdir.join(cratepath.file_name().unwrap());
- let name = cratepath.file_name().unwrap().to_str().unwrap();
- let name = &name[3..name.len() - 5]; // chop off lib/.rlib
-
- time_ext(sess.time_extended(), Some(sess), &format!("altering {}.rlib", name), || {
- let cfg = archive_config(sess, &dst, Some(cratepath));
- let mut archive = ArchiveBuilder::new(cfg);
- archive.update_symbols();
-
- let mut any_objects = false;
- for f in archive.src_files() {
- if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
- archive.remove_file(&f);
- continue
- }
-
- let canonical = f.replace("-", "_");
- let canonical_name = name.replace("-", "_");
-
- // Look for `.rcgu.o` at the end of the filename to conclude
- // that this is a Rust-related object file.
- fn looks_like_rust(s: &str) -> bool {
- let path = Path::new(s);
- let ext = path.extension().and_then(|s| s.to_str());
- if ext != Some(OutputType::Object.extension()) {
- return false
- }
- let ext2 = path.file_stem()
- .and_then(|s| Path::new(s).extension())
- .and_then(|s| s.to_str());
- ext2 == Some(RUST_CGU_EXT)
- }
-
- let is_rust_object =
- canonical.starts_with(&canonical_name) &&
- looks_like_rust(&f);
-
- // If we've been requested to skip all native object files
- // (those not generated by the rust compiler) then we can skip
- // this file. See above for why we may want to do this.
- let skip_because_cfg_say_so = skip_native && !is_rust_object;
-
- // If we're performing LTO and this is a rust-generated object
- // file, then we don't need the object file as it's part of the
- // LTO module. Note that `#![no_builtins]` is excluded from LTO,
- // though, so we let that object file slide.
- let skip_because_lto = are_upstream_rust_objects_already_included(sess) &&
- is_rust_object &&
- (sess.target.target.options.no_builtins ||
- !codegen_results.crate_info.is_no_builtins.contains(&cnum));
-
- if skip_because_cfg_say_so || skip_because_lto {
- archive.remove_file(&f);
- } else {
- any_objects = true;
- }
- }
-
- if !any_objects {
- return
- }
- archive.build();
-
- // If we're creating a dylib, then we need to include the
- // whole of each object in our archive into that artifact. This is
- // because a `dylib` can be reused as an intermediate artifact.
- //
- // Note, though, that we don't want to include the whole of a
- // compiler-builtins crate (e.g., compiler-rt) because it'll get
- // repeatedly linked anyway.
- if crate_type == config::CrateType::Dylib &&
- codegen_results.crate_info.compiler_builtins != Some(cnum) {
- cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
- } else {
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
- }
- });
- }
-
- // Same thing as above, but for dynamic crates instead of static crates.
- fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
- // Just need to tell the linker about where the library lives and
- // what its name is
- let parent = cratepath.parent();
- if let Some(dir) = parent {
- cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
- }
- let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
- cmd.link_rust_dylib(&unlib(&sess.target, filestem),
- parent.unwrap_or(Path::new("")));
- }
-}
-
-// Link in all of our upstream crates' native dependencies. Remember that
-// all of these upstream native dependencies are all non-static
-// dependencies. We've got two cases then:
-//
-// 1. The upstream crate is an rlib. In this case we *must* link in the
-// native dependency because the rlib is just an archive.
-//
-// 2. The upstream crate is a dylib. In order to use the dylib, we have to
-// have the dependency present on the system somewhere. Thus, we don't
-// gain a whole lot from not linking in the dynamic dependency to this
-// crate as well.
-//
-// The use case for this is a little subtle. In theory the native
-// dependencies of a crate are purely an implementation detail of the crate
-// itself, but the problem arises with generic and inlined functions. If a
-// generic function calls a native function, then the generic function must
-// be instantiated in the target crate, meaning that the native symbol must
-// also be resolved in the target crate.
-fn add_upstream_native_libraries(cmd: &mut dyn Linker,
- sess: &Session,
- codegen_results: &CodegenResults,
- crate_type: config::CrateType) {
- // Be sure to use a topological sorting of crates because there may be
- // interdependencies between native libraries. When passing -nodefaultlibs,
- // for example, almost all native libraries depend on libc, so we have to
- // make sure that's all the way at the right (liblibc is near the base of
- // the dependency chain).
- //
- // This passes RequireStatic, but the actual requirement doesn't matter,
- // we're just getting an ordering of crate numbers, we're not worried about
- // the paths.
- let formats = sess.dependency_formats.borrow();
- let data = formats.get(&crate_type).unwrap();
-
- let crates = &codegen_results.crate_info.used_crates_static;
- for &(cnum, _) in crates {
- for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
- let name = match lib.name {
- Some(ref l) => l,
- None => continue,
- };
- if !relevant_lib(sess, &lib) {
- continue
- }
- match lib.kind {
- NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
- NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
- NativeLibraryKind::NativeStaticNobundle => {
- // Link "static-nobundle" native libs only if the crate they originate from
- // is being linked statically to the current crate. If it's linked dynamically
- // or is an rlib already included via some other dylib crate, the symbols from
- // native libs will have already been included in that dylib.
- if data[cnum.as_usize() - 1] == Linkage::Static {
- cmd.link_staticlib(&name.as_str())
- }
- },
- // ignore statically included native libraries here as we've
- // already included them when we included the rust library
- // previously
- NativeLibraryKind::NativeStatic => {}
- }
- }
- }
-}
-
-fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
- match lib.cfg {
- Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
- None => true,
- }
-}
-
-fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
- match sess.lto() {
- Lto::Fat => true,
- Lto::Thin => {
- // If we defer LTO to the linker, we haven't run LTO ourselves, so
- // any upstream object files have not been copied yet.
- !sess.opts.cg.linker_plugin_lto.enabled()
- }
- Lto::No |
- Lto::ThinLocal => false,
- }
-}
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 84c652f..74cda2d 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -1,4 +1,4 @@
-use crate::back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
+use crate::back::bytecode::DecodedBytecode;
use crate::back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode,
to_llvm_opt_settings};
use crate::llvm::archive_ro::ArchiveRO;
@@ -15,9 +15,8 @@
use rustc::middle::exported_symbols::SymbolExportLevel;
use rustc::session::config::{self, Lto};
use rustc::util::common::time_ext;
-use rustc::util::profiling::ProfileCategory;
use rustc_data_structures::fx::FxHashMap;
-use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
+use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, ModuleKind};
use std::ffi::{CStr, CString};
use std::ptr;
@@ -67,8 +66,7 @@
.iter()
.filter_map(symbol_filter)
.collect::<Vec<CString>>();
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
- "generate_symbol_white_list_for_thinlto");
+ let _timer = cgcx.profile_activity("generate_symbol_white_list_for_thinlto");
info!("{} symbols to preserve in this crate", symbol_white_list.len());
// If we're performing LTO for the entire crate graph, then for each of our
@@ -97,8 +95,7 @@
}
for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
- format!("load: {}", path.display()));
+ let _timer = cgcx.profile_activity(format!("load: {}", path.display()));
let exported_symbols = cgcx.exported_symbols
.as_ref().expect("needs exported symbols for LTO");
symbol_white_list.extend(
@@ -727,8 +724,7 @@
// Like with "fat" LTO, get some better optimizations if landing pads
// are disabled by removing all landing pads.
if cgcx.no_landing_pads {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
- "LLVM_remove_landing_pads");
+ let _timer = cgcx.profile_activity("LLVM_remove_landing_pads");
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind");
}
diff --git a/src/librustc_codegen_llvm/back/rpath.rs b/src/librustc_codegen_llvm/back/rpath.rs
deleted file mode 100644
index 2b7abcb..0000000
--- a/src/librustc_codegen_llvm/back/rpath.rs
+++ /dev/null
@@ -1,270 +0,0 @@
-use rustc_data_structures::fx::FxHashSet;
-use std::env;
-use std::path::{Path, PathBuf};
-use std::fs;
-
-use rustc::hir::def_id::CrateNum;
-use rustc::middle::cstore::LibSource;
-
-pub struct RPathConfig<'a> {
- pub used_crates: &'a [(CrateNum, LibSource)],
- pub out_filename: PathBuf,
- pub is_like_osx: bool,
- pub has_rpath: bool,
- pub linker_is_gnu: bool,
- pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf,
-}
-
-pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
- // No rpath on windows
- if !config.has_rpath {
- return Vec::new();
- }
-
- debug!("preparing the RPATH!");
-
- let libs = config.used_crates.clone();
- let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::<Vec<_>>();
- let rpaths = get_rpaths(config, &libs);
- let mut flags = rpaths_to_flags(&rpaths);
-
- // Use DT_RUNPATH instead of DT_RPATH if available
- if config.linker_is_gnu {
- flags.push("-Wl,--enable-new-dtags".to_owned());
- }
-
- flags
-}
-
-fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
- let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
-
- for rpath in rpaths {
- if rpath.contains(',') {
- ret.push("-Wl,-rpath".into());
- ret.push("-Xlinker".into());
- ret.push(rpath.clone());
- } else {
- ret.push(format!("-Wl,-rpath,{}", &(*rpath)));
- }
- }
-
- ret
-}
-
-fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> {
- debug!("output: {:?}", config.out_filename.display());
- debug!("libs:");
- for libpath in libs {
- debug!(" {:?}", libpath.display());
- }
-
- // Use relative paths to the libraries. Binaries can be moved
- // as long as they maintain the relative relationship to the
- // crates they depend on.
- let rel_rpaths = get_rpaths_relative_to_output(config, libs);
-
- // And a final backup rpath to the global library location.
- let fallback_rpaths = vec![get_install_prefix_rpath(config)];
-
- fn log_rpaths(desc: &str, rpaths: &[String]) {
- debug!("{} rpaths:", desc);
- for rpath in rpaths {
- debug!(" {}", *rpath);
- }
- }
-
- log_rpaths("relative", &rel_rpaths);
- log_rpaths("fallback", &fallback_rpaths);
-
- let mut rpaths = rel_rpaths;
- rpaths.extend_from_slice(&fallback_rpaths);
-
- // Remove duplicates
- let rpaths = minimize_rpaths(&rpaths);
-
- rpaths
-}
-
-fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>,
- libs: &[PathBuf]) -> Vec<String> {
- libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
-}
-
-fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String {
- // Mac doesn't appear to support $ORIGIN
- let prefix = if config.is_like_osx {
- "@loader_path"
- } else {
- "$ORIGIN"
- };
-
- let cwd = env::current_dir().unwrap();
- let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib));
- lib.pop(); // strip filename
- let mut output = cwd.join(&config.out_filename);
- output.pop(); // strip filename
- let output = fs::canonicalize(&output).unwrap_or(output);
- let relative = path_relative_from(&lib, &output).unwrap_or_else(||
- panic!("couldn't create relative path from {:?} to {:?}", output, lib));
- // FIXME (#9639): This needs to handle non-utf8 paths
- format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
-}
-
-// This routine is adapted from the *old* Path's `path_relative_from`
-// function, which works differently from the new `relative_from` function.
-// In particular, this handles the case on unix where both paths are
-// absolute but with only the root as the common directory.
-fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
- use std::path::Component;
-
- if path.is_absolute() != base.is_absolute() {
- if path.is_absolute() {
- Some(PathBuf::from(path))
- } else {
- None
- }
- } else {
- let mut ita = path.components();
- let mut itb = base.components();
- let mut comps: Vec<Component<'_>> = vec![];
- loop {
- match (ita.next(), itb.next()) {
- (None, None) => break,
- (Some(a), None) => {
- comps.push(a);
- comps.extend(ita.by_ref());
- break;
- }
- (None, _) => comps.push(Component::ParentDir),
- (Some(a), Some(b)) if comps.is_empty() && a == b => (),
- (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
- (Some(_), Some(b)) if b == Component::ParentDir => return None,
- (Some(a), Some(_)) => {
- comps.push(Component::ParentDir);
- comps.extend(itb.map(|_| Component::ParentDir));
- comps.push(a);
- comps.extend(ita.by_ref());
- break;
- }
- }
- }
- Some(comps.iter().map(|c| c.as_os_str()).collect())
- }
-}
-
-
-fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String {
- let path = (config.get_install_prefix_lib_path)();
- let path = env::current_dir().unwrap().join(&path);
- // FIXME (#9639): This needs to handle non-utf8 paths
- path.to_str().expect("non-utf8 component in rpath").to_owned()
-}
-
-fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
- let mut set = FxHashSet::default();
- let mut minimized = Vec::new();
- for rpath in rpaths {
- if set.insert(rpath) {
- minimized.push(rpath.clone());
- }
- }
- minimized
-}
-
-#[cfg(all(unix, test))]
-mod tests {
- use super::{RPathConfig};
- use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
- use std::path::{Path, PathBuf};
-
- #[test]
- fn test_rpaths_to_flags() {
- let flags = rpaths_to_flags(&[
- "path1".to_string(),
- "path2".to_string()
- ]);
- assert_eq!(flags,
- ["-Wl,-rpath,path1",
- "-Wl,-rpath,path2"]);
- }
-
- #[test]
- fn test_minimize1() {
- let res = minimize_rpaths(&[
- "rpath1".to_string(),
- "rpath2".to_string(),
- "rpath1".to_string()
- ]);
- assert!(res == [
- "rpath1",
- "rpath2",
- ]);
- }
-
- #[test]
- fn test_minimize2() {
- let res = minimize_rpaths(&[
- "1a".to_string(),
- "2".to_string(),
- "2".to_string(),
- "1a".to_string(),
- "4a".to_string(),
- "1a".to_string(),
- "2".to_string(),
- "3".to_string(),
- "4a".to_string(),
- "3".to_string()
- ]);
- assert!(res == [
- "1a",
- "2",
- "4a",
- "3",
- ]);
- }
-
- #[test]
- fn test_rpath_relative() {
- if cfg!(target_os = "macos") {
- let config = &mut RPathConfig {
- used_crates: Vec::new(),
- has_rpath: true,
- is_like_osx: true,
- linker_is_gnu: false,
- out_filename: PathBuf::from("bin/rustc"),
- get_install_prefix_lib_path: &mut || panic!(),
- };
- let res = get_rpath_relative_to_output(config,
- Path::new("lib/libstd.so"));
- assert_eq!(res, "@loader_path/../lib");
- } else {
- let config = &mut RPathConfig {
- used_crates: Vec::new(),
- out_filename: PathBuf::from("bin/rustc"),
- get_install_prefix_lib_path: &mut || panic!(),
- has_rpath: true,
- is_like_osx: false,
- linker_is_gnu: true,
- };
- let res = get_rpath_relative_to_output(config,
- Path::new("lib/libstd.so"));
- assert_eq!(res, "$ORIGIN/../lib");
- }
- }
-
- #[test]
- fn test_xlinker() {
- let args = rpaths_to_flags(&[
- "a/normal/path".to_string(),
- "a,comma,path".to_string()
- ]);
-
- assert_eq!(args, vec![
- "-Wl,-rpath,a/normal/path".to_string(),
- "-Wl,-rpath".to_string(),
- "-Xlinker".to_string(),
- "a,comma,path".to_string()
- ]);
- }
-}
diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs
deleted file mode 100644
index f90bb89..0000000
--- a/src/librustc_codegen_llvm/back/wasm.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-use std::fs;
-use std::path::Path;
-use std::str;
-
-use serialize::leb128;
-
-// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
-const WASM_CUSTOM_SECTION_ID: u8 = 0;
-
-/// Adds or augment the existing `producers` section to encode information about
-/// the Rust compiler used to produce the wasm file.
-pub fn add_producer_section(
- path: &Path,
- rust_version: &str,
- rustc_version: &str,
-) {
- struct Field<'a> {
- name: &'a str,
- values: Vec<FieldValue<'a>>,
- }
-
- #[derive(Copy, Clone)]
- struct FieldValue<'a> {
- name: &'a str,
- version: &'a str,
- }
-
- let wasm = fs::read(path).expect("failed to read wasm output");
- let mut ret = WasmEncoder::new();
- ret.data.extend(&wasm[..8]);
-
- // skip the 8 byte wasm/version header
- let rustc_value = FieldValue {
- name: "rustc",
- version: rustc_version,
- };
- let rust_value = FieldValue {
- name: "Rust",
- version: rust_version,
- };
- let mut fields = Vec::new();
- let mut wrote_rustc = false;
- let mut wrote_rust = false;
-
- // Move all sections from the original wasm file to our output, skipping
- // everything except the producers section
- for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) {
- if id != WASM_CUSTOM_SECTION_ID {
- ret.byte(id);
- ret.bytes(raw);
- continue
- }
- let mut decoder = WasmDecoder::new(raw);
- if decoder.str() != "producers" {
- ret.byte(id);
- ret.bytes(raw);
- continue
- }
-
- // Read off the producers section into our fields outside the loop,
- // we'll re-encode the producers section when we're done (to handle an
- // entirely missing producers section as well).
- info!("rewriting existing producers section");
-
- for _ in 0..decoder.u32() {
- let name = decoder.str();
- let mut values = Vec::new();
- for _ in 0..decoder.u32() {
- let name = decoder.str();
- let version = decoder.str();
- values.push(FieldValue { name, version });
- }
-
- if name == "language" {
- values.push(rust_value);
- wrote_rust = true;
- } else if name == "processed-by" {
- values.push(rustc_value);
- wrote_rustc = true;
- }
- fields.push(Field { name, values });
- }
- }
-
- if !wrote_rust {
- fields.push(Field {
- name: "language",
- values: vec![rust_value],
- });
- }
- if !wrote_rustc {
- fields.push(Field {
- name: "processed-by",
- values: vec![rustc_value],
- });
- }
-
- // Append the producers section to the end of the wasm file.
- let mut section = WasmEncoder::new();
- section.str("producers");
- section.u32(fields.len() as u32);
- for field in fields {
- section.str(field.name);
- section.u32(field.values.len() as u32);
- for value in field.values {
- section.str(value.name);
- section.str(value.version);
- }
- }
- ret.byte(WASM_CUSTOM_SECTION_ID);
- ret.bytes(§ion.data);
-
- fs::write(path, &ret.data).expect("failed to write wasm output");
-}
-
-struct WasmSections<'a>(WasmDecoder<'a>);
-
-impl<'a> Iterator for WasmSections<'a> {
- type Item = (u8, &'a [u8]);
-
- fn next(&mut self) -> Option<(u8, &'a [u8])> {
- if self.0.data.is_empty() {
- return None
- }
-
- // see https://webassembly.github.io/spec/core/binary/modules.html#sections
- let id = self.0.byte();
- let section_len = self.0.u32();
- info!("new section {} / {} bytes", id, section_len);
- let section = self.0.skip(section_len as usize);
- Some((id, section))
- }
-}
-
-struct WasmDecoder<'a> {
- data: &'a [u8],
-}
-
-impl<'a> WasmDecoder<'a> {
- fn new(data: &'a [u8]) -> WasmDecoder<'a> {
- WasmDecoder { data }
- }
-
- fn byte(&mut self) -> u8 {
- self.skip(1)[0]
- }
-
- fn u32(&mut self) -> u32 {
- let (n, l1) = leb128::read_u32_leb128(self.data);
- self.data = &self.data[l1..];
- return n
- }
-
- fn skip(&mut self, amt: usize) -> &'a [u8] {
- let (data, rest) = self.data.split_at(amt);
- self.data = rest;
- data
- }
-
- fn str(&mut self) -> &'a str {
- let len = self.u32();
- str::from_utf8(self.skip(len as usize)).unwrap()
- }
-}
-
-struct WasmEncoder {
- data: Vec<u8>,
-}
-
-impl WasmEncoder {
- fn new() -> WasmEncoder {
- WasmEncoder { data: Vec::new() }
- }
-
- fn u32(&mut self, val: u32) {
- leb128::write_u32_leb128(&mut self.data, val);
- }
-
- fn byte(&mut self, val: u8) {
- self.data.push(val);
- }
-
- fn bytes(&mut self, val: &[u8]) {
- self.u32(val.len() as u32);
- self.data.extend_from_slice(val);
- }
-
- fn str(&mut self, val: &str) {
- self.bytes(val.as_bytes())
- }
-}
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index f0ed201..66ba958 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -1,5 +1,5 @@
use crate::attributes;
-use crate::back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
+use crate::back::bytecode;
use crate::back::lto::ThinBuffer;
use crate::base;
use crate::consts;
@@ -13,12 +13,11 @@
use rustc::hir::def_id::LOCAL_CRATE;
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler};
use rustc_codegen_ssa::traits::*;
-use rustc::session::config::{self, OutputType, Passes, Lto};
+use rustc::session::config::{self, OutputType, Passes, Lto, PgoGenerate};
use rustc::session::Session;
use rustc::ty::TyCtxt;
-use rustc_codegen_ssa::{ModuleCodegen, CompiledModule};
+use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, CompiledModule};
use rustc::util::common::time_ext;
-use rustc::util::profiling::ProfileCategory;
use rustc_fs_util::{path_to_c_string, link_or_copy};
use rustc_data_structures::small_c_str::SmallCStr;
use errors::{Handler, FatalError};
@@ -26,7 +25,7 @@
use std::ffi::{CString, CStr};
use std::fs;
use std::io::{self, Write};
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::str;
use std::sync::Arc;
use std::slice;
@@ -414,7 +413,7 @@
// Finally, run the actual optimization passes
{
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_function_passes");
+ let _timer = cgcx.profile_activity("LLVM_function_passes");
time_ext(config.time_passes,
None,
&format!("llvm function passes [{}]", module_name.unwrap()),
@@ -423,7 +422,7 @@
});
}
{
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_module_passes");
+ let _timer = cgcx.profile_activity("LLVM_module_passes");
time_ext(config.time_passes,
None,
&format!("llvm module passes [{}]", module_name.unwrap()),
@@ -445,7 +444,7 @@
config: &ModuleConfig)
-> Result<CompiledModule, FatalError>
{
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "codegen");
+ let _timer = cgcx.profile_activity("codegen");
{
let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
@@ -496,12 +495,12 @@
if write_bc || config.emit_bc_compressed || config.embed_bitcode {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_make_bitcode");
+ let _timer = cgcx.profile_activity("LLVM_make_bitcode");
let thin = ThinBuffer::new(llmod);
let data = thin.data();
if write_bc {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_bitcode");
+ let _timer = cgcx.profile_activity("LLVM_emit_bitcode");
if let Err(e) = fs::write(&bc_out, data) {
let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e);
diag_handler.err(&msg);
@@ -509,13 +508,12 @@
}
if config.embed_bitcode {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_embed_bitcode");
+ let _timer = cgcx.profile_activity("LLVM_embed_bitcode");
embed_bitcode(cgcx, llcx, llmod, Some(data));
}
if config.emit_bc_compressed {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
- "LLVM_compress_bitcode");
+ let _timer = cgcx.profile_activity("LLVM_compress_bitcode");
let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
let data = bytecode::encode(&module.name, data);
if let Err(e) = fs::write(&dst, data) {
@@ -530,7 +528,7 @@
time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
|| -> Result<(), FatalError> {
if config.emit_ir {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_ir");
+ let _timer = cgcx.profile_activity("LLVM_emit_ir");
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
let out_c = path_to_c_string(&out);
@@ -577,7 +575,7 @@
}
if config.emit_asm || asm_to_obj {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_asm");
+ let _timer = cgcx.profile_activity("LLVM_emit_asm");
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
// We can't use the same module for asm and binary output, because that triggers
@@ -595,13 +593,13 @@
}
if write_obj {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_obj");
+ let _timer = cgcx.profile_activity("LLVM_emit_obj");
with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
llvm::FileType::ObjectFile)
})?;
} else if asm_to_obj {
- let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_asm_to_obj");
+ let _timer = cgcx.profile_activity("LLVM_asm_to_obj");
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
run_assembler(cgcx, diag_handler, &assembly, &obj_out);
@@ -708,10 +706,20 @@
.unwrap_or(llvm::CodeGenOptSizeNone);
let inline_threshold = config.inline_threshold;
- let pgo_gen_path = config.pgo_gen.as_ref().map(|s| {
- let s = if s.is_empty() { "default_%m.profraw" } else { s };
- CString::new(s.as_bytes()).unwrap()
- });
+ let pgo_gen_path = match config.pgo_gen {
+ PgoGenerate::Enabled(ref opt_dir_path) => {
+ let path = if let Some(dir_path) = opt_dir_path {
+ dir_path.join("default_%m.profraw")
+ } else {
+ PathBuf::from("default_%m.profraw")
+ };
+
+ Some(CString::new(format!("{}", path.display())).unwrap())
+ }
+ PgoGenerate::Disabled => {
+ None
+ }
+ };
let pgo_use_path = if config.pgo_use.is_empty() {
None
@@ -787,14 +795,15 @@
return
}
// The x86 ABI seems to require that leading underscores are added to symbol
- // names, so we need an extra underscore on 32-bit. There's also a leading
+ // names, so we need an extra underscore on x86. There's also a leading
// '\x01' here which disables LLVM's symbol mangling (e.g., no extra
// underscores added in front).
- let prefix = if cgcx.target_pointer_width == "32" {
+ let prefix = if cgcx.target_arch == "x86" {
"\x01__imp__"
} else {
"\x01__imp_"
};
+
unsafe {
let i8p_ty = Type::i8p_llcx(llcx);
let globals = base::iter_globals(llmod)
@@ -802,14 +811,23 @@
llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage &&
llvm::LLVMIsDeclaration(val) == 0
})
- .map(move |val| {
+ .filter_map(|val| {
+ // Exclude some symbols that we know are not Rust symbols.
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
+ if ignored(name.to_bytes()) {
+ None
+ } else {
+ Some((val, name))
+ }
+ })
+ .map(move |(val, name)| {
let mut imp_name = prefix.as_bytes().to_vec();
imp_name.extend(name.to_bytes());
let imp_name = CString::new(imp_name).unwrap();
(imp_name, val)
})
.collect::<Vec<_>>();
+
for (imp_name, val) in globals {
let imp = llvm::LLVMAddGlobal(llmod,
i8p_ty,
@@ -818,4 +836,10 @@
llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
}
}
+
+ // Use this function to exclude certain symbols from `__imp` generation.
+ fn ignored(symbol_name: &[u8]) -> bool {
+ // These are symbols generated by LLVM's profiling instrumentation
+ symbol_name.starts_with(b"__llvm_profile_")
+ }
}
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 7ea5e91..9077e89 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -28,7 +28,7 @@
use rustc::middle::cstore::{EncodedMetadata};
use rustc::ty::TyCtxt;
use rustc::middle::exported_symbols;
-use rustc::session::config::{self, DebugInfo};
+use rustc::session::config::DebugInfo;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_data_structures::small_c_str::SmallCStr;
@@ -42,47 +42,16 @@
use crate::value::Value;
-
-pub fn write_metadata<'a, 'gcx>(
+pub fn write_compressed_metadata<'a, 'gcx>(
tcx: TyCtxt<'a, 'gcx, 'gcx>,
+ metadata: &EncodedMetadata,
llvm_module: &mut ModuleLlvm
-) -> EncodedMetadata {
+) {
use std::io::Write;
use flate2::Compression;
use flate2::write::DeflateEncoder;
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
-
- #[derive(PartialEq, Eq, PartialOrd, Ord)]
- enum MetadataKind {
- None,
- Uncompressed,
- Compressed
- }
-
- let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
- match *ty {
- config::CrateType::Executable |
- config::CrateType::Staticlib |
- config::CrateType::Cdylib => MetadataKind::None,
-
- config::CrateType::Rlib => MetadataKind::Uncompressed,
-
- config::CrateType::Dylib |
- config::CrateType::ProcMacro => MetadataKind::Compressed,
- }
- }).max().unwrap_or(MetadataKind::None);
-
- if kind == MetadataKind::None {
- return EncodedMetadata::new();
- }
-
- let metadata = tcx.encode_metadata();
- if kind == MetadataKind::Uncompressed {
- return metadata;
- }
-
- assert!(kind == MetadataKind::Compressed);
let mut compressed = tcx.metadata_encoding_version();
DeflateEncoder::new(&mut compressed, Compression::fast())
.write_all(&metadata.raw_data).unwrap();
@@ -107,7 +76,6 @@
let directive = CString::new(directive).unwrap();
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
}
- return metadata;
}
pub struct ValueIter<'ll> {
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 123fda1..48808ee 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -18,6 +18,7 @@
use rustc_codegen_ssa::base::to_immediate;
use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef};
use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
use std::ops::{Deref, Range};
use std::ptr;
@@ -66,6 +67,18 @@
}
}
+impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.cx.param_env()
+ }
+}
+
+impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.cx.target_spec()
+ }
+}
+
impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> {
type Ty = Ty<'tcx>;
type TyLayout = TyLayout<'tcx>;
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 9554e54..b9fd962 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -322,7 +322,7 @@
self.get_fn(fn_instance)
}
Some(AllocKind::Static(def_id)) => {
- assert!(self.tcx.is_static(def_id).is_some());
+ assert!(self.tcx.is_static(def_id));
self.get_static(def_id)
}
None => bug!("missing allocation {:?}", ptr.alloc_id),
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 8c83e9e..5f47108 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -14,6 +14,7 @@
use rustc::hir::Node;
use syntax_pos::Span;
use rustc_target::abi::HasDataLayout;
+use syntax::symbol::sym;
use syntax_pos::symbol::LocalInternedString;
use rustc::ty::{self, Ty};
use rustc_codegen_ssa::traits::*;
@@ -248,7 +249,7 @@
debug!("get_static: sym={} attrs={:?}", sym, attrs);
for attr in attrs {
- if attr.check_name("thread_local") {
+ if attr.check_name(sym::thread_local) {
llvm::set_thread_local_mode(g, self.tls_model);
}
}
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index f6956bd..7bf8f70 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -8,7 +8,6 @@
use crate::monomorphize::partitioning::CodegenUnit;
use crate::type_::Type;
-use crate::type_of::PointeeInfo;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n;
@@ -16,7 +15,9 @@
use rustc::mir::mono::Stats;
use rustc::session::config::{self, DebugInfo};
use rustc::session::Session;
-use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout, VariantIdx};
+use rustc::ty::layout::{
+ LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv
+};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::FxHashMap;
use rustc_target::spec::{HasTargetSpec, Target};
@@ -862,3 +863,9 @@
})
}
}
+
+impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ ty::ParamEnv::reveal_all()
+ }
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs
index 91496ff..04c9e93 100644
--- a/src/librustc_codegen_llvm/debuginfo/gdb.rs
+++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs
@@ -9,6 +9,7 @@
use rustc_codegen_ssa::traits::*;
use syntax::attr;
+use syntax::symbol::sym;
/// Inserts a side-effect free instruction sequence that makes sure that the
@@ -66,8 +67,7 @@
pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
let omit_gdb_pretty_printer_section =
- attr::contains_name(&cx.tcx.hir().krate_attrs(),
- "omit_gdb_pretty_printer_section");
+ attr::contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
!omit_gdb_pretty_printer_section &&
cx.sess().opts.debuginfo != DebugInfo::None &&
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 94d520e..13590fa 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -22,14 +22,16 @@
use rustc::hir::def::CtorKind;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::ich::NodeIdHashingMode;
+use rustc::mir::Field;
+use rustc::mir::GeneratorLayout;
use rustc::mir::interpret::truncate;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc::ty::Instance;
use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc::ty::layout::{self, Align, Integer, IntegerExt, LayoutOf,
- PrimitiveExt, Size, TyLayout};
+ PrimitiveExt, Size, TyLayout, VariantIdx};
use rustc::ty::subst::UnpackedKind;
-use rustc::session::config;
+use rustc::session::config::{self, DebugInfo};
use rustc::util::nodemap::FxHashMap;
use rustc_fs_util::path_to_c_string;
use rustc_data_structures::small_c_str::SmallCStr;
@@ -375,7 +377,7 @@
return_if_metadata_created_in_meantime!(cx, unique_type_id);
- let slice_type_name = compute_debuginfo_type_name(cx, slice_ptr_type, true);
+ let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true);
let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
@@ -478,7 +480,7 @@
let trait_object_type = trait_object_type.unwrap_or(trait_type);
let trait_type_name =
- compute_debuginfo_type_name(cx, trait_object_type, false);
+ compute_debuginfo_type_name(cx.tcx, trait_object_type, false);
let file_metadata = unknown_file_metadata(cx);
@@ -690,14 +692,15 @@
usage_site_span).finalize(cx)
}
ty::Generator(def_id, substs, _) => {
- let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| {
+ let upvar_tys : Vec<_> = substs.prefix_tys(def_id, cx.tcx).map(|t| {
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)
}).collect();
- prepare_tuple_metadata(cx,
- t,
- &upvar_tys,
- unique_type_id,
- usage_site_span).finalize(cx)
+ prepare_enum_metadata(cx,
+ t,
+ def_id,
+ unique_type_id,
+ usage_site_span,
+ upvar_tys).finalize(cx)
}
ty::Adt(def, ..) => match def.adt_kind() {
AdtKind::Struct => {
@@ -717,13 +720,15 @@
t,
def.did,
unique_type_id,
- usage_site_span).finalize(cx)
+ usage_site_span,
+ vec![]).finalize(cx)
}
},
ty::Tuple(ref elements) => {
+ let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect();
prepare_tuple_metadata(cx,
t,
- &elements[..],
+ &tys,
unique_type_id,
usage_site_span).finalize(cx)
}
@@ -782,26 +787,30 @@
file_name,
defining_crate);
- let directory = if defining_crate == LOCAL_CRATE {
- &cx.sess().working_dir.0
+ let file_name = &file_name.to_string();
+ let file_name_symbol = Symbol::intern(file_name);
+ if defining_crate == LOCAL_CRATE {
+ let directory = &cx.sess().working_dir.0.to_string_lossy();
+ file_metadata_raw(cx, file_name, Some(file_name_symbol),
+ directory, Some(Symbol::intern(directory)))
} else {
// If the path comes from an upstream crate we assume it has been made
// independent of the compiler's working directory one way or another.
- Path::new("")
- };
-
- file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy())
+ file_metadata_raw(cx, file_name, Some(file_name_symbol), "", None)
+ }
}
pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
- file_metadata_raw(cx, "<unknown>", "")
+ file_metadata_raw(cx, "<unknown>", None, "", None)
}
fn file_metadata_raw(cx: &CodegenCx<'ll, '_>,
file_name: &str,
- directory: &str)
+ file_name_symbol: Option<Symbol>,
+ directory: &str,
+ directory_symbol: Option<Symbol>)
-> &'ll DIFile {
- let key = (Symbol::intern(file_name), Symbol::intern(directory));
+ let key = (file_name_symbol, directory_symbol);
if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) {
return *file_metadata;
@@ -865,7 +874,7 @@
) -> &'ll DIType {
debug!("foreign_type_metadata: {:?}", t);
- let name = compute_debuginfo_type_name(cx, t, false);
+ let name = compute_debuginfo_type_name(cx.tcx, t, false);
create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA)
}
@@ -875,7 +884,7 @@
pointee_type_metadata: &'ll DIType,
) -> &'ll DIType {
let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
- let name = compute_debuginfo_type_name(cx, pointer_type, false);
+ let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false);
let name = SmallCStr::new(&name);
unsafe {
llvm::LLVMRustDIBuilderCreatePointerType(
@@ -916,7 +925,26 @@
let producer = CString::new(producer).unwrap();
let flags = "\0";
let split_name = "\0";
- let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
+
+ // FIXME(#60020):
+ //
+ // This should actually be
+ //
+ // ```
+ // let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
+ // ```
+ //
+ // that is, we should set LLVM's emission kind to `LineTablesOnly` if
+ // we are compiling with "limited" debuginfo. However, some of the
+ // existing tools relied on slightly more debuginfo being generated than
+ // would be the case with `LineTablesOnly`, and we did not want to break
+ // these tools in a "drive-by fix", without a good idea or plan about
+ // what limited debuginfo should exactly look like. So for now we keep
+ // the emission kind as `FullDebug`.
+ //
+ // See https://github.com/rust-lang/rust/issues/60020 for details.
+ let kind = DebugEmissionKind::FullDebug;
+ assert!(tcx.sess.opts.debuginfo != DebugInfo::None);
unsafe {
let file_metadata = llvm::LLVMRustDIBuilderCreateFile(
@@ -994,6 +1022,31 @@
discriminant: Option<u64>,
}
+impl<'ll> MemberDescription<'ll> {
+ fn into_metadata(self,
+ cx: &CodegenCx<'ll, '_>,
+ composite_type_metadata: &'ll DIScope) -> &'ll DIType {
+ let member_name = CString::new(self.name).unwrap();
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateVariantMemberType(
+ DIB(cx),
+ composite_type_metadata,
+ member_name.as_ptr(),
+ unknown_file_metadata(cx),
+ UNKNOWN_LINE_NUMBER,
+ self.size.bits(),
+ self.align.bits() as u32,
+ self.offset.bits(),
+ match self.discriminant {
+ None => None,
+ Some(value) => Some(cx.const_u64(value)),
+ },
+ self.flags,
+ self.type_metadata)
+ }
+ }
+}
+
// A factory for MemberDescriptions. It produces a list of member descriptions
// for some record-like type. MemberDescriptionFactories are used to defer the
// creation of type member descriptions in order to break cycles arising from
@@ -1071,7 +1124,7 @@
unique_type_id: UniqueTypeId,
span: Span,
) -> RecursiveTypeDescription<'ll, 'tcx> {
- let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
+ let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
let (struct_def_id, variant) = match struct_type.sty {
ty::Adt(def, _) => (def.did, def.non_enum_variant()),
@@ -1137,7 +1190,7 @@
unique_type_id: UniqueTypeId,
span: Span,
) -> RecursiveTypeDescription<'ll, 'tcx> {
- let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
+ let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
let struct_stub = create_struct_stub(cx,
tuple_type,
@@ -1193,7 +1246,7 @@
unique_type_id: UniqueTypeId,
span: Span,
) -> RecursiveTypeDescription<'ll, 'tcx> {
- let union_name = compute_debuginfo_type_name(cx, union_type, false);
+ let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
let (union_def_id, variant) = match union_type.sty {
ty::Adt(def, _) => (def.did, def.non_enum_variant()),
@@ -1260,7 +1313,16 @@
impl EnumMemberDescriptionFactory<'ll, 'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
-> Vec<MemberDescription<'ll>> {
- let adt = &self.enum_type.ty_adt_def().unwrap();
+ let variant_info_for = |index: VariantIdx| {
+ match &self.enum_type.sty {
+ ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
+ ty::Generator(def_id, substs, _) => {
+ let generator_layout = cx.tcx.generator_layout(*def_id);
+ VariantInfo::Generator(*substs, generator_layout, index)
+ }
+ _ => bug!(),
+ }
+ };
// This will always find the metadata in the type map.
let fallback = use_enum_fallback(cx);
@@ -1271,12 +1333,18 @@
};
match self.layout.variants {
- layout::Variants::Single { .. } if adt.variants.is_empty() => vec![],
layout::Variants::Single { index } => {
+ if let ty::Adt(adt, _) = &self.enum_type.sty {
+ if adt.variants.is_empty() {
+ return vec![];
+ }
+ }
+
+ let variant_info = variant_info_for(index);
let (variant_type_metadata, member_description_factory) =
describe_enum_variant(cx,
self.layout,
- &adt.variants[index],
+ variant_info,
NoDiscriminant,
self_metadata,
self.span);
@@ -1293,7 +1361,7 @@
name: if fallback {
String::new()
} else {
- adt.variants[index].ident.as_str().to_string()
+ variant_info.variant_name()
},
type_metadata: variant_type_metadata,
offset: Size::ZERO,
@@ -1306,22 +1374,26 @@
}
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
+ discr_index,
ref variants,
..
} => {
let discriminant_info = if fallback {
- RegularDiscriminant(self.discriminant_type_metadata
- .expect(""))
+ RegularDiscriminant {
+ discr_field: Field::from(discr_index),
+ discr_type_metadata: self.discriminant_type_metadata.unwrap()
+ }
} else {
// This doesn't matter in this case.
NoDiscriminant
};
variants.iter_enumerated().map(|(i, _)| {
let variant = self.layout.for_variant(cx, i);
+ let variant_info = variant_info_for(i);
let (variant_type_metadata, member_desc_factory) =
describe_enum_variant(cx,
variant,
- &adt.variants[i],
+ variant_info,
discriminant_info,
self_metadata,
self.span);
@@ -1333,20 +1405,21 @@
self.enum_type,
variant_type_metadata,
member_descriptions);
+
MemberDescription {
name: if fallback {
String::new()
} else {
- adt.variants[i].ident.as_str().to_string()
+ variant_info.variant_name()
},
type_metadata: variant_type_metadata,
offset: Size::ZERO,
size: self.layout.size,
align: self.layout.align.abi,
flags: DIFlags::FlagZero,
- discriminant: Some(self.layout.ty.ty_adt_def().unwrap()
- .discriminant_for_variant(cx.tcx, i)
- .val as u64),
+ discriminant: Some(
+ self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val as u64
+ ),
}
}).collect()
}
@@ -1358,6 +1431,7 @@
},
ref discr,
ref variants,
+ discr_index,
} => {
if fallback {
let variant = self.layout.for_variant(cx, dataful_variant);
@@ -1365,7 +1439,7 @@
let (variant_type_metadata, member_description_factory) =
describe_enum_variant(cx,
variant,
- &adt.variants[dataful_variant],
+ variant_info_for(dataful_variant),
OptimizedDiscriminant,
self.containing_scope,
self.span);
@@ -1403,9 +1477,11 @@
}
compute_field_path(cx, &mut name,
self.layout,
- self.layout.fields.offset(0),
- self.layout.field(cx, 0).size);
- name.push_str(&adt.variants[*niche_variants.start()].ident.as_str());
+ self.layout.fields.offset(discr_index),
+ self.layout.field(cx, discr_index).size);
+ variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| {
+ name.push_str(variant_name);
+ });
// Create the (singleton) list of descriptions of union members.
vec![
@@ -1422,10 +1498,11 @@
} else {
variants.iter_enumerated().map(|(i, _)| {
let variant = self.layout.for_variant(cx, i);
+ let variant_info = variant_info_for(i);
let (variant_type_metadata, member_desc_factory) =
describe_enum_variant(cx,
variant,
- &adt.variants[i],
+ variant_info,
OptimizedDiscriminant,
self_metadata,
self.span);
@@ -1453,7 +1530,7 @@
};
MemberDescription {
- name: adt.variants[i].ident.as_str().to_string(),
+ name: variant_info.variant_name(),
type_metadata: variant_type_metadata,
offset: Size::ZERO,
size: self.layout.size,
@@ -1486,6 +1563,8 @@
name: name.to_string(),
type_metadata: if use_enum_fallback(cx) {
match self.discriminant_type_metadata {
+ // Discriminant is always the first field of our variant
+ // when using the enum fallback.
Some(metadata) if i == 0 => metadata,
_ => type_metadata(cx, ty, self.span)
}
@@ -1504,11 +1583,54 @@
#[derive(Copy, Clone)]
enum EnumDiscriminantInfo<'ll> {
- RegularDiscriminant(&'ll DIType),
+ RegularDiscriminant{ discr_field: Field, discr_type_metadata: &'ll DIType },
OptimizedDiscriminant,
NoDiscriminant
}
+#[derive(Copy, Clone)]
+enum VariantInfo<'tcx> {
+ Adt(&'tcx ty::VariantDef),
+ Generator(ty::GeneratorSubsts<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx),
+}
+
+impl<'tcx> VariantInfo<'tcx> {
+ fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
+ match self {
+ VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
+ VariantInfo::Generator(substs, _, variant_index) =>
+ f(&substs.variant_name(*variant_index)),
+ }
+ }
+
+ fn variant_name(&self) -> String {
+ match self {
+ VariantInfo::Adt(variant) => variant.ident.to_string(),
+ VariantInfo::Generator(_, _, variant_index) => {
+ // Since GDB currently prints out the raw discriminant along
+ // with every variant, make each variant name be just the value
+ // of the discriminant. The struct name for the variant includes
+ // the actual variant description.
+ format!("{}", variant_index.as_usize()).to_string()
+ }
+ }
+ }
+
+ fn field_name(&self, i: usize) -> String {
+ let field_name = match self {
+ VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn =>
+ Some(variant.fields[i].ident.to_string()),
+ VariantInfo::Generator(_, generator_layout, variant_index) => {
+ let field = generator_layout.variant_fields[*variant_index][i.into()];
+ let decl = &generator_layout.__local_debuginfo_codegen_only_do_not_use[field];
+ decl.name.map(|name| name.to_string())
+ }
+ _ => None,
+ };
+ field_name.unwrap_or_else(|| format!("__{}", i))
+ }
+}
+
// Returns a tuple of (1) type_metadata_stub of the variant, (2) a
// MemberDescriptionFactory for producing the descriptions of the
// fields of the variant. This is a rudimentary version of a full
@@ -1516,34 +1638,37 @@
fn describe_enum_variant(
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyLayout<'tcx>,
- variant: &'tcx ty::VariantDef,
+ variant: VariantInfo<'tcx>,
discriminant_info: EnumDiscriminantInfo<'ll>,
containing_scope: &'ll DIScope,
span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
- let variant_name = variant.ident.as_str();
- let unique_type_id = debug_context(cx).type_map
- .borrow_mut()
- .get_unique_type_id_of_enum_variant(
- cx,
- layout.ty,
- &variant_name);
-
- let metadata_stub = create_struct_stub(cx,
- layout.ty,
- &variant_name,
- unique_type_id,
- Some(containing_scope));
+ let metadata_stub = variant.map_struct_name(|variant_name| {
+ let unique_type_id = debug_context(cx).type_map
+ .borrow_mut()
+ .get_unique_type_id_of_enum_variant(
+ cx,
+ layout.ty,
+ &variant_name);
+ create_struct_stub(cx,
+ layout.ty,
+ &variant_name,
+ unique_type_id,
+ Some(containing_scope))
+ });
// Build an array of (field name, field type) pairs to be captured in the factory closure.
let (offsets, args) = if use_enum_fallback(cx) {
// If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info {
- RegularDiscriminant(_) => {
+ RegularDiscriminant { discr_field, .. } => {
// We have the layout of an enum variant, we need the layout of the outer enum
let enum_layout = cx.layout_of(layout.ty);
- (Some(enum_layout.fields.offset(0)),
- Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty)))
+ let offset = enum_layout.fields.offset(discr_field.as_usize());
+ let args = (
+ "RUST$ENUM$DISR".to_owned(),
+ enum_layout.field(cx, discr_field.as_usize()).ty);
+ (Some(offset), Some(args))
}
_ => (None, None),
};
@@ -1552,12 +1677,7 @@
layout.fields.offset(i)
})).collect(),
discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
- let name = if variant.ctor_kind == CtorKind::Fn {
- format!("__{}", i)
- } else {
- variant.fields[i].ident.to_string()
- };
- (name, layout.field(cx, i).ty)
+ (variant.field_name(i), layout.field(cx, i).ty)
})).collect()
)
} else {
@@ -1566,12 +1686,7 @@
layout.fields.offset(i)
}).collect(),
(0..layout.fields.count()).map(|i| {
- let name = if variant.ctor_kind == CtorKind::Fn {
- format!("__{}", i)
- } else {
- variant.fields[i].ident.to_string()
- };
- (name, layout.field(cx, i).ty)
+ (variant.field_name(i), layout.field(cx, i).ty)
}).collect()
)
};
@@ -1581,8 +1696,8 @@
offsets,
args,
discriminant_type_metadata: match discriminant_info {
- RegularDiscriminant(discriminant_type_metadata) => {
- Some(discriminant_type_metadata)
+ RegularDiscriminant { discr_type_metadata, .. } => {
+ Some(discr_type_metadata)
}
_ => None
},
@@ -1598,8 +1713,9 @@
enum_def_id: DefId,
unique_type_id: UniqueTypeId,
span: Span,
+ outer_field_tys: Vec<Ty<'tcx>>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
- let enum_name = compute_debuginfo_type_name(cx, enum_type, false);
+ let enum_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
let containing_scope = get_namespace_for_item(cx, enum_def_id);
// FIXME: This should emit actual file metadata for the enum, but we
@@ -1611,20 +1727,36 @@
let file_metadata = unknown_file_metadata(cx);
let discriminant_type_metadata = |discr: layout::Primitive| {
- let def = enum_type.ty_adt_def().unwrap();
- let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
- .zip(&def.variants)
- .map(|((_, discr), v)| {
- let name = SmallCStr::new(&v.ident.as_str());
- unsafe {
- Some(llvm::LLVMRustDIBuilderCreateEnumerator(
- DIB(cx),
- name.as_ptr(),
- // FIXME: what if enumeration has i128 discriminant?
- discr.val as u64))
- }
- })
- .collect();
+ let enumerators_metadata: Vec<_> = match enum_type.sty {
+ ty::Adt(def, _) => def
+ .discriminants(cx.tcx)
+ .zip(&def.variants)
+ .map(|((_, discr), v)| {
+ let name = SmallCStr::new(&v.ident.as_str());
+ unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateEnumerator(
+ DIB(cx),
+ name.as_ptr(),
+ // FIXME: what if enumeration has i128 discriminant?
+ discr.val as u64))
+ }
+ })
+ .collect(),
+ ty::Generator(_, substs, _) => substs
+ .variant_range(enum_def_id, cx.tcx)
+ .map(|variant_index| {
+ let name = SmallCStr::new(&substs.variant_name(variant_index));
+ unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateEnumerator(
+ DIB(cx),
+ name.as_ptr(),
+ // FIXME: what if enumeration has i128 discriminant?
+ variant_index.as_usize() as u64))
+ }
+ })
+ .collect(),
+ _ => bug!(),
+ };
let disr_type_key = (enum_def_id, discr);
let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types
@@ -1637,14 +1769,18 @@
(discr.size(cx), discr.align(cx));
let discriminant_base_type_metadata =
type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP);
- let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str();
- let name = SmallCStr::new(&discriminant_name);
+ let discriminant_name = match enum_type.sty {
+ ty::Adt(..) => SmallCStr::new(&cx.tcx.item_name(enum_def_id).as_str()),
+ ty::Generator(..) => SmallCStr::new(&enum_name),
+ _ => bug!(),
+ };
+
let discriminant_type_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateEnumerationType(
DIB(cx),
containing_scope,
- name.as_ptr(),
+ discriminant_name.as_ptr(),
file_metadata,
UNKNOWN_LINE_NUMBER,
discriminant_size.bits(),
@@ -1725,6 +1861,11 @@
);
}
+ let discriminator_name = match &enum_type.sty {
+ ty::Generator(..) => Some(SmallCStr::new(&"__state")),
+ _ => None,
+ };
+ let discriminator_name = discriminator_name.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut());
let discriminator_metadata = match layout.variants {
// A single-variant enum has no discriminant.
layout::Variants::Single { .. } => None,
@@ -1732,6 +1873,7 @@
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche { .. },
ref discr,
+ discr_index,
..
} => {
// Find the integer type of the correct size.
@@ -1750,12 +1892,12 @@
Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
containing_scope,
- ptr::null_mut(),
+ discriminator_name,
file_metadata,
UNKNOWN_LINE_NUMBER,
size.bits(),
align.abi.bits() as u32,
- layout.fields.offset(0).bits(),
+ layout.fields.offset(discr_index).bits(),
DIFlags::FlagArtificial,
discr_metadata))
}
@@ -1764,6 +1906,7 @@
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
ref discr,
+ discr_index,
..
} => {
let discr_type = discr.value.to_ty(cx.tcx);
@@ -1774,18 +1917,34 @@
Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
containing_scope,
- ptr::null_mut(),
+ discriminator_name,
file_metadata,
UNKNOWN_LINE_NUMBER,
size.bits(),
align.bits() as u32,
- layout.fields.offset(0).bits(),
+ layout.fields.offset(discr_index).bits(),
DIFlags::FlagArtificial,
discr_metadata))
}
},
};
+ let mut outer_fields = match layout.variants {
+ layout::Variants::Single { .. } => vec![],
+ layout::Variants::Multiple { .. } => {
+ let tuple_mdf = TupleMemberDescriptionFactory {
+ ty: enum_type,
+ component_types: outer_field_tys,
+ span
+ };
+ tuple_mdf
+ .create_member_descriptions(cx)
+ .into_iter()
+ .map(|desc| Some(desc.into_metadata(cx, containing_scope)))
+ .collect()
+ }
+ };
+
let variant_part_unique_type_id_str = SmallCStr::new(
debug_context(cx).type_map
.borrow_mut()
@@ -1806,9 +1965,10 @@
empty_array,
variant_part_unique_type_id_str.as_ptr())
};
+ outer_fields.push(Some(variant_part));
// The variant part must be wrapped in a struct according to DWARF.
- let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
+ let type_array = create_DIArray(DIB(cx), &outer_fields);
let struct_wrapper = unsafe {
llvm::LLVMRustDIBuilderCreateStructType(
DIB(cx),
@@ -1840,12 +2000,6 @@
span,
}),
);
-
- fn get_enum_discriminant_name(cx: &CodegenCx<'_, '_>,
- def_id: DefId)
- -> InternedString {
- cx.tcx.item_name(def_id)
- }
}
/// Creates debug information for a composite type, that is, anything that
@@ -1903,26 +2057,7 @@
let member_metadata: Vec<_> = member_descriptions
.into_iter()
- .map(|member_description| {
- let member_name = CString::new(member_description.name).unwrap();
- unsafe {
- Some(llvm::LLVMRustDIBuilderCreateVariantMemberType(
- DIB(cx),
- composite_type_metadata,
- member_name.as_ptr(),
- unknown_file_metadata(cx),
- UNKNOWN_LINE_NUMBER,
- member_description.size.bits(),
- member_description.align.bits() as u32,
- member_description.offset.bits(),
- match member_description.discriminant {
- None => None,
- Some(value) => Some(cx.const_u64(value)),
- },
- member_description.flags,
- member_description.type_metadata))
- }
- })
+ .map(|desc| Some(desc.into_metadata(cx, composite_type_metadata)))
.collect();
let type_params = compute_type_parameters(cx, composite_type);
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index 57e4ac0..f3070a0 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -29,7 +29,7 @@
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess,
- VariableKind, FunctionDebugContextData};
+ VariableKind, FunctionDebugContextData, type_names};
use libc::c_uint;
use std::cell::RefCell;
@@ -44,7 +44,6 @@
pub mod gdb;
mod utils;
mod namespace;
-mod type_names;
pub mod metadata;
mod create_scope_map;
mod source_loc;
@@ -64,7 +63,7 @@
llcontext: &'a llvm::Context,
llmod: &'a llvm::Module,
builder: &'a mut DIBuilder<'a>,
- created_files: RefCell<FxHashMap<(Symbol, Symbol), &'a DIFile>>,
+ created_files: RefCell<FxHashMap<(Option<Symbol>, Option<Symbol>), &'a DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Primitive), &'a DIType>>,
type_map: RefCell<TypeMap<'a, 'tcx>>,
@@ -393,7 +392,7 @@
if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
signature.extend(
args.iter().map(|argument_type| {
- Some(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP))
+ Some(type_metadata(cx, argument_type.expect_ty(), syntax_pos::DUMMY_SP))
})
);
}
@@ -422,7 +421,7 @@
let actual_type =
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type);
// Add actual type name to <...> clause of function name
- let actual_type_name = compute_debuginfo_type_name(cx,
+ let actual_type_name = compute_debuginfo_type_name(cx.tcx(),
actual_type,
true);
name_to_append_suffix_to.push_str(&actual_type_name[..]);
@@ -543,7 +542,7 @@
finalize(self)
}
- fn debuginfo_upvar_decls_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] {
+ fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] {
unsafe {
[llvm::LLVMRustDIBuilderCreateOpDeref(),
llvm::LLVMRustDIBuilderCreateOpPlusUconst(),
diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs
deleted file mode 100644
index eff7cd1..0000000
--- a/src/librustc_codegen_llvm/debuginfo/type_names.rs
+++ /dev/null
@@ -1,256 +0,0 @@
-// Type Names for Debug Info.
-
-use crate::common::CodegenCx;
-use rustc::hir::def_id::DefId;
-use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, Ty};
-use rustc_codegen_ssa::traits::*;
-use rustc_data_structures::fx::FxHashSet;
-
-use rustc::hir;
-
-// Compute the name of the type as it should be stored in debuginfo. Does not do
-// any caching, i.e., calling the function twice with the same type will also do
-// the work twice. The `qualified` parameter only affects the first level of the
-// type name, further levels (i.e., type parameters) are always fully qualified.
-pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- t: Ty<'tcx>,
- qualified: bool)
- -> String {
- let mut result = String::with_capacity(64);
- let mut visited = FxHashSet::default();
- push_debuginfo_type_name(cx, t, qualified, &mut result, &mut visited);
- result
-}
-
-// Pushes the name of the type as it should be stored in debuginfo on the
-// `output` String. See also compute_debuginfo_type_name().
-pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- t: Ty<'tcx>,
- qualified: bool,
- output: &mut String,
- visited: &mut FxHashSet<Ty<'tcx>>) {
-
- // When targeting MSVC, emit C++ style type names for compatibility with
- // .natvis visualizers (and perhaps other existing native debuggers?)
- let cpp_like_names = cx.sess().target.target.options.is_like_msvc;
-
- match t.sty {
- ty::Bool => output.push_str("bool"),
- ty::Char => output.push_str("char"),
- ty::Str => output.push_str("str"),
- ty::Never => output.push_str("!"),
- ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()),
- ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
- ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()),
- ty::Foreign(def_id) => push_item_name(cx, def_id, qualified, output),
- ty::Adt(def, substs) => {
- push_item_name(cx, def.did, qualified, output);
- push_type_params(cx, substs, output, visited);
- },
- ty::Tuple(component_types) => {
- output.push('(');
- for &component_type in component_types {
- push_debuginfo_type_name(cx, component_type, true, output, visited);
- output.push_str(", ");
- }
- if !component_types.is_empty() {
- output.pop();
- output.pop();
- }
- output.push(')');
- },
- ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
- if !cpp_like_names {
- output.push('*');
- }
- match mutbl {
- hir::MutImmutable => output.push_str("const "),
- hir::MutMutable => output.push_str("mut "),
- }
-
- push_debuginfo_type_name(cx, inner_type, true, output, visited);
-
- if cpp_like_names {
- output.push('*');
- }
- },
- ty::Ref(_, inner_type, mutbl) => {
- if !cpp_like_names {
- output.push('&');
- }
- if mutbl == hir::MutMutable {
- output.push_str("mut ");
- }
-
- push_debuginfo_type_name(cx, inner_type, true, output, visited);
-
- if cpp_like_names {
- output.push('*');
- }
- },
- ty::Array(inner_type, len) => {
- output.push('[');
- push_debuginfo_type_name(cx, inner_type, true, output, visited);
- output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
- output.push(']');
- },
- ty::Slice(inner_type) => {
- if cpp_like_names {
- output.push_str("slice<");
- } else {
- output.push('[');
- }
-
- push_debuginfo_type_name(cx, inner_type, true, output, visited);
-
- if cpp_like_names {
- output.push('>');
- } else {
- output.push(']');
- }
- },
- ty::Dynamic(ref trait_data, ..) => {
- if let Some(principal) = trait_data.principal() {
- let principal = cx.tcx.normalize_erasing_late_bound_regions(
- ty::ParamEnv::reveal_all(),
- &principal,
- );
- push_item_name(cx, principal.def_id, false, output);
- push_type_params(cx, principal.substs, output, visited);
- } else {
- output.push_str("dyn '_");
- }
- },
- ty::FnDef(..) | ty::FnPtr(_) => {
- // We've encountered a weird 'recursive type'
- // Currently, the only way to generate such a type
- // is by using 'impl trait':
- //
- // fn foo() -> impl Copy { foo }
- //
- // There's not really a sensible name we can generate,
- // since we don't include 'impl trait' types (e.g. ty::Opaque)
- // in the output
- //
- // Since we need to generate *something*, we just
- // use a dummy string that should make it clear
- // that something unusual is going on
- if !visited.insert(t) {
- output.push_str("<recursive_type>");
- return;
- }
-
-
- let sig = t.fn_sig(cx.tcx);
- if sig.unsafety() == hir::Unsafety::Unsafe {
- output.push_str("unsafe ");
- }
-
- let abi = sig.abi();
- if abi != crate::abi::Abi::Rust {
- output.push_str("extern \"");
- output.push_str(abi.name());
- output.push_str("\" ");
- }
-
- output.push_str("fn(");
-
- let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- if !sig.inputs().is_empty() {
- for ¶meter_type in sig.inputs() {
- push_debuginfo_type_name(cx, parameter_type, true, output, visited);
- output.push_str(", ");
- }
- output.pop();
- output.pop();
- }
-
- if sig.c_variadic {
- if !sig.inputs().is_empty() {
- output.push_str(", ...");
- } else {
- output.push_str("...");
- }
- }
-
- output.push(')');
-
- if !sig.output().is_unit() {
- output.push_str(" -> ");
- push_debuginfo_type_name(cx, sig.output(), true, output, visited);
- }
-
-
- // We only keep the type in 'visited'
- // for the duration of the body of this method.
- // It's fine for a particular function type
- // to show up multiple times in one overall type
- // (e.g. MyType<fn() -> u8, fn() -> u8>
- //
- // We only care about avoiding recursing
- // directly back to the type we're currently
- // processing
- visited.remove(t);
- },
- ty::Closure(..) => {
- output.push_str("closure");
- }
- ty::Generator(..) => {
- output.push_str("generator");
- }
- ty::Error |
- ty::Infer(_) |
- ty::Placeholder(..) |
- ty::UnnormalizedProjection(..) |
- ty::Projection(..) |
- ty::Bound(..) |
- ty::Opaque(..) |
- ty::GeneratorWitness(..) |
- ty::Param(_) => {
- bug!("debuginfo: Trying to create type name for \
- unexpected type: {:?}", t);
- }
- }
-
- fn push_item_name(cx: &CodegenCx<'_, '_>,
- def_id: DefId,
- qualified: bool,
- output: &mut String) {
- if qualified {
- output.push_str(&cx.tcx.crate_name(def_id.krate).as_str());
- for path_element in cx.tcx.def_path(def_id).data {
- output.push_str("::");
- output.push_str(&path_element.data.as_interned_str().as_str());
- }
- } else {
- output.push_str(&cx.tcx.item_name(def_id).as_str());
- }
- }
-
- // Pushes the type parameters in the given `InternalSubsts` to the output string.
- // This ignores region parameters, since they can't reliably be
- // reconstructed for items from non-local crates. For local crates, this
- // would be possible but with inlining and LTO we have to use the least
- // common denominator - otherwise we would run into conflicts.
- fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- substs: SubstsRef<'tcx>,
- output: &mut String,
- visited: &mut FxHashSet<Ty<'tcx>>) {
- if substs.types().next().is_none() {
- return;
- }
-
- output.push('<');
-
- for type_parameter in substs.types() {
- push_debuginfo_type_name(cx, type_parameter, true, output, visited);
- output.push_str(", ");
- }
-
- output.pop();
- output.pop();
-
- output.push('>');
- }
-}
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 3febcb0..bcb14b8 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -13,13 +13,13 @@
use crate::llvm;
use crate::llvm::AttributePlace::Function;
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType, FnTypeLlvmExt};
use crate::attributes;
use crate::context::CodegenCx;
use crate::type_::Type;
use crate::value::Value;
use rustc::ty::{self, PolyFnSig};
-use rustc::ty::layout::LayoutOf;
+use rustc::ty::layout::{FnTypeExt, LayoutOf};
use rustc::session::config::Sanitizer;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_codegen_ssa::traits::*;
diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/error_codes.rs
similarity index 100%
rename from src/librustc_codegen_llvm/diagnostics.rs
rename to src/librustc_codegen_llvm/error_codes.rs
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index ceb08f9..9ae0e26 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -20,7 +20,7 @@
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc::hir;
use syntax::ast::{self, FloatTy};
-use syntax::symbol::Symbol;
+use syntax::symbol::LocalInternedString;
use rustc_codegen_ssa::traits::*;
@@ -213,7 +213,7 @@
}
"type_name" => {
let tp_ty = substs.type_at(0);
- let ty_name = Symbol::intern(&tp_ty.to_string()).as_str();
+ let ty_name = LocalInternedString::intern(&tp_ty.to_string());
self.const_str_slice(ty_name)
}
"type_id" => {
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 0aae6b4..09b28405 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -44,8 +44,6 @@
#[macro_use] extern crate syntax;
extern crate syntax_pos;
extern crate rustc_errors as errors;
-extern crate serialize;
-extern crate tempfile;
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput};
@@ -65,22 +63,18 @@
use rustc::session::Session;
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
use rustc::ty::{self, TyCtxt};
-use rustc::util::profiling::ProfileCategory;
use rustc::util::common::ErrorReported;
use rustc_mir::monomorphize;
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
-mod diagnostics;
+mod error_codes;
mod back {
- mod archive;
+ pub mod archive;
pub mod bytecode;
- pub mod link;
pub mod lto;
pub mod write;
- mod rpath;
- pub mod wasm;
}
mod abi;
@@ -116,12 +110,13 @@
ModuleLlvm::new_metadata(tcx, mod_name)
}
- fn write_metadata<'b, 'gcx>(
+ fn write_compressed_metadata<'b, 'gcx>(
&self,
tcx: TyCtxt<'b, 'gcx, 'gcx>,
- metadata: &mut ModuleLlvm
- ) -> EncodedMetadata {
- base::write_metadata(tcx, metadata)
+ metadata: &EncodedMetadata,
+ llvm_module: &mut ModuleLlvm
+ ) {
+ base::write_compressed_metadata(tcx, metadata, llvm_module)
}
fn codegen_allocator<'b, 'gcx>(
&self,
@@ -295,9 +290,12 @@
fn codegen_crate<'b, 'tcx>(
&self,
tcx: TyCtxt<'b, 'tcx, 'tcx>,
+ metadata: EncodedMetadata,
+ need_metadata_module: bool,
rx: mpsc::Receiver<Box<dyn Any + Send>>
) -> Box<dyn Any> {
- box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx)
+ box rustc_codegen_ssa::base::codegen_crate(
+ LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, rx)
}
fn join_codegen_and_link(
@@ -306,7 +304,7 @@
sess: &Session,
dep_graph: &DepGraph,
outputs: &OutputFilenames,
- ) -> Result<(), ErrorReported>{
+ ) -> Result<(), ErrorReported> {
use rustc::util::common::time;
let (codegen_results, work_products) =
ongoing_codegen.downcast::
@@ -330,12 +328,21 @@
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
- sess.profiler(|p| p.start_activity(ProfileCategory::Linking, "link_crate"));
+ sess.profiler(|p| p.start_activity("link_crate"));
time(sess, "linking", || {
- back::link::link_binary(sess, &codegen_results,
- outputs, &codegen_results.crate_name.as_str());
+ use rustc_codegen_ssa::back::link::link_binary;
+ use crate::back::archive::LlvmArchiveBuilder;
+
+ let target_cpu = crate::llvm_util::target_cpu(sess);
+ link_binary::<LlvmArchiveBuilder<'_>>(
+ sess,
+ &codegen_results,
+ outputs,
+ &codegen_results.crate_name.as_str(),
+ target_cpu,
+ );
});
- sess.profiler(|p| p.end_activity(ProfileCategory::Linking, "link_crate"));
+ sess.profiler(|p| p.end_activity("link_crate"));
// Now that we won't touch anything in the incremental compilation directory
// any more, we can finalize it (which involves renaming it)
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index f6ee8be..f88923f 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1382,7 +1382,6 @@
pub fn LLVMRustDebugMetadataVersion() -> u32;
pub fn LLVMRustVersionMajor() -> u32;
pub fn LLVMRustVersionMinor() -> u32;
- pub fn LLVMRustIsRustLLVM() -> bool;
pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 5fea9c8..274c896 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -7,6 +7,7 @@
use libc::c_int;
use std::ffi::CString;
use syntax::feature_gate::UnstableFeatures;
+use syntax::symbol::sym;
use std::str;
use std::slice;
@@ -61,7 +62,7 @@
if sess.opts.debugging_opts.disable_instrumentation_preinliner {
add("-disable-preinline");
}
- if llvm::LLVMRustIsRustLLVM() {
+ if get_major_version() >= 8 {
match sess.opts.debugging_opts.merge_functions
.unwrap_or(sess.target.target.options.merge_functions) {
MergeFunctions::Disabled |
@@ -93,104 +94,106 @@
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
-const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
- ("aclass", Some("arm_target_feature")),
- ("mclass", Some("arm_target_feature")),
- ("rclass", Some("arm_target_feature")),
- ("dsp", Some("arm_target_feature")),
- ("neon", Some("arm_target_feature")),
- ("v5te", Some("arm_target_feature")),
- ("v6", Some("arm_target_feature")),
- ("v6k", Some("arm_target_feature")),
- ("v6t2", Some("arm_target_feature")),
- ("v7", Some("arm_target_feature")),
- ("v8", Some("arm_target_feature")),
- ("vfp2", Some("arm_target_feature")),
- ("vfp3", Some("arm_target_feature")),
- ("vfp4", Some("arm_target_feature")),
+const ARM_WHITELIST: &[(&str, Option<Symbol>)] = &[
+ ("aclass", Some(sym::arm_target_feature)),
+ ("mclass", Some(sym::arm_target_feature)),
+ ("rclass", Some(sym::arm_target_feature)),
+ ("dsp", Some(sym::arm_target_feature)),
+ ("neon", Some(sym::arm_target_feature)),
+ ("v5te", Some(sym::arm_target_feature)),
+ ("v6", Some(sym::arm_target_feature)),
+ ("v6k", Some(sym::arm_target_feature)),
+ ("v6t2", Some(sym::arm_target_feature)),
+ ("v7", Some(sym::arm_target_feature)),
+ ("v8", Some(sym::arm_target_feature)),
+ ("vfp2", Some(sym::arm_target_feature)),
+ ("vfp3", Some(sym::arm_target_feature)),
+ ("vfp4", Some(sym::arm_target_feature)),
];
-const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
- ("fp", Some("aarch64_target_feature")),
- ("neon", Some("aarch64_target_feature")),
- ("sve", Some("aarch64_target_feature")),
- ("crc", Some("aarch64_target_feature")),
- ("crypto", Some("aarch64_target_feature")),
- ("ras", Some("aarch64_target_feature")),
- ("lse", Some("aarch64_target_feature")),
- ("rdm", Some("aarch64_target_feature")),
- ("fp16", Some("aarch64_target_feature")),
- ("rcpc", Some("aarch64_target_feature")),
- ("dotprod", Some("aarch64_target_feature")),
- ("v8.1a", Some("aarch64_target_feature")),
- ("v8.2a", Some("aarch64_target_feature")),
- ("v8.3a", Some("aarch64_target_feature")),
+const AARCH64_WHITELIST: &[(&str, Option<Symbol>)] = &[
+ ("fp", Some(sym::aarch64_target_feature)),
+ ("neon", Some(sym::aarch64_target_feature)),
+ ("sve", Some(sym::aarch64_target_feature)),
+ ("crc", Some(sym::aarch64_target_feature)),
+ ("crypto", Some(sym::aarch64_target_feature)),
+ ("ras", Some(sym::aarch64_target_feature)),
+ ("lse", Some(sym::aarch64_target_feature)),
+ ("rdm", Some(sym::aarch64_target_feature)),
+ ("fp16", Some(sym::aarch64_target_feature)),
+ ("rcpc", Some(sym::aarch64_target_feature)),
+ ("dotprod", Some(sym::aarch64_target_feature)),
+ ("v8.1a", Some(sym::aarch64_target_feature)),
+ ("v8.2a", Some(sym::aarch64_target_feature)),
+ ("v8.3a", Some(sym::aarch64_target_feature)),
];
-const X86_WHITELIST: &[(&str, Option<&str>)] = &[
- ("adx", Some("adx_target_feature")),
+const X86_WHITELIST: &[(&str, Option<Symbol>)] = &[
+ ("adx", Some(sym::adx_target_feature)),
("aes", None),
("avx", None),
("avx2", None),
- ("avx512bw", Some("avx512_target_feature")),
- ("avx512cd", Some("avx512_target_feature")),
- ("avx512dq", Some("avx512_target_feature")),
- ("avx512er", Some("avx512_target_feature")),
- ("avx512f", Some("avx512_target_feature")),
- ("avx512ifma", Some("avx512_target_feature")),
- ("avx512pf", Some("avx512_target_feature")),
- ("avx512vbmi", Some("avx512_target_feature")),
- ("avx512vl", Some("avx512_target_feature")),
- ("avx512vpopcntdq", Some("avx512_target_feature")),
+ ("avx512bw", Some(sym::avx512_target_feature)),
+ ("avx512cd", Some(sym::avx512_target_feature)),
+ ("avx512dq", Some(sym::avx512_target_feature)),
+ ("avx512er", Some(sym::avx512_target_feature)),
+ ("avx512f", Some(sym::avx512_target_feature)),
+ ("avx512ifma", Some(sym::avx512_target_feature)),
+ ("avx512pf", Some(sym::avx512_target_feature)),
+ ("avx512vbmi", Some(sym::avx512_target_feature)),
+ ("avx512vl", Some(sym::avx512_target_feature)),
+ ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
("bmi1", None),
("bmi2", None),
- ("cmpxchg16b", Some("cmpxchg16b_target_feature")),
+ ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
+ ("f16c", Some(sym::f16c_target_feature)),
("fma", None),
("fxsr", None),
("lzcnt", None),
- ("mmx", Some("mmx_target_feature")),
- ("movbe", Some("movbe_target_feature")),
+ ("mmx", Some(sym::mmx_target_feature)),
+ ("movbe", Some(sym::movbe_target_feature)),
("pclmulqdq", None),
("popcnt", None),
("rdrand", None),
("rdseed", None),
+ ("rtm", Some(sym::rtm_target_feature)),
("sha", None),
("sse", None),
("sse2", None),
("sse3", None),
("sse4.1", None),
("sse4.2", None),
- ("sse4a", Some("sse4a_target_feature")),
+ ("sse4a", Some(sym::sse4a_target_feature)),
("ssse3", None),
- ("tbm", Some("tbm_target_feature")),
+ ("tbm", Some(sym::tbm_target_feature)),
("xsave", None),
("xsavec", None),
("xsaveopt", None),
("xsaves", None),
];
-const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
- ("hvx", Some("hexagon_target_feature")),
- ("hvx-double", Some("hexagon_target_feature")),
+const HEXAGON_WHITELIST: &[(&str, Option<Symbol>)] = &[
+ ("hvx", Some(sym::hexagon_target_feature)),
+ ("hvx-double", Some(sym::hexagon_target_feature)),
];
-const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
- ("altivec", Some("powerpc_target_feature")),
- ("power8-altivec", Some("powerpc_target_feature")),
- ("power9-altivec", Some("powerpc_target_feature")),
- ("power8-vector", Some("powerpc_target_feature")),
- ("power9-vector", Some("powerpc_target_feature")),
- ("vsx", Some("powerpc_target_feature")),
+const POWERPC_WHITELIST: &[(&str, Option<Symbol>)] = &[
+ ("altivec", Some(sym::powerpc_target_feature)),
+ ("power8-altivec", Some(sym::powerpc_target_feature)),
+ ("power9-altivec", Some(sym::powerpc_target_feature)),
+ ("power8-vector", Some(sym::powerpc_target_feature)),
+ ("power9-vector", Some(sym::powerpc_target_feature)),
+ ("vsx", Some(sym::powerpc_target_feature)),
];
-const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
- ("fp64", Some("mips_target_feature")),
- ("msa", Some("mips_target_feature")),
+const MIPS_WHITELIST: &[(&str, Option<Symbol>)] = &[
+ ("fp64", Some(sym::mips_target_feature)),
+ ("msa", Some(sym::mips_target_feature)),
];
-const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
- ("simd128", Some("wasm_target_feature")),
- ("atomics", Some("wasm_target_feature")),
+const WASM_WHITELIST: &[(&str, Option<Symbol>)] = &[
+ ("simd128", Some(sym::wasm_target_feature)),
+ ("atomics", Some(sym::wasm_target_feature)),
];
/// When rustdoc is running, provide a list of all known features so that all their respective
@@ -198,7 +201,7 @@
///
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
/// iterator!
-pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
+pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<Symbol>)> {
ARM_WHITELIST.iter().cloned()
.chain(AARCH64_WHITELIST.iter().cloned())
.chain(X86_WHITELIST.iter().cloned())
@@ -245,7 +248,7 @@
}
pub fn target_feature_whitelist(sess: &Session)
- -> &'static [(&'static str, Option<&'static str>)]
+ -> &'static [(&'static str, Option<Symbol>)]
{
match &*sess.target.target.arch {
"arm" => ARM_WHITELIST,
diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs
index a2df687..7cf497c 100644
--- a/src/librustc_codegen_llvm/metadata.rs
+++ b/src/librustc_codegen_llvm/metadata.rs
@@ -5,6 +5,8 @@
use rustc_target::spec::Target;
use rustc_data_structures::owning_ref::OwningRef;
+use rustc_codegen_ssa::METADATA_FILENAME;
+
use std::path::Path;
use std::ptr;
use std::slice;
@@ -12,8 +14,6 @@
pub use rustc_data_structures::sync::MetadataRef;
-pub const METADATA_FILENAME: &str = "rust.metadata.bin";
-
pub struct LlvmMetadataLoader;
impl MetadataLoader for LlvmMetadataLoader {
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index a5ed64a..a3d3f07 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -10,7 +10,7 @@
use crate::common;
use crate::type_of::LayoutLlvmExt;
-use crate::abi::{LlvmType, FnTypeExt};
+use crate::abi::{LlvmType, FnTypeLlvmExt};
use syntax::ast;
use rustc::ty::Ty;
use rustc::ty::layout::{self, Align, Size, TyLayout};
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 0204476..800bf50 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -1,10 +1,9 @@
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType};
use crate::common::*;
use crate::type_::Type;
-use rustc::hir;
use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout};
-use rustc_target::abi::FloatTy;
+use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout};
+use rustc_target::abi::{FloatTy, TyLayoutMethods};
use rustc_mir::monomorphize::item::DefPathBasedNames;
use rustc_codegen_ssa::traits::*;
@@ -63,6 +62,11 @@
write!(&mut name, "::{}", def.variants[index].ident).unwrap();
}
}
+ if let (&ty::Generator(_, substs, _), &layout::Variants::Single { index })
+ = (&layout.ty.sty, &layout.variants)
+ {
+ write!(&mut name, "::{}", substs.variant_name(index)).unwrap();
+ }
Some(name)
}
_ => None
@@ -169,28 +173,6 @@
}
}
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum PointerKind {
- /// Most general case, we know no restrictions to tell LLVM.
- Shared,
-
- /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`.
- Frozen,
-
- /// `&mut T`, when we know `noalias` is safe for LLVM.
- UniqueBorrowed,
-
- /// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns.
- UniqueOwned
-}
-
-#[derive(Copy, Clone)]
-pub struct PointeeInfo {
- pub size: Size,
- pub align: Align,
- pub safe: Option<PointerKind>,
-}
-
pub trait LayoutLlvmExt<'tcx> {
fn is_llvm_immediate(&self) -> bool;
fn is_llvm_scalar_pair<'a>(&self) -> bool;
@@ -401,116 +383,7 @@
return pointee;
}
- let mut result = None;
- match self.ty.sty {
- ty::RawPtr(mt) if offset.bytes() == 0 => {
- let (size, align) = cx.size_and_align_of(mt.ty);
- result = Some(PointeeInfo {
- size,
- align,
- safe: None
- });
- }
-
- ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
- let (size, align) = cx.size_and_align_of(ty);
-
- let kind = match mt {
- hir::MutImmutable => if cx.type_is_freeze(ty) {
- PointerKind::Frozen
- } else {
- PointerKind::Shared
- },
- hir::MutMutable => {
- // Previously we would only emit noalias annotations for LLVM >= 6 or in
- // panic=abort mode. That was deemed right, as prior versions had many bugs
- // in conjunction with unwinding, but later versions didn’t seem to have
- // said issues. See issue #31681.
- //
- // Alas, later on we encountered a case where noalias would generate wrong
- // code altogether even with recent versions of LLVM in *safe* code with no
- // unwinding involved. See #54462.
- //
- // For now, do not enable mutable_noalias by default at all, while the
- // issue is being figured out.
- let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias
- .unwrap_or(false);
- if mutable_noalias {
- PointerKind::UniqueBorrowed
- } else {
- PointerKind::Shared
- }
- }
- };
-
- result = Some(PointeeInfo {
- size,
- align,
- safe: Some(kind)
- });
- }
-
- _ => {
- let mut data_variant = match self.variants {
- layout::Variants::Multiple {
- discr_kind: layout::DiscriminantKind::Niche {
- dataful_variant,
- ..
- },
- ..
- } => {
- // Only the niche itself is always initialized,
- // so only check for a pointer at its offset.
- //
- // If the niche is a pointer, it's either valid
- // (according to its type), or null (which the
- // niche field's scalar validity range encodes).
- // This allows using `dereferenceable_or_null`
- // for e.g., `Option<&T>`, and this will continue
- // to work as long as we don't start using more
- // niches than just null (e.g., the first page
- // of the address space, or unaligned pointers).
- if self.fields.offset(0) == offset {
- Some(self.for_variant(cx, dataful_variant))
- } else {
- None
- }
- }
- _ => Some(*self)
- };
-
- if let Some(variant) = data_variant {
- // We're not interested in any unions.
- if let layout::FieldPlacement::Union(_) = variant.fields {
- data_variant = None;
- }
- }
-
- if let Some(variant) = data_variant {
- let ptr_end = offset + layout::Pointer.size(cx);
- for i in 0..variant.fields.count() {
- let field_start = variant.fields.offset(i);
- if field_start <= offset {
- let field = variant.field(cx, i);
- if ptr_end <= field_start + field.size {
- // We found the right field, look inside it.
- result = field.pointee_info_at(cx, offset - field_start);
- break;
- }
- }
- }
- }
-
- // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
- if let Some(ref mut pointee) = result {
- if let ty::Adt(def, _) = self.ty.sty {
- if def.is_box() && offset.bytes() == 0 {
- pointee.safe = Some(PointerKind::UniqueOwned);
- }
- }
- }
- }
- }
+ let result = Ty::pointee_info_at(*self, cx, offset);
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
result
diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs
index 7fc17d1..410e00f 100644
--- a/src/librustc_codegen_llvm/va_arg.rs
+++ b/src/librustc_codegen_llvm/va_arg.rs
@@ -145,4 +145,3 @@
}
}
}
-