Importing rustc-1.63.0
Test: ./build.py --lto=thin
Bug: 241303140
Change-Id: I967a77fc8365f26b17c8b9b70d5a2d64d948dd86
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index b9baa87..cc8b3a1 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -393,6 +393,7 @@
fn llvm_cconv(&self) -> llvm::CallConv {
match self.conv {
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
+ Conv::RustCold => llvm::ColdCallConv,
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
Conv::AvrInterrupt => llvm::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index e994001..a539469 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -604,7 +604,8 @@
InlineAsmRegClass::X86(
X86InlineAsmRegClass::x87_reg
| X86InlineAsmRegClass::mmx_reg
- | X86InlineAsmRegClass::kreg0,
+ | X86InlineAsmRegClass::kreg0
+ | X86InlineAsmRegClass::tmm_reg,
) => unreachable!("clobber-only"),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
@@ -692,7 +693,8 @@
InlineAsmRegClass::X86(
X86InlineAsmRegClass::x87_reg
| X86InlineAsmRegClass::mmx_reg
- | X86InlineAsmRegClass::kreg0,
+ | X86InlineAsmRegClass::kreg0
+ | X86InlineAsmRegClass::tmm_reg,
) => {
unreachable!("clobber-only")
}
@@ -766,7 +768,8 @@
InlineAsmRegClass::X86(
X86InlineAsmRegClass::x87_reg
| X86InlineAsmRegClass::mmx_reg
- | X86InlineAsmRegClass::kreg0,
+ | X86InlineAsmRegClass::kreg0
+ | X86InlineAsmRegClass::tmm_reg,
) => {
unreachable!("clobber-only")
}
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 8f6438e..da9d8b5 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -15,19 +15,12 @@
use rustc_session::cstore::{DllCallingConvention, DllImport};
use rustc_session::Session;
-struct ArchiveConfig<'a> {
- pub sess: &'a Session,
- pub dst: PathBuf,
- pub src: Option<PathBuf>,
-}
-
/// Helper for adding many files to an archive.
#[must_use = "must call build() to finish building the archive"]
pub struct LlvmArchiveBuilder<'a> {
- config: ArchiveConfig<'a>,
- removals: Vec<String>,
+ sess: &'a Session,
+ dst: PathBuf,
additions: Vec<Addition>,
- src_archive: Option<Option<ArchiveRO>>,
}
enum Addition {
@@ -50,10 +43,6 @@
}
}
-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()) }
-}
-
/// Map machine type strings to values of LLVM's MachineTypes enum.
fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
match cpu {
@@ -68,37 +57,8 @@
impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
/// Creates a new static archive, ready for modifying the archive specified
/// by `config`.
- 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(),
- src_archive: None,
- }
- }
-
- /// Removes a file from this archive
- fn remove_file(&mut self, file: &str) {
- self.removals.push(file.to_string());
- }
-
- /// Lists all files in an archive
- fn src_files(&mut self) -> Vec<String> {
- if self.src_archive().is_none() {
- return Vec::new();
- }
-
- let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap();
-
- archive
- .iter()
- .filter_map(|child| child.ok())
- .filter(is_relevant_child)
- .filter_map(|child| child.name())
- .filter(|name| !self.removals.iter().any(|x| x == name))
- .map(|name| name.to_owned())
- .collect()
+ fn new(sess: &'a Session, output: &Path) -> LlvmArchiveBuilder<'a> {
+ LlvmArchiveBuilder { sess, dst: output.to_path_buf(), additions: Vec::new() }
}
fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
@@ -129,13 +89,10 @@
/// 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));
+ fn build(mut self) -> bool {
+ match self.build_with_llvm() {
+ Ok(any_members) => any_members,
+ Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)),
}
}
@@ -151,7 +108,7 @@
output_path.with_extension("lib")
};
- let target = &self.config.sess.target;
+ let target = &self.sess.target;
let mingw_gnu_toolchain = target.vendor == "pc"
&& target.os == "windows"
&& target.env == "gnu"
@@ -160,7 +117,7 @@
let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
.iter()
.map(|import: &DllImport| {
- if self.config.sess.target.arch == "x86" {
+ if self.sess.target.arch == "x86" {
(
LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
import.ordinal,
@@ -197,11 +154,11 @@
match std::fs::write(&def_file_path, def_file_content) {
Ok(_) => {}
Err(e) => {
- self.config.sess.fatal(&format!("Error writing .DEF file: {}", e));
+ self.sess.fatal(&format!("Error writing .DEF file: {}", e));
}
};
- let dlltool = find_binutils_dlltool(self.config.sess);
+ let dlltool = find_binutils_dlltool(self.sess);
let result = std::process::Command::new(dlltool)
.args([
"-d",
@@ -215,9 +172,9 @@
match result {
Err(e) => {
- self.config.sess.fatal(&format!("Error calling dlltool: {}", e));
+ self.sess.fatal(&format!("Error calling dlltool: {}", e));
}
- Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
+ Ok(output) if !output.status.success() => self.sess.fatal(&format!(
"Dlltool could not create import library: {}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
@@ -263,13 +220,13 @@
output_path_z.as_ptr(),
ffi_exports.as_ptr(),
ffi_exports.len(),
- llvm_machine_type(&self.config.sess.target.arch) as u16,
- !self.config.sess.target.is_like_msvc,
+ llvm_machine_type(&self.sess.target.arch) as u16,
+ !self.sess.target.is_like_msvc,
)
};
if result == crate::llvm::LLVMRustResult::Failure {
- self.config.sess.fatal(&format!(
+ self.sess.fatal(&format!(
"Error creating import library for {}: {}",
lib_name,
llvm::last_error().unwrap_or("unknown LLVM error".to_string())
@@ -278,7 +235,7 @@
};
self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
- self.config.sess.fatal(&format!(
+ self.sess.fatal(&format!(
"failed to add native library {}: {}",
output_path.display(),
e
@@ -288,46 +245,19 @@
}
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 build_with_llvm(&mut self) -> io::Result<bool> {
+ let kind = &*self.sess.target.archive_format;
+ let kind = kind.parse::<ArchiveKind>().map_err(|_| kind).unwrap_or_else(|kind| {
+ self.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
+ });
- fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
- let kind = &*self.config.sess.target.archive_format;
- kind.parse().map_err(|_| kind)
- }
-
- fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
- let removals = mem::take(&mut self.removals);
let mut additions = mem::take(&mut self.additions);
let mut strings = Vec::new();
let mut members = Vec::new();
- let dst = CString::new(self.config.dst.to_str().unwrap())?;
+ let dst = CString::new(self.dst.to_str().unwrap())?;
unsafe {
- if let Some(archive) = self.src_archive() {
- for child in archive.iter() {
- let child = child.map_err(string_to_io_error)?;
- let Some(child_name) = child.name() else { continue };
- if removals.iter().any(|r| r == child_name) {
- continue;
- }
-
- let name = CString::new(child_name)?;
- members.push(llvm::LLVMRustArchiveMemberNew(
- ptr::null(),
- name.as_ptr(),
- Some(child.raw),
- ));
- strings.push(name);
- }
- }
for addition in &mut additions {
match addition {
Addition::File { path, name_in_archive } => {
@@ -389,7 +319,7 @@
};
Err(io::Error::new(io::ErrorKind::Other, msg))
} else {
- Ok(())
+ Ok(!members.is_empty())
};
for member in members {
llvm::LLVMRustArchiveMemberFree(member);
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index d0724ba..38402e0 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -354,14 +354,14 @@
Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode })
}
-crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
+pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>);
impl<'a> Linker<'a> {
- crate fn new(llmod: &'a llvm::Module) -> Self {
+ pub(crate) fn new(llmod: &'a llvm::Module) -> Self {
unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
}
- crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
+ pub(crate) fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
unsafe {
if llvm::LLVMRustLinkerAdd(
self.0,
@@ -586,9 +586,21 @@
// LTO-specific optimization passes that LLVM provides.
//
// This code is based off the code found in llvm's LTO code generator:
- // tools/lto/LTOCodeGenerator.cpp
+ // llvm/lib/LTO/LTOCodeGenerator.cpp
debug!("running the pass manager");
unsafe {
+ if !llvm::LLVMRustHasModuleFlag(
+ module.module_llvm.llmod(),
+ "LTOPostLink".as_ptr().cast(),
+ 11,
+ ) {
+ llvm::LLVMRustAddModuleFlag(
+ module.module_llvm.llmod(),
+ llvm::LLVMModFlagBehavior::Error,
+ "LTOPostLink\0".as_ptr().cast(),
+ 1,
+ );
+ }
if llvm_util::should_use_new_llvm_pass_manager(
&config.new_llvm_pass_manager,
&cgcx.target_arch,
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 99e3053..ab8874d 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -56,28 +56,24 @@
file_type: llvm::FileType,
self_profiler_ref: &SelfProfilerRef,
) -> Result<(), FatalError> {
+ debug!("write_output_file output={:?} dwo_output={:?}", output, dwo_output);
unsafe {
let output_c = path_to_c_string(output);
- let result = if let Some(dwo_output) = dwo_output {
- let dwo_output_c = path_to_c_string(dwo_output);
- llvm::LLVMRustWriteOutputFile(
- target,
- pm,
- m,
- output_c.as_ptr(),
- dwo_output_c.as_ptr(),
- file_type,
- )
+ let dwo_output_c;
+ let dwo_output_ptr = if let Some(dwo_output) = dwo_output {
+ dwo_output_c = path_to_c_string(dwo_output);
+ dwo_output_c.as_ptr()
} else {
- llvm::LLVMRustWriteOutputFile(
- target,
- pm,
- m,
- output_c.as_ptr(),
- std::ptr::null(),
- file_type,
- )
+ std::ptr::null()
};
+ let result = llvm::LLVMRustWriteOutputFile(
+ target,
+ pm,
+ m,
+ output_c.as_ptr(),
+ dwo_output_ptr,
+ file_type,
+ );
// Record artifact sizes for self-profiling
if result == llvm::LLVMRustResult::Success {
@@ -340,7 +336,7 @@
}
let level = match level {
llvm::DiagnosticLevel::Error => Level::Error { lint: false },
- llvm::DiagnosticLevel::Warning => Level::Warning,
+ llvm::DiagnosticLevel::Warning => Level::Warning(None),
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
};
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
@@ -467,7 +463,7 @@
let llvm_selfprofiler =
llvm_profiler.as_mut().map(|s| s as *mut _ as *mut c_void).unwrap_or(std::ptr::null_mut());
- let extra_passes = config.passes.join(",");
+ let extra_passes = if !is_lto { config.passes.join(",") } else { "".to_string() };
let llvm_plugins = config.llvm_plugins.join(",");
@@ -1040,7 +1036,8 @@
// reason (see issue #90326 for historical background).
let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
|| cgcx.opts.target_triple.triple().contains("-darwin")
- || cgcx.opts.target_triple.triple().contains("-tvos");
+ || cgcx.opts.target_triple.triple().contains("-tvos")
+ || cgcx.opts.target_triple.triple().contains("-watchos");
if is_apple
|| cgcx.opts.target_triple.triple().starts_with("wasm")
|| cgcx.opts.target_triple.triple().starts_with("asmjs")
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 88b8795..c41a419 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -509,15 +509,20 @@
OperandValue::Ref(place.llval, Some(llextra), place.align)
} else if place.layout.is_llvm_immediate() {
let mut const_llval = None;
+ let llty = place.layout.llvm_type(self);
unsafe {
if let Some(global) = llvm::LLVMIsAGlobalVariable(place.llval) {
if llvm::LLVMIsGlobalConstant(global) == llvm::True {
- const_llval = llvm::LLVMGetInitializer(global);
+ if let Some(init) = llvm::LLVMGetInitializer(global) {
+ if self.val_ty(init) == llty {
+ const_llval = Some(init);
+ }
+ }
}
}
}
let llval = const_llval.unwrap_or_else(|| {
- let load = self.load(place.layout.llvm_type(self), place.llval, place.align);
+ let load = self.load(llty, place.llval, place.align);
if let abi::Abi::Scalar(scalar) = place.layout.abi {
scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO);
}
@@ -1412,7 +1417,7 @@
unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
}
- crate fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
+ pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
let (ty, f) = self.cx.get_intrinsic(intrinsic);
self.call(ty, f, args, None)
}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 4d3f3f3..5bbbfe9 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -212,11 +212,11 @@
}
impl<'ll> CodegenCx<'ll, '_> {
- crate fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+ pub(crate) fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMConstBitCast(val, ty) }
}
- crate fn static_addr_of_mut(
+ pub(crate) fn static_addr_of_mut(
&self,
cv: &'ll Value,
align: Align,
@@ -241,7 +241,7 @@
}
}
- crate fn get_static(&self, def_id: DefId) -> &'ll Value {
+ pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
let instance = Instance::mono(self.tcx, def_id);
if let Some(&g) = self.instances.borrow().get(&instance) {
return g;
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index d296ee3..c007728 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -326,11 +326,20 @@
)
}
+ if sess.opts.debugging_opts.virtual_function_elimination {
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Error,
+ "Virtual Function Elim\0".as_ptr().cast(),
+ 1,
+ );
+ }
+
llmod
}
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
- crate fn new(
+ pub(crate) fn new(
tcx: TyCtxt<'tcx>,
codegen_unit: &'tcx CodegenUnit<'tcx>,
llvm_module: &'ll crate::ModuleLlvm,
@@ -447,7 +456,7 @@
}
}
- crate fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> {
+ pub(crate) fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> {
&self.statics_to_rauw
}
@@ -599,7 +608,7 @@
}
impl<'ll> CodegenCx<'ll, '_> {
- crate fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) {
+ pub(crate) fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) {
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
return v;
}
@@ -656,6 +665,7 @@
let t_isize = self.type_isize();
let t_f32 = self.type_f32();
let t_f64 = self.type_f64();
+ let t_metadata = self.type_metadata();
ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);
@@ -881,21 +891,22 @@
ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
}
- ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1);
+ ifn!("llvm.type.test", fn(i8p, t_metadata) -> i1);
+ ifn!("llvm.type.checked.load", fn(i8p, t_i32, t_metadata) -> mk_struct! {i8p, i1});
if self.sess().opts.debuginfo != DebugInfo::None {
- ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void);
- ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void);
+ ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void);
+ ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void);
}
None
}
- crate fn eh_catch_typeinfo(&self) -> &'ll Value {
+ pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value {
if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() {
return eh_catch_typeinfo;
}
let tcx = self.tcx;
- assert!(self.sess().target.is_like_emscripten);
+ assert!(self.sess().target.os == "emscripten");
let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
Some(def_id) => self.get_static(def_id),
_ => {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 31a0924..5186aee 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -5,11 +5,14 @@
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::value::Value;
+use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
use rustc_codegen_ssa::traits::*;
+use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
-use rustc_session::config::DebugInfo;
+use rustc_session::config::{CrateType, DebugInfo};
use rustc_span::symbol::sym;
+use rustc_span::DebuggerVisualizerType;
/// Inserts a side-effect free instruction sequence that makes sure that the
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
@@ -37,9 +40,33 @@
section_var.unwrap_or_else(|| {
let section_name = b".debug_gdb_scripts\0";
- let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
+ let mut section_contents = Vec::new();
+
+ // Add the pretty printers for the standard library first.
+ section_contents.extend_from_slice(b"\x01gdb_load_rust_pretty_printers.py\0");
+
+ // Next, add the pretty printers that were specified via the `#[debugger_visualizer]` attribute.
+ let visualizers = collect_debugger_visualizers_transitive(
+ cx.tcx,
+ DebuggerVisualizerType::GdbPrettyPrinter,
+ );
+ let crate_name = cx.tcx.crate_name(LOCAL_CRATE);
+ for (index, visualizer) in visualizers.iter().enumerate() {
+ // The initial byte `4` instructs GDB that the following pretty printer
+ // is defined inline as opposed to in a standalone file.
+ section_contents.extend_from_slice(b"\x04");
+ let vis_name = format!("pretty-printer-{}-{}\n", crate_name.as_str(), index);
+ section_contents.extend_from_slice(vis_name.as_bytes());
+ section_contents.extend_from_slice(&visualizer.src);
+
+ // The final byte `0` tells GDB that the pretty printer has been
+ // fully defined and can continue searching for additional
+ // pretty printers.
+ section_contents.extend_from_slice(b"\0");
+ }
unsafe {
+ let section_contents = section_contents.as_slice();
let llvm_type = cx.type_array(cx.type_i8(), section_contents.len() as u64);
let section_var = cx
@@ -62,7 +89,32 @@
let omit_gdb_pretty_printer_section =
cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
+ // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
+ // ODR violations at link time, this section will not be emitted for rlibs since
+ // each rlib could produce a different set of visualizers that would be embedded
+ // in the `.debug_gdb_scripts` section. For that reason, we make sure that the
+ // section is only emitted for leaf crates.
+ let embed_visualizers = cx.sess().crate_types().iter().any(|&crate_type| match crate_type {
+ CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => {
+ // These are crate types for which we will embed pretty printers since they
+ // are treated as leaf crates.
+ true
+ }
+ CrateType::ProcMacro => {
+ // We could embed pretty printers for proc macro crates too but it does not
+ // seem like a good default, since this is a rare use case and we don't
+ // want to slow down the common case.
+ false
+ }
+ CrateType::Rlib => {
+ // As per the above description, embedding pretty printers for rlibs could
+ // lead to ODR violations so we skip this crate type as well.
+ false
+ }
+ });
+
!omit_gdb_pretty_printer_section
&& cx.sess().opts.debuginfo != DebugInfo::None
&& cx.sess().target.emit_debug_gdb_scripts
+ && embed_visualizers
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index f2cf3b1..d5f39a4 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -30,26 +30,28 @@
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::bug;
use rustc_middle::mir::{self, GeneratorLayout};
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES};
-use rustc_session::config::{self, DebugInfo};
+use rustc_middle::ty::{
+ self, AdtKind, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
+};
+use rustc_session::config::{self, DebugInfo, Lto};
use rustc_span::symbol::Symbol;
-use rustc_span::FileNameDisplayPreference;
-use rustc_span::{self, SourceFile, SourceFileHash};
+use rustc_span::FileName;
+use rustc_span::{self, FileNameDisplayPreference, SourceFile};
+use rustc_symbol_mangling::typeid_for_trait_ref;
use rustc_target::abi::{Align, Size};
use smallvec::smallvec;
use tracing::debug;
-use libc::{c_longlong, c_uint};
+use libc::{c_char, c_longlong, c_uint};
use std::borrow::Cow;
-use std::collections::hash_map::Entry;
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter;
use std::path::{Path, PathBuf};
use std::ptr;
+use tracing::instrument;
impl PartialEq for llvm::Metadata {
fn eq(&self, other: &Self) -> bool {
@@ -527,76 +529,103 @@
}
pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
- debug!("file_metadata: file_name: {:?}", source_file.name);
+ let cache_key = Some((source_file.name_hash, source_file.src_hash));
+ return debug_context(cx)
+ .created_files
+ .borrow_mut()
+ .entry(cache_key)
+ .or_insert_with(|| alloc_new_file_metadata(cx, source_file));
- let hash = Some(&source_file.src_hash);
- let file_name = Some(source_file.name.prefer_remapped().to_string());
- let directory = if source_file.is_real_file() && !source_file.is_imported() {
- Some(
- cx.sess()
- .opts
- .working_dir
- .to_string_lossy(FileNameDisplayPreference::Remapped)
- .to_string(),
- )
- } 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.
- None
- };
- file_metadata_raw(cx, file_name, directory, hash)
+ #[instrument(skip(cx, source_file), level = "debug")]
+ fn alloc_new_file_metadata<'ll>(
+ cx: &CodegenCx<'ll, '_>,
+ source_file: &SourceFile,
+ ) -> &'ll DIFile {
+ debug!(?source_file.name);
+
+ let (directory, file_name) = match &source_file.name {
+ FileName::Real(filename) => {
+ let working_directory = &cx.sess().opts.working_dir;
+ debug!(?working_directory);
+
+ let filename = cx
+ .sess()
+ .source_map()
+ .path_mapping()
+ .to_embeddable_absolute_path(filename.clone(), working_directory);
+
+ // Construct the absolute path of the file
+ let abs_path = filename.remapped_path_if_available();
+ debug!(?abs_path);
+
+ if let Ok(rel_path) =
+ abs_path.strip_prefix(working_directory.remapped_path_if_available())
+ {
+ // If the compiler's working directory (which also is the DW_AT_comp_dir of
+ // the compilation unit) is a prefix of the path we are about to emit, then
+ // only emit the part relative to the working directory.
+ // Because of path remapping we sometimes see strange things here: `abs_path`
+ // might actually look like a relative path
+ // (e.g. `<crate-name-and-version>/src/lib.rs`), so if we emit it without
+ // taking the working directory into account, downstream tooling will
+ // interpret it as `<working-directory>/<crate-name-and-version>/src/lib.rs`,
+ // which makes no sense. Usually in such cases the working directory will also
+ // be remapped to `<crate-name-and-version>` or some other prefix of the path
+ // we are remapping, so we end up with
+ // `<crate-name-and-version>/<crate-name-and-version>/src/lib.rs`.
+ // By moving the working directory portion into the `directory` part of the
+ // DIFile, we allow LLVM to emit just the relative path for DWARF, while
+ // still emitting the correct absolute path for CodeView.
+ (
+ working_directory.to_string_lossy(FileNameDisplayPreference::Remapped),
+ rel_path.to_string_lossy().into_owned(),
+ )
+ } else {
+ ("".into(), abs_path.to_string_lossy().into_owned())
+ }
+ }
+ other => ("".into(), other.prefer_remapped().to_string_lossy().into_owned()),
+ };
+
+ let hash_kind = match source_file.src_hash.kind {
+ rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
+ rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
+ rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
+ };
+ let hash_value = hex_encode(source_file.src_hash.hash_bytes());
+
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateFile(
+ DIB(cx),
+ file_name.as_ptr().cast(),
+ file_name.len(),
+ directory.as_ptr().cast(),
+ directory.len(),
+ hash_kind,
+ hash_value.as_ptr().cast(),
+ hash_value.len(),
+ )
+ }
+ }
}
pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
- file_metadata_raw(cx, None, None, None)
-}
+ debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| unsafe {
+ let file_name = "<unknown>";
+ let directory = "";
+ let hash_value = "";
-fn file_metadata_raw<'ll>(
- cx: &CodegenCx<'ll, '_>,
- file_name: Option<String>,
- directory: Option<String>,
- hash: Option<&SourceFileHash>,
-) -> &'ll DIFile {
- let key = (file_name, directory);
-
- match debug_context(cx).created_files.borrow_mut().entry(key) {
- Entry::Occupied(o) => o.get(),
- Entry::Vacant(v) => {
- let (file_name, directory) = v.key();
- debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory);
-
- let file_name = file_name.as_deref().unwrap_or("<unknown>");
- let directory = directory.as_deref().unwrap_or("");
-
- let (hash_kind, hash_value) = match hash {
- Some(hash) => {
- let kind = match hash.kind {
- rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
- rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
- rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
- };
- (kind, hex_encode(hash.hash_bytes()))
- }
- None => (llvm::ChecksumKind::None, String::new()),
- };
-
- let file_metadata = unsafe {
- llvm::LLVMRustDIBuilderCreateFile(
- DIB(cx),
- file_name.as_ptr().cast(),
- file_name.len(),
- directory.as_ptr().cast(),
- directory.len(),
- hash_kind,
- hash_value.as_ptr().cast(),
- hash_value.len(),
- )
- };
-
- v.insert(file_metadata);
- file_metadata
- }
- }
+ llvm::LLVMRustDIBuilderCreateFile(
+ DIB(cx),
+ file_name.as_ptr().cast(),
+ file_name.len(),
+ directory.as_ptr().cast(),
+ directory.len(),
+ llvm::ChecksumKind::None,
+ hash_value.as_ptr().cast(),
+ hash_value.len(),
+ )
+ })
}
trait MsvcBasicName {
@@ -1337,7 +1366,7 @@
is_local_to_unit,
global,
None,
- global_align.bytes() as u32,
+ global_align.bits() as u32,
);
}
}
@@ -1364,7 +1393,7 @@
tcx.vtable_entries(trait_ref)
} else {
- COMMON_VTABLE_ENTRIES
+ TyCtxt::COMMON_VTABLE_ENTRIES
};
// All function pointers are described as opaque pointers. This could be improved in the future
@@ -1440,6 +1469,84 @@
.di_node
}
+fn vcall_visibility_metadata<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ ty: Ty<'tcx>,
+ trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
+ vtable: &'ll Value,
+) {
+ enum VCallVisibility {
+ Public = 0,
+ LinkageUnit = 1,
+ TranslationUnit = 2,
+ }
+
+ let Some(trait_ref) = trait_ref else { return };
+
+ let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
+ let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
+ let trait_def_id = trait_ref_self.def_id();
+ let trait_vis = cx.tcx.visibility(trait_def_id);
+
+ let cgus = cx.sess().codegen_units();
+ let single_cgu = cgus == 1;
+
+ let lto = cx.sess().lto();
+
+ // Since LLVM requires full LTO for the virtual function elimination optimization to apply,
+ // only the `Lto::Fat` cases are relevant currently.
+ let vcall_visibility = match (lto, trait_vis, single_cgu) {
+ // If there is not LTO and the visibility in public, we have to assume that the vtable can
+ // be seen from anywhere. With multiple CGUs, the vtable is quasi-public.
+ (Lto::No | Lto::ThinLocal, Visibility::Public, _)
+ | (Lto::No, Visibility::Restricted(_) | Visibility::Invisible, false) => {
+ VCallVisibility::Public
+ }
+ // With LTO and a quasi-public visibility, the usages of the functions of the vtable are
+ // all known by the `LinkageUnit`.
+ // FIXME: LLVM only supports this optimization for `Lto::Fat` currently. Once it also
+ // supports `Lto::Thin` the `VCallVisibility` may have to be adjusted for those.
+ (Lto::Fat | Lto::Thin, Visibility::Public, _)
+ | (
+ Lto::ThinLocal | Lto::Thin | Lto::Fat,
+ Visibility::Restricted(_) | Visibility::Invisible,
+ false,
+ ) => VCallVisibility::LinkageUnit,
+ // If there is only one CGU, private vtables can only be seen by that CGU/translation unit
+ // and therefore we know of all usages of functions in the vtable.
+ (_, Visibility::Restricted(_) | Visibility::Invisible, true) => {
+ VCallVisibility::TranslationUnit
+ }
+ };
+
+ let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
+
+ unsafe {
+ let typeid = llvm::LLVMMDStringInContext(
+ cx.llcx,
+ trait_ref_typeid.as_ptr() as *const c_char,
+ trait_ref_typeid.as_bytes().len() as c_uint,
+ );
+ let v = [cx.const_usize(0), typeid];
+ llvm::LLVMRustGlobalAddMetadata(
+ vtable,
+ llvm::MD_type as c_uint,
+ llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+ cx.llcx,
+ v.as_ptr(),
+ v.len() as c_uint,
+ )),
+ );
+ let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64));
+ let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1);
+ llvm::LLVMGlobalSetMetadata(
+ vtable,
+ llvm::MetadataType::MD_vcall_visibility as c_uint,
+ vcall_visibility_metadata,
+ );
+ }
+}
+
/// Creates debug information for the given vtable, which is for the
/// given type.
///
@@ -1450,6 +1557,12 @@
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
vtable: &'ll Value,
) {
+ // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in
+ // LLVM at the moment.
+ if cx.sess().opts.debugging_opts.virtual_function_elimination && cx.sess().lto() == Lto::Fat {
+ vcall_visibility_metadata(cx, ty, poly_trait_ref, vtable);
+ }
+
if cx.dbg_cx.is_none() {
return;
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 6a16455..71699b5 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -31,14 +31,14 @@
use rustc_session::config::{self, DebugInfo};
use rustc_session::Session;
use rustc_span::symbol::Symbol;
-use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, Span};
+use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span};
use rustc_target::abi::Size;
use libc::c_uint;
use smallvec::SmallVec;
+use std::cell::OnceCell;
use std::cell::RefCell;
use std::iter;
-use std::lazy::OnceCell;
use tracing::debug;
mod create_scope_map;
@@ -61,7 +61,7 @@
llcontext: &'ll llvm::Context,
llmod: &'ll llvm::Module,
builder: &'ll mut DIBuilder<'ll>,
- created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'ll DIFile>>,
+ created_files: RefCell<FxHashMap<Option<(u128, SourceFileHash)>, &'ll DIFile>>,
type_map: metadata::TypeMap<'ll, 'tcx>,
namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 4407297..9f36474 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -406,6 +406,16 @@
self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
}
+ fn type_checked_load(
+ &mut self,
+ llvtable: &'ll Value,
+ vtable_byte_offset: u64,
+ typeid: &'ll Value,
+ ) -> Self::Value {
+ let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
+ self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid])
+ }
+
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
self.call_intrinsic("llvm.va_start", &[va_list])
}
@@ -431,7 +441,7 @@
bx.store(bx.const_i32(0), dest, ret_align);
} else if wants_msvc_seh(bx.sess()) {
codegen_msvc_try(bx, try_func, data, catch_func, dest);
- } else if bx.sess().target.is_like_emscripten {
+ } else if bx.sess().target.os == "emscripten" {
codegen_emcc_try(bx, try_func, data, catch_func, dest);
} else {
codegen_gnu_try(bx, try_func, data, catch_func, dest);
@@ -816,7 +826,7 @@
span: Span,
) -> Result<&'ll Value, ()> {
// macros for error handling:
- #[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
+ #[allow(unused_macro_rules)]
macro_rules! emit_error {
($msg: tt) => {
emit_error!($msg, )
@@ -1145,7 +1155,7 @@
span: Span,
args: &[OperandRef<'tcx, &'ll Value>],
) -> Result<&'ll Value, ()> {
- #[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
+ #[allow(unused_macro_rules)]
macro_rules! emit_error {
($msg: tt) => {
emit_error!($msg, )
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 0bead46..6713a75 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -5,12 +5,10 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(crate_visibility_modifier)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(extern_types)]
#![feature(once_cell)]
-#![feature(nll)]
#![feature(iter_intersperse)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
@@ -305,8 +303,8 @@
local stack variable in the ABI.)
basic
- Generate stack canaries in functions with:
- - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
+ Generate stack canaries in functions with local variables of `[T; N]`
+ type, where `T` is byte-sized and `N` >= 8.
none
Do not generate stack canaries.
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 13baadd..b831423 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -381,9 +381,8 @@
impl AtomicOrdering {
pub fn from_generic(ao: rustc_codegen_ssa::common::AtomicOrdering) -> Self {
match ao {
- rustc_codegen_ssa::common::AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic,
rustc_codegen_ssa::common::AtomicOrdering::Unordered => AtomicOrdering::Unordered,
- rustc_codegen_ssa::common::AtomicOrdering::Monotonic => AtomicOrdering::Monotonic,
+ rustc_codegen_ssa::common::AtomicOrdering::Relaxed => AtomicOrdering::Monotonic,
rustc_codegen_ssa::common::AtomicOrdering::Acquire => AtomicOrdering::Acquire,
rustc_codegen_ssa::common::AtomicOrdering::Release => AtomicOrdering::Release,
rustc_codegen_ssa::common::AtomicOrdering::AcquireRelease => {
@@ -443,6 +442,7 @@
MD_nonnull = 11,
MD_align = 17,
MD_type = 19,
+ MD_vcall_visibility = 28,
MD_noundef = 29,
}
@@ -775,7 +775,7 @@
}
impl CounterMappingRegion {
- crate fn code_region(
+ pub(crate) fn code_region(
counter: coverage_map::Counter,
file_id: u32,
start_line: u32,
@@ -799,7 +799,7 @@
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
- crate fn branch_region(
+ pub(crate) fn branch_region(
counter: coverage_map::Counter,
false_counter: coverage_map::Counter,
file_id: u32,
@@ -824,7 +824,7 @@
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
- crate fn expansion_region(
+ pub(crate) fn expansion_region(
file_id: u32,
expanded_file_id: u32,
start_line: u32,
@@ -848,7 +848,7 @@
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
- crate fn skipped_region(
+ pub(crate) fn skipped_region(
file_id: u32,
start_line: u32,
start_col: u32,
@@ -871,7 +871,7 @@
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
- crate fn gap_region(
+ pub(crate) fn gap_region(
counter: coverage_map::Counter,
file_id: u32,
start_line: u32,
@@ -1068,6 +1068,7 @@
pub fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);
pub fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value);
pub fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
+ pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
// Operations on constants of any type
@@ -1081,6 +1082,11 @@
Vals: *const &'a Value,
Count: c_uint,
) -> &'a Value;
+ pub fn LLVMMDNodeInContext2<'a>(
+ C: &'a Context,
+ Vals: *const &'a Metadata,
+ Count: size_t,
+ ) -> &'a Metadata;
pub fn LLVMAddNamedMetadataOperand<'a>(M: &'a Module, Name: *const c_char, Val: &'a Value);
// Operations on scalar constants
@@ -1937,6 +1943,7 @@
name: *const c_char,
value: u32,
);
+ pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 7b407c9..ce6c6e3 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -218,15 +218,17 @@
sess: &Session,
features: &FxHashMap<&str, bool>,
) -> Option<&'static [&'static str]> {
- for tied in tied_target_features(sess) {
- // Tied features must be set to the same value, or not set at all
- let mut tied_iter = tied.iter();
- let enabled = features.get(tied_iter.next().unwrap());
- if tied_iter.any(|f| enabled != features.get(f)) {
- return Some(tied);
+ if !features.is_empty() {
+ for tied in tied_target_features(sess) {
+ // Tied features must be set to the same value, or not set at all
+ let mut tied_iter = tied.iter();
+ let enabled = features.get(tied_iter.next().unwrap());
+ if tied_iter.any(|f| enabled != features.get(f)) {
+ return Some(tied);
+ }
}
}
- None
+ return None;
}
// Used to generate cfg variables and apply features
@@ -440,6 +442,7 @@
// -Ctarget-features
let supported_features = supported_target_features(sess);
+ let mut featsmap = FxHashMap::default();
let feats = sess
.opts
.cg
@@ -485,35 +488,36 @@
}
diag.emit();
}
- Some((enable_disable, feature))
- })
- .collect::<SmallVec<[(char, &str); 8]>>();
- if diagnostics {
- // FIXME(nagisa): figure out how to not allocate a full hashset here.
- let featmap = feats.iter().map(|&(flag, feat)| (feat, flag == '+')).collect();
- if let Some(f) = check_tied_features(sess, &featmap) {
- sess.err(&format!(
- "target features {} must all be enabled or disabled together",
- f.join(", ")
- ));
- }
+ if diagnostics {
+ // FIXME(nagisa): figure out how to not allocate a full hashset here.
+ featsmap.insert(feature, enable_disable == '+');
+ }
+
+ // rustc-specific features do not get passed down to LLVM…
+ if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+ return None;
+ }
+ // ... otherwise though we run through `to_llvm_features` when
+ // passing requests down to LLVM. This means that all in-language
+ // features also work on the command line instead of having two
+ // different names when the LLVM name and the Rust name differ.
+ Some(
+ to_llvm_features(sess, feature)
+ .into_iter()
+ .map(move |f| format!("{}{}", enable_disable, f)),
+ )
+ })
+ .flatten();
+ features.extend(feats);
+
+ if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
+ sess.err(&format!(
+ "target features {} must all be enabled or disabled together",
+ f.join(", ")
+ ));
}
- features.extend(feats.into_iter().flat_map(|(enable_disable, feature)| {
- // rustc-specific features do not get passed down to LLVM…
- if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
- return SmallVec::<[_; 2]>::new();
- }
- // ... otherwise though we run through `to_llvm_features` when
- // passing requests down to LLVM. This means that all in-language
- // features also work on the command line instead of having two
- // different names when the LLVM name and the Rust name differ.
- to_llvm_features(sess, feature)
- .into_iter()
- .map(|f| format!("{}{}", enable_disable, f))
- .collect()
- }));
features
}
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 21b77f7..cf2d3c4 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -39,33 +39,33 @@
}
impl<'ll> CodegenCx<'ll, '_> {
- crate fn type_named_struct(&self, name: &str) -> &'ll Type {
+ pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type {
let name = SmallCStr::new(name);
unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
}
- crate fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
+ pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) }
}
- crate fn type_void(&self) -> &'ll Type {
+ pub(crate) fn type_void(&self) -> &'ll Type {
unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
}
- crate fn type_metadata(&self) -> &'ll Type {
+ pub(crate) fn type_metadata(&self) -> &'ll Type {
unsafe { llvm::LLVMRustMetadataTypeInContext(self.llcx) }
}
///x Creates an integer type with the given number of bits, e.g., i24
- crate fn type_ix(&self, num_bits: u64) -> &'ll Type {
+ pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type {
unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) }
}
- crate fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
+ pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
unsafe { llvm::LLVMVectorType(ty, len as c_uint) }
}
- crate fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
+ pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
unsafe {
let n_args = llvm::LLVMCountParamTypes(ty) as usize;
let mut args = Vec::with_capacity(n_args);
@@ -75,11 +75,11 @@
}
}
- crate fn type_bool(&self) -> &'ll Type {
+ pub(crate) fn type_bool(&self) -> &'ll Type {
self.type_i8()
}
- crate fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type {
+ pub(crate) fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type {
match t {
ty::IntTy::Isize => self.type_isize(),
ty::IntTy::I8 => self.type_i8(),
@@ -90,7 +90,7 @@
}
}
- crate fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type {
+ pub(crate) fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type {
match t {
ty::UintTy::Usize => self.type_isize(),
ty::UintTy::U8 => self.type_i8(),
@@ -101,14 +101,14 @@
}
}
- crate fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type {
+ pub(crate) fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type {
match t {
ty::FloatTy::F32 => self.type_f32(),
ty::FloatTy::F64 => self.type_f64(),
}
}
- crate fn type_pointee_for_align(&self, align: Align) -> &'ll Type {
+ pub(crate) fn type_pointee_for_align(&self, align: Align) -> &'ll Type {
// FIXME(eddyb) We could find a better approximation if ity.align < align.
let ity = Integer::approximate_align(self, align);
self.type_from_integer(ity)
@@ -116,7 +116,7 @@
/// Return a LLVM type that has at most the required alignment,
/// and exactly the required size, as a best-effort padding array.
- crate fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type {
+ pub(crate) fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type {
let unit = Integer::approximate_align(self, align);
let size = size.bytes();
let unit_size = unit.size().bytes();
@@ -124,11 +124,11 @@
self.type_array(self.type_from_integer(unit), size / unit_size)
}
- crate fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
+ pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
}
- crate fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
+ pub(crate) fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
unsafe { llvm::LLVMRustArrayType(ty, len) }
}
}