summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_ssa/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs206
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs30
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs36
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs40
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs709
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs444
-rw-r--r--compiler/rustc_codegen_ssa/src/glue.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs74
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs140
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs76
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs165
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs1
24 files changed, 1686 insertions, 307 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 58558fb8c..d3cd085cf 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -124,7 +124,7 @@ fn try_filter_fat_archs(
) -> io::Result<Option<PathBuf>> {
let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
- let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
+ let desired = match archs.iter().find(|a| a.architecture() == target_arch) {
Some(a) => a,
None => return Ok(None),
};
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index fe2e4b36c..34e042376 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library;
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -208,16 +208,16 @@ pub fn link_binary<'a>(
Ok(())
}
+// Crate type is not passed when calculating the dylibs to include for LTO. In that case all
+// crate types must use the same dependency formats.
pub fn each_linked_rlib(
- sess: &Session,
info: &CrateInfo,
+ crate_type: Option<CrateType>,
f: &mut dyn FnMut(CrateNum, &Path),
) -> Result<(), errors::LinkRlibError> {
let crates = info.used_crates.iter();
- let mut fmts = None;
- let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
- if lto_active {
+ let fmts = if crate_type.is_none() {
for combination in info.dependency_formats.iter().combinations(2) {
let (ty1, list1) = &combination[0];
let (ty2, list2) = &combination[1];
@@ -230,27 +230,23 @@ pub fn each_linked_rlib(
});
}
}
- }
-
- for (ty, list) in info.dependency_formats.iter() {
- match ty {
- CrateType::Executable
- | CrateType::Staticlib
- | CrateType::Cdylib
- | CrateType::ProcMacro => {
- fmts = Some(list);
- break;
- }
- CrateType::Dylib if lto_active => {
- fmts = Some(list);
- break;
- }
- _ => {}
+ if info.dependency_formats.is_empty() {
+ return Err(errors::LinkRlibError::MissingFormat);
}
- }
- let Some(fmts) = fmts else {
- return Err(errors::LinkRlibError::MissingFormat);
+ &info.dependency_formats[0].1
+ } else {
+ let fmts = info
+ .dependency_formats
+ .iter()
+ .find_map(|&(ty, ref list)| if Some(ty) == crate_type { Some(list) } else { None });
+
+ let Some(fmts) = fmts else {
+ return Err(errors::LinkRlibError::MissingFormat);
+ };
+
+ fmts
};
+
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
@@ -449,7 +445,7 @@ fn link_rlib<'a>(
/// Extract all symbols defined in raw-dylib libraries, collated by library name.
///
/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
-/// then the CodegenResults value contains one NativeLib instance for each block. However, the
+/// then the CodegenResults value contains one NativeLib instance for each block. However, the
/// linker appears to expect only a single import library for each library used, so we need to
/// collate the symbols together by library name before generating the import libraries.
fn collate_raw_dylibs<'a, 'b>(
@@ -516,64 +512,71 @@ fn link_staticlib<'a>(
)?;
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| {
- matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
- && !relevant_lib(sess, lib)
- });
+ let res = each_linked_rlib(
+ &codegen_results.crate_info,
+ Some(CrateType::Staticlib),
+ &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| {
+ matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+ && !relevant_lib(sess, lib)
+ });
- let lto = are_upstream_rust_objects_already_included(sess)
- && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
+ let lto = are_upstream_rust_objects_already_included(sess)
+ && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
- // Ignoring obj file starting with the crate name
- // as simple comparison is not enough - there
- // might be also an extra name suffix
- let obj_start = name.as_str().to_owned();
+ // Ignoring obj file starting with the crate name
+ // as simple comparison is not enough - there
+ // might be also an extra name suffix
+ let obj_start = name.as_str().to_owned();
- ab.add_archive(
- path,
- Box::new(move |fname: &str| {
- // Ignore metadata files, no matter the name.
- if fname == METADATA_FILENAME {
- return true;
- }
+ ab.add_archive(
+ path,
+ Box::new(move |fname: &str| {
+ // Ignore metadata files, no matter the name.
+ if fname == METADATA_FILENAME {
+ return true;
+ }
- // Don't include Rust objects if LTO is enabled
- if lto && looks_like_rust_object_file(fname) {
- return true;
- }
+ // Don't include Rust objects if LTO is enabled
+ if lto && looks_like_rust_object_file(fname) {
+ return true;
+ }
- // Otherwise if this is *not* a rust object and we're skipping
- // objects then skip this file
- if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
- return true;
- }
+ // Otherwise if this is *not* a rust object and we're skipping
+ // objects then skip this file
+ if skip_object_files
+ && (!fname.starts_with(&obj_start) || !fname.ends_with(".o"))
+ {
+ return true;
+ }
- // ok, don't skip this
- false
- }),
- )
- .unwrap();
+ // ok, don't skip this
+ false
+ }),
+ )
+ .unwrap();
- all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
- });
+ all_native_libs
+ .extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
+ },
+ );
if let Err(e) = res {
sess.emit_fatal(e);
}
@@ -607,21 +610,21 @@ fn link_dwarf_object<'a>(
}
impl<Relocations> ThorinSession<Relocations> {
- fn alloc_mmap<'arena>(&'arena self, data: Mmap) -> &'arena Mmap {
+ fn alloc_mmap(&self, data: Mmap) -> &Mmap {
(*self.arena_mmap.alloc(data)).borrow()
}
}
impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
- fn alloc_data<'arena>(&'arena self, data: Vec<u8>) -> &'arena [u8] {
+ fn alloc_data(&self, data: Vec<u8>) -> &[u8] {
(*self.arena_data.alloc(data)).borrow()
}
- fn alloc_relocation<'arena>(&'arena self, data: Relocations) -> &'arena Relocations {
+ fn alloc_relocation(&self, data: Relocations) -> &Relocations {
(*self.arena_relocations.alloc(data)).borrow()
}
- fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]> {
+ fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {
let file = File::open(&path)?;
let mmap = (unsafe { Mmap::map(file) })?;
Ok(self.alloc_mmap(mmap))
@@ -722,7 +725,7 @@ fn link_natively<'a>(
linker::disable_localization(&mut cmd);
- for &(ref k, ref v) in sess.target.link_env.as_ref() {
+ for (k, v) in sess.target.link_env.as_ref() {
cmd.env(k.as_ref(), v.as_ref());
}
for k in sess.target.link_env_remove.as_ref() {
@@ -1194,7 +1197,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
if cfg!(any(target_os = "solaris", target_os = "illumos")) {
// On historical Solaris systems, "cc" may have
// been Sun Studio, which is not flag-compatible
- // with "gcc". This history casts a long shadow,
+ // with "gcc". This history casts a long shadow,
// and many modern illumos distributions today
// ship GCC as "gcc" without also making it
// available as "cc".
@@ -1228,12 +1231,23 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
sess.emit_fatal(errors::LinkerFileStem);
});
+ // Remove any version postfix.
+ let stem = stem
+ .rsplit_once('-')
+ .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
+ .unwrap_or(stem);
+
+ // GCC/Clang can have an optional target prefix.
let flavor = if stem == "emcc" {
LinkerFlavor::EmCc
} else if stem == "gcc"
|| stem.ends_with("-gcc")
+ || stem == "g++"
+ || stem.ends_with("-g++")
|| stem == "clang"
|| stem.ends_with("-clang")
+ || stem == "clang++"
+ || stem.ends_with("-clang++")
{
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
@@ -1354,7 +1368,8 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
if !lib_args.is_empty() {
sess.emit_note(errors::StaticLibraryNativeArtifacts);
// Prefix for greppability
- sess.emit_note(errors::NativeStaticLibs { arguments: lib_args.join(" ") });
+ // Note: This must not be translated as tools are allowed to depend on this exact string.
+ sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" ")));
}
}
@@ -2612,7 +2627,7 @@ fn add_static_crate<'a>(
sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
let mut archive = archive_builder_builder.new_archive_builder(sess);
- if let Err(e) = archive.add_archive(
+ if let Err(error) = archive.add_archive(
cratepath,
Box::new(move |f| {
if f == METADATA_FILENAME {
@@ -2652,7 +2667,7 @@ fn add_static_crate<'a>(
false
}),
) {
- sess.fatal(&format!("failed to build archive from rlib: {}", e));
+ sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
}
if archive.build(&dst) {
link_upstream(&dst);
@@ -2822,11 +2837,30 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
// Implement the "linker flavor" part of -Zgcc-ld
// by asking cc to use some kind of lld.
cmd.arg("-fuse-ld=lld");
+
if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
- cmd.arg(format!("--target={}", sess.target.llvm_target));
+ //
+ // Note that we don't want to do that by default on macOS: e.g. passing a
+ // 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
+ // shown in issue #101653 and the discussion in PR #101792.
+ //
+ // It could be required in some cases of cross-compiling with
+ // `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
+ // which specific versions of clang, macOS SDK, host and target OS
+ // combinations impact us here.
+ //
+ // So we do a simple first-approximation until we know more of what the
+ // Apple targets require (and which would be handled prior to hitting this
+ // `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
+ // this should be manually passed if needed. We specify the target when
+ // targeting a different linker flavor on macOS, and that's also always
+ // the case when targeting WASM.
+ if sess.target.linker_flavor != sess.host.linker_flavor {
+ cmd.arg(format!("--target={}", sess.target.llvm_target));
+ }
}
}
}
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index f087d903e..eaf1e9817 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -108,7 +108,7 @@ pub fn get_linker<'a>(
if sess.target.is_like_msvc {
if let Some(ref tool) = msvc_tool {
cmd.args(tool.args());
- for &(ref k, ref v) in tool.env() {
+ for (k, v) in tool.env() {
if k == "PATH" {
new_path.extend(env::split_paths(v));
msvc_changed_path = true;
@@ -544,7 +544,7 @@ impl<'a> Linker for GccLinker<'a> {
// link times negatively.
//
// -dead_strip can't be part of the pre_link_args because it's also used
- // for partial linking when using multiple codegen units (-r). So we
+ // for partial linking when using multiple codegen units (-r). So we
// insert it here.
if self.sess.target.is_like_osx {
self.linker_arg("-dead_strip");
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 51c5c375d..7d3c14fec 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -100,7 +100,13 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};
let architecture = match &sess.target.arch[..] {
"arm" => Architecture::Arm,
- "aarch64" => Architecture::Aarch64,
+ "aarch64" => {
+ if sess.target.pointer_width == 32 {
+ Architecture::Aarch64_Ilp32
+ } else {
+ Architecture::Aarch64
+ }
+ }
"x86" => Architecture::I386,
"s390x" => Architecture::S390x,
"mips" => Architecture::Mips,
@@ -165,11 +171,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};
e_flags
}
- Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
- // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
- // that the `+d` target feature represents whether the double
- // float abi is enabled.
- let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ Architecture::Riscv32 | Architecture::Riscv64 => {
+ // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
+ let mut e_flags: u32 = 0x0;
+ let features = &sess.target.options.features;
+ // Check if compressed is enabled
+ if features.contains("+c") {
+ e_flags |= elf::EF_RISCV_RVC;
+ }
+
+ // Select the appropriate floating-point ABI
+ if features.contains("+d") {
+ e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ } else if features.contains("+f") {
+ e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
+ } else {
+ e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
+ }
e_flags
}
_ => 0,
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 22f534d90..57a99e74c 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -163,21 +163,25 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b
tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
}
-fn exported_symbols_provider_local<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn exported_symbols_provider_local(
+ tcx: TyCtxt<'_>,
cnum: CrateNum,
-) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
+) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] {
assert_eq!(cnum, LOCAL_CRATE);
if !tcx.sess.opts.output_types.should_codegen() {
return &[];
}
- let mut symbols: Vec<_> = tcx
- .reachable_non_generics(LOCAL_CRATE)
- .iter()
- .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
- .collect();
+ // FIXME: Sorting this is unnecessary since we are sorting later anyway.
+ // Can we skip the later sorting?
+ let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| {
+ tcx.reachable_non_generics(LOCAL_CRATE)
+ .to_sorted(&hcx, true)
+ .into_iter()
+ .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
+ .collect()
+ });
if tcx.entry_fn(()).is_some() {
let exported_symbol =
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 12fca6496..9f1614af7 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -105,7 +105,7 @@ pub struct ModuleConfig {
pub emit_thin_lto: bool,
pub bc_cmdline: String,
- // Miscellaneous flags. These are mostly copied from command-line
+ // Miscellaneous flags. These are mostly copied from command-line
// options.
pub verify_llvm_ir: bool,
pub no_prepopulate_passes: bool,
@@ -538,7 +538,7 @@ fn produce_final_output_artifacts(
let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| {
if compiled_modules.modules.len() == 1 {
- // 1) Only one codegen unit. In this case it's no difficulty
+ // 1) Only one codegen unit. In this case it's no difficulty
// to copy `foo.0.x` to `foo.x`.
let module_name = Some(&compiled_modules.modules[0].name[..]);
let path = crate_output.temp_path(output_type, module_name);
@@ -557,15 +557,15 @@ fn produce_final_output_artifacts(
.to_owned();
if crate_output.outputs.contains_key(&output_type) {
- // 2) Multiple codegen units, with `--emit foo=some_name`. We have
+ // 2) Multiple codegen units, with `--emit foo=some_name`. We have
// no good solution for this case, so warn the user.
sess.emit_warning(errors::IgnoringEmitPath { extension });
} else if crate_output.single_output_file.is_some() {
- // 3) Multiple codegen units, with `-o some_name`. We have
+ // 3) Multiple codegen units, with `-o some_name`. We have
// no good solution for this case, so warn the user.
sess.emit_warning(errors::IgnoringOutput { extension });
} else {
- // 4) Multiple codegen units, but no explicit name. We
+ // 4) Multiple codegen units, but no explicit name. We
// just leave the `foo.0.x` files in place.
// (We don't have to do any work in this case.)
}
@@ -579,7 +579,7 @@ fn produce_final_output_artifacts(
match *output_type {
OutputType::Bitcode => {
user_wants_bitcode = true;
- // Copy to .bc, but always keep the .0.bc. There is a later
+ // Copy to .bc, but always keep the .0.bc. There is a later
// check to figure out if we should delete .0.bc files, or keep
// them for making an rlib.
copy_if_one_unit(OutputType::Bitcode, true);
@@ -611,7 +611,7 @@ fn produce_final_output_artifacts(
// `-C save-temps` or `--emit=` flags).
if !sess.opts.cg.save_temps {
- // Remove the temporary .#module-name#.o objects. If the user didn't
+ // Remove the temporary .#module-name#.o objects. If the user didn't
// explicitly request bitcode (with --emit=bc), and the bitcode is not
// needed for building an rlib, then we must remove .#module-name#.bc as
// well.
@@ -1002,7 +1002,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
let sess = tcx.sess;
let mut each_linked_rlib_for_lto = Vec::new();
- drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
+ drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
if link::ignored_for_lto(sess, crate_info, cnum) {
return;
}
@@ -1098,7 +1098,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// There are a few environmental pre-conditions that shape how the system
// is set up:
//
- // - Error reporting only can happen on the main thread because that's the
+ // - Error reporting can only happen on the main thread because that's the
// only place where we have access to the compiler `Session`.
// - LLVM work can be done on any thread.
// - Codegen can only happen on the main thread.
@@ -1110,16 +1110,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
// Error Reporting
// ===============
// The error reporting restriction is handled separately from the rest: We
- // set up a `SharedEmitter` the holds an open channel to the main thread.
+ // set up a `SharedEmitter` that holds an open channel to the main thread.
// When an error occurs on any thread, the shared emitter will send the
// error message to the receiver main thread (`SharedEmitterMain`). The
// main thread will periodically query this error message queue and emit
// any error messages it has received. It might even abort compilation if
- // has received a fatal error. In this case we rely on all other threads
+ // it has received a fatal error. In this case we rely on all other threads
// being torn down automatically with the main thread.
// Since the main thread will often be busy doing codegen work, error
// reporting will be somewhat delayed, since the message queue can only be
- // checked in between to work packages.
+ // checked in between two work packages.
//
// Work Processing Infrastructure
// ==============================
@@ -1133,7 +1133,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// thread about what work to do when, and it will spawn off LLVM worker
// threads as open LLVM WorkItems become available.
//
- // The job of the main thread is to codegen CGUs into LLVM work package
+ // The job of the main thread is to codegen CGUs into LLVM work packages
// (since the main thread is the only thread that can do this). The main
// thread will block until it receives a message from the coordinator, upon
// which it will codegen one CGU, send it to the coordinator and block
@@ -1142,10 +1142,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
//
// The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is
// available, it will spawn off a new LLVM worker thread and let it process
- // that a WorkItem. When a LLVM worker thread is done with its WorkItem,
+ // a WorkItem. When a LLVM worker thread is done with its WorkItem,
// it will just shut down, which also frees all resources associated with
// the given LLVM module, and sends a message to the coordinator that the
- // has been completed.
+ // WorkItem has been completed.
//
// Work Scheduling
// ===============
@@ -1165,7 +1165,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
//
// Doing LLVM Work on the Main Thread
// ----------------------------------
- // Since the main thread owns the compiler processes implicit `Token`, it is
+ // Since the main thread owns the compiler process's implicit `Token`, it is
// wasteful to keep it blocked without doing any work. Therefore, what we do
// in this case is: We spawn off an additional LLVM worker thread that helps
// reduce the queue. The work it is doing corresponds to the implicit
@@ -1216,7 +1216,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// ------------------------------
//
// The final job the coordinator thread is responsible for is managing LTO
- // and how that works. When LTO is requested what we'll to is collect all
+ // and how that works. When LTO is requested what we'll do is collect all
// optimized LLVM modules into a local vector on the coordinator. Once all
// modules have been codegened and optimized we hand this to the `lto`
// module for further optimization. The `lto` module will return back a list
@@ -1899,7 +1899,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
// FIXME: time_llvm_passes support - does this use a global context or
// something?
- if sess.codegen_units() == 1 && sess.time_llvm_passes() {
+ if sess.codegen_units() == 1 && sess.opts.unstable_opts.time_llvm_passes {
self.backend.print_pass_timings()
}
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 4f396e970..32d3cfe6f 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -5,6 +5,7 @@ use crate::back::write::{
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
};
use crate::common::{IntPredicate, RealPredicate, TypeKind};
+use crate::errors;
use crate::meth;
use crate::mir;
use crate::mir::operand::OperandValue;
@@ -41,7 +42,6 @@ use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
use rustc_target::abi::{Align, Size, VariantIdx};
use std::collections::BTreeSet;
-use std::convert::TryFrom;
use std::time::{Duration, Instant};
use itertools::Itertools;
@@ -153,9 +153,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
(
&ty::Dynamic(ref data_a, _, src_dyn_kind),
&ty::Dynamic(ref data_b, _, target_dyn_kind),
- ) => {
- assert_eq!(src_dyn_kind, target_dyn_kind);
-
+ ) if src_dyn_kind == target_dyn_kind => {
let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
if data_a.principal_def_id() == data_b.principal_def_id() {
@@ -452,10 +450,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let Some(llfn) = cx.declare_c_main(llfty) else {
// FIXME: We should be smart and show a better diagnostic here.
let span = cx.tcx().def_span(rust_main_def_id);
- cx.sess()
- .struct_span_err(span, "entry symbol `main` declared multiple times")
- .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
- .emit();
+ cx.sess().emit_err(errors::MultipleMainFunctions { span });
cx.sess().abort_if_errors();
bug!();
};
@@ -596,8 +591,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
&metadata,
&exported_symbols::metadata_symbol_name(tcx),
);
- if let Err(err) = std::fs::write(&file_name, data) {
- tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
+ if let Err(error) = std::fs::write(&file_name, data) {
+ tcx.sess.emit_fatal(errors::MetadataObjectFileWrite { error });
}
Some(CompiledModule {
name: metadata_cgu_name,
@@ -682,7 +677,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
});
let mut total_codegen_time = Duration::new(0, 0);
- let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size());
+ let start_rss = tcx.sess.opts.unstable_opts.time_passes.then(|| get_resident_set_size());
// The non-parallel compiler can only translate codegen units to LLVM IR
// on a single thread, leading to a staircase effect where the N LLVM
@@ -782,7 +777,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// Since the main thread is sometimes blocked during codegen, we keep track
// -Ztime-passes output manually.
- if tcx.sess.time_passes() {
+ if tcx.sess.opts.unstable_opts.time_passes {
let end_rss = get_resident_set_size();
print_time_passes_entry(
@@ -816,11 +811,7 @@ impl CrateInfo {
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
let windows_subsystem = subsystem.map(|subsystem| {
if subsystem != sym::windows && subsystem != sym::console {
- tcx.sess.fatal(&format!(
- "invalid windows subsystem `{}`, only \
- `windows` and `console` are allowed",
- subsystem
- ));
+ tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
}
subsystem.to_string()
});
@@ -973,16 +964,19 @@ pub fn provide(providers: &mut Providers) {
};
let (defids, _) = tcx.collect_and_partition_mono_items(cratenum);
- for id in &*defids {
+
+ let any_for_speed = defids.items().any(|id| {
let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
match optimize {
- attr::OptimizeAttr::None => continue,
- attr::OptimizeAttr::Size => continue,
- attr::OptimizeAttr::Speed => {
- return for_speed;
- }
+ attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
+ attr::OptimizeAttr::Speed => true,
}
+ });
+
+ if any_for_speed {
+ return for_speed;
}
+
tcx.sess.opts.optimize
};
}
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
new file mode 100644
index 000000000..8808ad2dc
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -0,0 +1,709 @@
+use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
+use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
+use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::mir::mono::Linkage;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self as ty, DefIdTree, TyCtxt};
+use rustc_session::{lint, parse::feature_err};
+use rustc_span::{sym, Span};
+use rustc_target::spec::{abi, SanitizerSet};
+
+use crate::target_features::from_target_feature;
+use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
+
+fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
+ use rustc_middle::mir::mono::Linkage::*;
+
+ // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
+ // applicable to variable declarations and may not really make sense for
+ // Rust code in the first place but allow them anyway and trust that the
+ // user knows what they're doing. Who knows, unanticipated use cases may pop
+ // up in the future.
+ //
+ // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
+ // and don't have to be, LLVM treats them as no-ops.
+ match name {
+ "appending" => Appending,
+ "available_externally" => AvailableExternally,
+ "common" => Common,
+ "extern_weak" => ExternalWeak,
+ "external" => External,
+ "internal" => Internal,
+ "linkonce" => LinkOnceAny,
+ "linkonce_odr" => LinkOnceODR,
+ "private" => Private,
+ "weak" => WeakAny,
+ "weak_odr" => WeakODR,
+ _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
+ }
+}
+
+fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
+ if cfg!(debug_assertions) {
+ let def_kind = tcx.def_kind(did);
+ assert!(
+ def_kind.has_codegen_attrs(),
+ "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
+ );
+ }
+
+ let did = did.expect_local();
+ let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
+ let mut codegen_fn_attrs = CodegenFnAttrs::new();
+ if tcx.should_inherit_track_caller(did) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
+ }
+
+ let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
+
+ // In some cases, attribute are only valid on functions, but it's the `check_attr`
+ // pass that check that they aren't used anywhere else, rather this module.
+ // In these cases, we bail from performing further checks that are only meaningful for
+ // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
+ // report a delayed bug, just in case `check_attr` isn't doing its job.
+ let validate_fn_only_attr = |attr_sp| -> bool {
+ let def_kind = tcx.def_kind(did);
+ if let DefKind::Fn | DefKind::AssocFn | DefKind::Variant | DefKind::Ctor(..) = def_kind {
+ true
+ } else {
+ tcx.sess.delay_span_bug(attr_sp, "this attribute can only be applied to functions");
+ false
+ }
+ };
+
+ let mut inline_span = None;
+ let mut link_ordinal_span = None;
+ let mut no_sanitize_span = None;
+ for attr in attrs.iter() {
+ if attr.has_name(sym::cold) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
+ } else if attr.has_name(sym::rustc_allocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
+ } else if attr.has_name(sym::ffi_returns_twice) {
+ if tcx.is_foreign_item(did) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
+ } else {
+ // `#[ffi_returns_twice]` is only allowed `extern fn`s.
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0724,
+ "`#[ffi_returns_twice]` may only be used on foreign functions"
+ )
+ .emit();
+ }
+ } else if attr.has_name(sym::ffi_pure) {
+ if tcx.is_foreign_item(did) {
+ if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
+ // `#[ffi_const]` functions cannot be `#[ffi_pure]`
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0757,
+ "`#[ffi_const]` function cannot be `#[ffi_pure]`"
+ )
+ .emit();
+ } else {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
+ }
+ } else {
+ // `#[ffi_pure]` is only allowed on foreign functions
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0755,
+ "`#[ffi_pure]` may only be used on foreign functions"
+ )
+ .emit();
+ }
+ } else if attr.has_name(sym::ffi_const) {
+ if tcx.is_foreign_item(did) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
+ } else {
+ // `#[ffi_const]` is only allowed on foreign functions
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0756,
+ "`#[ffi_const]` may only be used on foreign functions"
+ )
+ .emit();
+ }
+ } else if attr.has_name(sym::rustc_nounwind) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ } else if attr.has_name(sym::rustc_reallocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
+ } else if attr.has_name(sym::rustc_deallocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
+ } else if attr.has_name(sym::rustc_allocator_zeroed) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
+ } else if attr.has_name(sym::naked) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
+ } else if attr.has_name(sym::no_mangle) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+ } else if attr.has_name(sym::no_coverage) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+ } else if attr.has_name(sym::rustc_std_internal_symbol) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+ } else if attr.has_name(sym::used) {
+ let inner = attr.meta_item_list();
+ match inner.as_deref() {
+ Some([item]) if item.has_name(sym::linker) => {
+ if !tcx.features().used_with_arg {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::used_with_arg,
+ attr.span,
+ "`#[used(linker)]` is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
+ }
+ Some([item]) if item.has_name(sym::compiler) => {
+ if !tcx.features().used_with_arg {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::used_with_arg,
+ attr.span,
+ "`#[used(compiler)]` is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+ }
+ Some(_) => {
+ tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
+ }
+ None => {
+ // Unfortunately, unconditionally using `llvm.used` causes
+ // issues in handling `.init_array` with the gold linker,
+ // but using `llvm.compiler.used` caused a nontrival amount
+ // of unintentional ecosystem breakage -- particularly on
+ // Mach-O targets.
+ //
+ // As a result, we emit `llvm.compiler.used` only on ELF
+ // targets. This is somewhat ad-hoc, but actually follows
+ // our pre-LLVM 13 behavior (prior to the ecosystem
+ // breakage), and seems to match `clang`'s behavior as well
+ // (both before and after LLVM 13), possibly because they
+ // have similar compatibility concerns to us. See
+ // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
+ // and following comments for some discussion of this, as
+ // well as the comments in `rustc_codegen_llvm` where these
+ // flags are handled.
+ //
+ // Anyway, to be clear: this is still up in the air
+ // somewhat, and is subject to change in the future (which
+ // is a good thing, because this would ideally be a bit
+ // more firmed up).
+ let is_like_elf = !(tcx.sess.target.is_like_osx
+ || tcx.sess.target.is_like_windows
+ || tcx.sess.target.is_like_wasm);
+ codegen_fn_attrs.flags |= if is_like_elf {
+ CodegenFnAttrFlags::USED
+ } else {
+ CodegenFnAttrFlags::USED_LINKER
+ };
+ }
+ }
+ } else if attr.has_name(sym::cmse_nonsecure_entry) {
+ if validate_fn_only_attr(attr.span)
+ && !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. })
+ {
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0776,
+ "`#[cmse_nonsecure_entry]` requires C ABI"
+ )
+ .emit();
+ }
+ if !tcx.sess.target.llvm_target.contains("thumbv8m") {
+ struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
+ } else if attr.has_name(sym::thread_local) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
+ } else if attr.has_name(sym::track_caller) {
+ if !tcx.is_closure(did.to_def_id())
+ && validate_fn_only_attr(attr.span)
+ && tcx.fn_sig(did).abi() != abi::Abi::Rust
+ {
+ struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
+ .emit();
+ }
+ if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::closure_track_caller,
+ attr.span,
+ "`#[track_caller]` on closures is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
+ } else if attr.has_name(sym::export_name) {
+ if let Some(s) = attr.value_str() {
+ if s.as_str().contains('\0') {
+ // `#[export_name = ...]` will be converted to a null-terminated string,
+ // so it may not contain any null characters.
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0648,
+ "`export_name` may not contain null characters"
+ )
+ .emit();
+ }
+ codegen_fn_attrs.export_name = Some(s);
+ }
+ } else if attr.has_name(sym::target_feature) {
+ if !tcx.is_closure(did.to_def_id())
+ && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
+ {
+ if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
+ // The `#[target_feature]` attribute is allowed on
+ // WebAssembly targets on all functions, including safe
+ // ones. Other targets require that `#[target_feature]` is
+ // only applied to unsafe functions (pending the
+ // `target_feature_11` feature) because on most targets
+ // execution of instructions that are not supported is
+ // considered undefined behavior. For WebAssembly which is a
+ // 100% safe target at execution time it's not possible to
+ // execute undefined instructions, and even if a future
+ // feature was added in some form for this it would be a
+ // deterministic trap. There is no undefined behavior when
+ // executing WebAssembly so `#[target_feature]` is allowed
+ // on safe functions (but again, only for WebAssembly)
+ //
+ // Note that this is also allowed if `actually_rustdoc` so
+ // if a target is documenting some wasm-specific code then
+ // it's not spuriously denied.
+ } else if !tcx.features().target_feature_11 {
+ let mut err = feature_err(
+ &tcx.sess.parse_sess,
+ sym::target_feature_11,
+ attr.span,
+ "`#[target_feature(..)]` can only be applied to `unsafe` functions",
+ );
+ err.span_label(tcx.def_span(did), "not an `unsafe` function");
+ err.emit();
+ } else {
+ check_target_feature_trait_unsafe(tcx, did, attr.span);
+ }
+ }
+ from_target_feature(
+ tcx,
+ attr,
+ supported_target_features,
+ &mut codegen_fn_attrs.target_features,
+ );
+ } else if attr.has_name(sym::linkage) {
+ if let Some(val) = attr.value_str() {
+ let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
+ if tcx.is_foreign_item(did) {
+ codegen_fn_attrs.import_linkage = linkage;
+ } else {
+ codegen_fn_attrs.linkage = linkage;
+ }
+ }
+ } else if attr.has_name(sym::link_section) {
+ if let Some(val) = attr.value_str() {
+ if val.as_str().bytes().any(|b| b == 0) {
+ let msg = format!(
+ "illegal null byte in link_section \
+ value: `{}`",
+ &val
+ );
+ tcx.sess.span_err(attr.span, &msg);
+ } else {
+ codegen_fn_attrs.link_section = Some(val);
+ }
+ }
+ } else if attr.has_name(sym::link_name) {
+ codegen_fn_attrs.link_name = attr.value_str();
+ } else if attr.has_name(sym::link_ordinal) {
+ link_ordinal_span = Some(attr.span);
+ if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
+ codegen_fn_attrs.link_ordinal = ordinal;
+ }
+ } else if attr.has_name(sym::no_sanitize) {
+ no_sanitize_span = Some(attr.span);
+ if let Some(list) = attr.meta_item_list() {
+ for item in list.iter() {
+ if item.has_name(sym::address) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
+ } else if item.has_name(sym::cfi) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
+ } else if item.has_name(sym::kcfi) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
+ } else if item.has_name(sym::memory) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
+ } else if item.has_name(sym::memtag) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
+ } else if item.has_name(sym::shadow_call_stack) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
+ } else if item.has_name(sym::thread) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
+ } else if item.has_name(sym::hwaddress) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
+ } else {
+ tcx.sess
+ .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
+ .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
+ .emit();
+ }
+ }
+ }
+ } else if attr.has_name(sym::instruction_set) {
+ codegen_fn_attrs.instruction_set = match attr.meta_kind() {
+ Some(MetaItemKind::List(ref items)) => match items.as_slice() {
+ [NestedMetaItem::MetaItem(set)] => {
+ let segments =
+ set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+ match segments.as_slice() {
+ [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
+ if !tcx.sess.target.has_thumb_interworking {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0779,
+ "target does not support `#[instruction_set]`"
+ )
+ .emit();
+ None
+ } else if segments[1] == sym::a32 {
+ Some(InstructionSetAttr::ArmA32)
+ } else if segments[1] == sym::t32 {
+ Some(InstructionSetAttr::ArmT32)
+ } else {
+ unreachable!()
+ }
+ }
+ _ => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0779,
+ "invalid instruction set specified",
+ )
+ .emit();
+ None
+ }
+ }
+ }
+ [] => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0778,
+ "`#[instruction_set]` requires an argument"
+ )
+ .emit();
+ None
+ }
+ _ => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0779,
+ "cannot specify more than one instruction set"
+ )
+ .emit();
+ None
+ }
+ },
+ _ => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0778,
+ "must specify an instruction set"
+ )
+ .emit();
+ None
+ }
+ };
+ } else if attr.has_name(sym::repr) {
+ codegen_fn_attrs.alignment = match attr.meta_item_list() {
+ Some(items) => match items.as_slice() {
+ [item] => match item.name_value_literal() {
+ Some((sym::align, literal)) => {
+ let alignment = rustc_attr::parse_alignment(&literal.kind);
+
+ match alignment {
+ Ok(align) => Some(align),
+ Err(msg) => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0589,
+ "invalid `repr(align)` attribute: {}",
+ msg
+ )
+ .emit();
+
+ None
+ }
+ }
+ }
+ _ => None,
+ },
+ [] => None,
+ _ => None,
+ },
+ None => None,
+ };
+ }
+ }
+
+ codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
+ if !attr.has_name(sym::inline) {
+ return ia;
+ }
+ match attr.meta_kind() {
+ Some(MetaItemKind::Word) => InlineAttr::Hint,
+ Some(MetaItemKind::List(ref items)) => {
+ inline_span = Some(attr.span);
+ if items.len() != 1 {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0534,
+ "expected one argument"
+ )
+ .emit();
+ InlineAttr::None
+ } else if list_contains_name(&items, sym::always) {
+ InlineAttr::Always
+ } else if list_contains_name(&items, sym::never) {
+ InlineAttr::Never
+ } else {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ items[0].span(),
+ E0535,
+ "invalid argument"
+ )
+ .help("valid inline arguments are `always` and `never`")
+ .emit();
+
+ InlineAttr::None
+ }
+ }
+ Some(MetaItemKind::NameValue(_)) => ia,
+ None => ia,
+ }
+ });
+
+ codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
+ if !attr.has_name(sym::optimize) {
+ return ia;
+ }
+ let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
+ match attr.meta_kind() {
+ Some(MetaItemKind::Word) => {
+ err(attr.span, "expected one argument");
+ ia
+ }
+ Some(MetaItemKind::List(ref items)) => {
+ inline_span = Some(attr.span);
+ if items.len() != 1 {
+ err(attr.span, "expected one argument");
+ OptimizeAttr::None
+ } else if list_contains_name(&items, sym::size) {
+ OptimizeAttr::Size
+ } else if list_contains_name(&items, sym::speed) {
+ OptimizeAttr::Speed
+ } else {
+ err(items[0].span(), "invalid argument");
+ OptimizeAttr::None
+ }
+ }
+ Some(MetaItemKind::NameValue(_)) => ia,
+ None => ia,
+ }
+ });
+
+ // #73631: closures inherit `#[target_feature]` annotations
+ if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
+ let owner_id = tcx.parent(did.to_def_id());
+ if tcx.def_kind(owner_id).has_codegen_attrs() {
+ codegen_fn_attrs
+ .target_features
+ .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
+ }
+ }
+
+ // If a function uses #[target_feature] it can't be inlined into general
+ // purpose functions as they wouldn't have the right target features
+ // enabled. For that reason we also forbid #[inline(always)] as it can't be
+ // respected.
+ if !codegen_fn_attrs.target_features.is_empty() {
+ if codegen_fn_attrs.inline == InlineAttr::Always {
+ if let Some(span) = inline_span {
+ tcx.sess.span_err(
+ span,
+ "cannot use `#[inline(always)]` with \
+ `#[target_feature]`",
+ );
+ }
+ }
+ }
+
+ if !codegen_fn_attrs.no_sanitize.is_empty() {
+ if codegen_fn_attrs.inline == InlineAttr::Always {
+ if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(did);
+ tcx.struct_span_lint_hir(
+ lint::builtin::INLINE_NO_SANITIZE,
+ hir_id,
+ no_sanitize_span,
+ "`no_sanitize` will have no effect after inlining",
+ |lint| lint.span_note(inline_span, "inlining requested here"),
+ )
+ }
+ }
+ }
+
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+ codegen_fn_attrs.inline = InlineAttr::Never;
+ }
+
+ // Weak lang items have the same semantics as "std internal" symbols in the
+ // sense that they're preserved through all our LTO passes and only
+ // strippable by the linker.
+ //
+ // Additionally weak lang items have predetermined symbol names.
+ if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+ }
+ if let Some((name, _)) = lang_items::extract(attrs)
+ && let Some(lang_item) = LangItem::from_name(name)
+ && let Some(link_name) = lang_item.link_name()
+ {
+ codegen_fn_attrs.export_name = Some(link_name);
+ codegen_fn_attrs.link_name = Some(link_name);
+ }
+ check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
+
+ // Internal symbols to the standard library all have no_mangle semantics in
+ // that they have defined symbol names present in the function name. This
+ // also applies to weak symbols where they all have known symbol names.
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+ }
+
+ // Any linkage to LLVM intrinsics for now forcibly marks them all as never
+ // unwinds since LLVM sometimes can't handle codegen which `invoke`s
+ // intrinsic functions.
+ if let Some(name) = &codegen_fn_attrs.link_name {
+ if name.as_str().starts_with("llvm.") {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ }
+ }
+
+ codegen_fn_attrs
+}
+
+/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
+/// applied to the method prototype.
+fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ if let Some(impl_item) = tcx.opt_associated_item(def_id)
+ && let ty::AssocItemContainer::ImplContainer = impl_item.container
+ && let Some(trait_item) = impl_item.trait_item_def_id
+ {
+ return tcx
+ .codegen_fn_attrs(trait_item)
+ .flags
+ .intersects(CodegenFnAttrFlags::TRACK_CALLER);
+ }
+
+ false
+}
+
+fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
+ use rustc_ast::{LitIntType, LitKind, MetaItemLit};
+ if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::raw_dylib,
+ attr.span,
+ "`#[link_ordinal]` is unstable on x86",
+ )
+ .emit();
+ }
+ let meta_item_list = attr.meta_item_list();
+ let meta_item_list = meta_item_list.as_deref();
+ let sole_meta_list = match meta_item_list {
+ Some([item]) => item.lit(),
+ Some(_) => {
+ tcx.sess
+ .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
+ .note("the attribute requires exactly one argument")
+ .emit();
+ return None;
+ }
+ _ => None,
+ };
+ if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
+ sole_meta_list
+ {
+ // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
+ // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
+ // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
+ // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
+ //
+ // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
+ // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
+ // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
+ // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
+ // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
+ // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
+ // about LINK.EXE failing.)
+ if *ordinal <= u16::MAX as u128 {
+ Some(*ordinal as u16)
+ } else {
+ let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
+ tcx.sess
+ .struct_span_err(attr.span, &msg)
+ .note("the value may not exceed `u16::MAX`")
+ .emit();
+ None
+ }
+ } else {
+ tcx.sess
+ .struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
+ .note("an unsuffixed integer value, e.g., `1`, is expected")
+ .emit();
+ None
+ }
+}
+
+fn check_link_name_xor_ordinal(
+ tcx: TyCtxt<'_>,
+ codegen_fn_attrs: &CodegenFnAttrs,
+ inline_span: Option<Span>,
+) {
+ if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
+ return;
+ }
+ let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
+ if let Some(span) = inline_span {
+ tcx.sess.span_err(span, msg);
+ } else {
+ tcx.sess.err(msg);
+ }
+}
+
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
+}
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 71f9179d0..e1abb73a5 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -1,10 +1,8 @@
#![allow(non_camel_case_types)]
-use rustc_errors::struct_span_err;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
-use rustc_session::Session;
use rustc_span::Span;
use crate::base;
@@ -193,10 +191,6 @@ pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
}
-pub fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
- struct_span_err!(a, b, E0511, "{}", c).emit();
-}
-
pub fn asm_const_to_str<'tcx>(
tcx: TyCtxt<'tcx>,
sp: Span,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
index 6e3f4f0b8..60e9b40e8 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
@@ -10,7 +10,7 @@ pub mod type_names;
/// NOTE: This is somewhat inconsistent right now: For empty enums and enums with a single
/// fieldless variant, we generate DW_TAG_struct_type, although a
/// DW_TAG_enumeration_type would be a better fit.
-pub fn wants_c_like_enum_debuginfo<'tcx>(enum_type_and_layout: TyAndLayout<'tcx>) -> bool {
+pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> bool {
match enum_type_and_layout.ty.kind() {
ty::Adt(adt_def, _) => {
if !adt_def.is_enum() {
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index b004fbf85..1599ccbb2 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -93,6 +93,7 @@ fn push_debuginfo_type_name<'tcx>(
Err(e) => {
// Computing the layout can still fail here, e.g. if the target architecture
// cannot represent the type. See https://github.com/rust-lang/rust/issues/94961.
+ // FIXME: migrate once `rustc_middle::mir::interpret::InterpError` is translatable.
tcx.sess.fatal(&format!("{}", e));
}
}
@@ -235,7 +236,7 @@ fn push_debuginfo_type_name<'tcx>(
let projection_bounds: SmallVec<[_; 4]> = trait_data
.projection_bounds()
.map(|bound| {
- let ExistentialProjection { item_def_id, term, .. } =
+ let ExistentialProjection { def_id: item_def_id, term, .. } =
tcx.erase_late_bound_regions(bound);
// FIXME(associated_const_equality): allow for consts here
(item_def_id, term.ty().unwrap())
@@ -411,9 +412,8 @@ fn push_debuginfo_type_name<'tcx>(
ty::Error(_)
| ty::Infer(_)
| ty::Placeholder(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Bound(..)
- | ty::Opaque(..)
| ty::GeneratorWitness(..) => {
bug!(
"debuginfo: Trying to create type name for \
@@ -510,7 +510,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
visited.clear();
push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited);
} else {
- vtable_name.push_str("_");
+ vtable_name.push('_');
}
push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index e3b6fbf1b..d81252653 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -6,7 +6,9 @@ use rustc_errors::{
IntoDiagnosticArg,
};
use rustc_macros::Diagnostic;
+use rustc_middle::ty::Ty;
use rustc_span::{Span, Symbol};
+use rustc_type_ir::FloatTy;
use std::borrow::Cow;
use std::io::Error;
use std::path::{Path, PathBuf};
@@ -445,12 +447,6 @@ pub struct LinkerFileStem;
pub struct StaticLibraryNativeArtifacts;
#[derive(Diagnostic)]
-#[diag(codegen_ssa_native_static_libs)]
-pub struct NativeStaticLibs {
- pub arguments: String,
-}
-
-#[derive(Diagnostic)]
#[diag(codegen_ssa_link_script_unavailable)]
pub struct LinkScriptUnavailable;
@@ -548,3 +544,439 @@ pub struct ArchiveBuildFailure {
pub struct UnknownArchiveKind<'a> {
pub kind: &'a str,
}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_used_symbol)]
+pub struct ExpectedUsedSymbol {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_multiple_main_functions)]
+#[help]
+pub struct MultipleMainFunctions {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_metadata_object_file_write)]
+pub struct MetadataObjectFileWrite {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_windows_subsystem)]
+pub struct InvalidWindowsSubsystem {
+ pub subsystem: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_erroneous_constant)]
+pub struct ErroneousConstant {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_polymorphic_constant_too_generic)]
+pub struct PolymorphicConstantTooGeneric {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_shuffle_indices_evaluation)]
+pub struct ShuffleIndicesEvaluation {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_missing_memory_ordering)]
+pub struct MissingMemoryOrdering;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_atomic_ordering)]
+pub struct UnknownAtomicOrdering;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_atomic_compare_exchange)]
+pub struct AtomicCompareExchange;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_atomic_operation)]
+pub struct UnknownAtomicOperation;
+
+#[derive(Diagnostic)]
+pub enum InvalidMonomorphization<'tcx> {
+ #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = "E0511")]
+ BasicIntegerType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = "E0511")]
+ BasicFloatType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = "E0511")]
+ FloatToIntUnchecked {
+ #[primary_span]
+ span: Span,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = "E0511")]
+ FloatingPointVector {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ f_ty: FloatTy,
+ in_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = "E0511")]
+ FloatingPointType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = "E0511")]
+ UnrecognizedIntrinsic {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = "E0511")]
+ SimdArgument {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = "E0511")]
+ SimdInput {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = "E0511")]
+ SimdFirst {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = "E0511")]
+ SimdSecond {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = "E0511")]
+ SimdThird {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = "E0511")]
+ SimdReturn {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = "E0511")]
+ InvalidBitmask {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ mask_ty: Ty<'tcx>,
+ expected_int_bits: u64,
+ expected_bytes: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = "E0511")]
+ ReturnLengthInputType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = "E0511")]
+ SecondArgumentLength {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ in_ty: Ty<'tcx>,
+ arg_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = "E0511")]
+ ThirdArgumentLength {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ in_ty: Ty<'tcx>,
+ arg_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = "E0511")]
+ ReturnIntegerType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ret_ty: Ty<'tcx>,
+ out_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = "E0511")]
+ SimdShuffle {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_length, code = "E0511")]
+ ReturnLength {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ ret_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_element, code = "E0511")]
+ ReturnElement {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ out_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = "E0511")]
+ ShuffleIndexNotConstant {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ arg_idx: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = "E0511")]
+ ShuffleIndexOutOfBounds {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ arg_idx: u64,
+ total_len: u128,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = "E0511")]
+ InsertedType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ out_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_type, code = "E0511")]
+ ReturnType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = "E0511")]
+ ExpectedReturnType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = "E0511")]
+ MismatchedLengths {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ m_len: u64,
+ v_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = "E0511")]
+ MaskType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = "E0511")]
+ VectorArgument {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = "E0511")]
+ CannotReturn {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ret_ty: Ty<'tcx>,
+ expected_int_bits: u64,
+ expected_bytes: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = "E0511")]
+ ExpectedElementType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ expected_element: Ty<'tcx>,
+ second_arg: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ mutability: ExpectedPointerMutability,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = "E0511")]
+ ThirdArgElementType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ expected_element: Ty<'tcx>,
+ third_arg: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = "E0511")]
+ UnsupportedSymbolOfSize {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ symbol: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ size: u64,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = "E0511")]
+ UnsupportedSymbol {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ symbol: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = "E0511")]
+ CastFatPointer {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = "E0511")]
+ ExpectedPointer {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = "E0511")]
+ ExpectedUsize {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = "E0511")]
+ UnsupportedCast {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ out_elem: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = "E0511")]
+ UnsupportedOperation {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = "E0511")]
+ ExpectedVectorElementType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ expected_element: Ty<'tcx>,
+ vector_type: Ty<'tcx>,
+ },
+}
+
+pub enum ExpectedPointerMutability {
+ Mut,
+ Not,
+}
+
+impl IntoDiagnosticArg for ExpectedPointerMutability {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ match self {
+ ExpectedPointerMutability::Mut => DiagnosticArgValue::Str(Cow::Borrowed("*mut")),
+ ExpectedPointerMutability::Not => DiagnosticArgValue::Str(Cow::Borrowed("*_")),
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs
index 6015d48de..0f6e6032f 100644
--- a/compiler/rustc_codegen_ssa/src/glue.rs
+++ b/compiler/rustc_codegen_ssa/src/glue.rs
@@ -29,6 +29,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
.get_usize(bx, vtable);
+ // Size is always <= isize::MAX.
+ let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+ bx.range_metadata(size, WrappingRange { start: 0, end: size_bound });
// Alignment is always nonzero.
bx.range_metadata(align, WrappingRange { start: 1, end: !0 });
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index def6390f6..0e6596d4b 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -42,6 +42,7 @@ use std::path::{Path, PathBuf};
pub mod back;
pub mod base;
+pub mod codegen_attrs;
pub mod common;
pub mod coverageinfo;
pub mod debuginfo;
@@ -180,6 +181,7 @@ pub fn provide(providers: &mut Providers) {
crate::back::symbol_export::provide(providers);
crate::base::provide(providers);
crate::target_features::provide(providers);
+ crate::codegen_attrs::provide(providers);
}
pub fn provide_extern(providers: &mut ExternProviders) {
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index cae46ebd2..2421acab4 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -31,8 +31,7 @@ impl<'a, 'tcx> VirtualIndex {
let typeid =
bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)));
let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes();
- let type_checked_load = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
- let func = bx.extract_value(type_checked_load, 0);
+ let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
bx.pointercast(func, llty)
} else {
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
@@ -66,7 +65,7 @@ impl<'a, 'tcx> VirtualIndex {
/// This takes a valid `self` receiver type and extracts the principal trait
/// ref of the type.
-fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> {
+fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> {
for arg in ty.peel_refs().walk() {
if let GenericArgKind::Type(ty) = arg.unpack() {
if let ty::Dynamic(data, _, _) = ty.kind() {
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index c7617d2e4..dd1ac2c74 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -261,6 +261,9 @@ impl CleanupKind {
}
}
+/// MSVC requires unwinding code to be split to a tree of *funclets*, where each funclet can only
+/// branch to itself or to its parent. Luckily, the code we generates matches this pattern.
+/// Recover that structure in an analyze pass.
pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKind> {
fn discover_masters<'tcx>(
result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 03d833fbb..978aff511 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -289,16 +289,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.cleanup_ret(funclet, None);
} else {
let slot = self.get_personality_slot(bx);
- let lp0 = slot.project_field(bx, 0);
- let lp0 = bx.load_operand(lp0).immediate();
- let lp1 = slot.project_field(bx, 1);
- let lp1 = bx.load_operand(lp1).immediate();
+ let exn0 = slot.project_field(bx, 0);
+ let exn0 = bx.load_operand(exn0).immediate();
+ let exn1 = slot.project_field(bx, 1);
+ let exn1 = bx.load_operand(exn1).immediate();
slot.storage_dead(bx);
- let mut lp = bx.const_undef(self.landing_pad_type());
- lp = bx.insert_value(lp, lp0, 0);
- lp = bx.insert_value(lp, lp1, 1);
- bx.resume(lp);
+ bx.resume(exn0, exn1);
}
}
@@ -307,12 +304,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
helper: TerminatorCodegenHelper<'tcx>,
bx: &mut Bx,
discr: &mir::Operand<'tcx>,
- switch_ty: Ty<'tcx>,
targets: &SwitchTargets,
) {
let discr = self.codegen_operand(bx, &discr);
- // `switch_ty` is redundant, sanity-check that.
- assert_eq!(discr.layout.ty, switch_ty);
+ let switch_ty = discr.layout.ty;
let mut target_iter = targets.iter();
if target_iter.len() == 1 {
// If there are two targets (one conditional, one fallback), emit `br` instead of
@@ -642,7 +637,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.set_debug_loc(bx, terminator.source_info);
// Obtain the panic entry point.
- let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicNoUnwind);
+ let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
// Codegen the actual panic invoke/call.
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &[], None, None, &[], false);
@@ -668,12 +663,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
enum AssertIntrinsic {
Inhabited,
ZeroValid,
- UninitValid,
+ MemUninitializedValid,
}
let panic_intrinsic = intrinsic.and_then(|i| match i {
sym::assert_inhabited => Some(AssertIntrinsic::Inhabited),
sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid),
- sym::assert_uninit_valid => Some(AssertIntrinsic::UninitValid),
+ sym::assert_mem_uninitialized_valid => Some(AssertIntrinsic::MemUninitializedValid),
_ => None,
});
if let Some(intrinsic) = panic_intrinsic {
@@ -684,7 +679,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let do_panic = match intrinsic {
Inhabited => layout.abi.is_uninhabited(),
ZeroValid => !bx.tcx().permits_zero_init(layout),
- UninitValid => !bx.tcx().permits_uninit_init(layout),
+ MemUninitializedValid => !bx.tcx().permits_uninit_init(layout),
};
Some(if do_panic {
let msg_str = with_no_visible_paths!({
@@ -703,11 +698,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
});
let msg = bx.const_str(&msg_str);
- let location = self.get_caller_location(bx, source_info).immediate();
// Obtain the panic entry point.
let (fn_abi, llfn) =
- common::build_langcall(bx, Some(source_info.span), LangItem::Panic);
+ common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
// Codegen the actual panic invoke/call.
helper.do_call(
@@ -715,7 +709,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx,
fn_abi,
llfn,
- &[msg.0, msg.1, location],
+ &[msg.0, msg.1],
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
cleanup,
&[],
@@ -753,10 +747,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (instance, mut llfn) = match *callee.layout.ty.kind() {
ty::FnDef(def_id, substs) => (
Some(
- ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs)
- .unwrap()
- .unwrap()
- .polymorphize(bx.tcx()),
+ ty::Instance::expect_resolve(
+ bx.tcx(),
+ ty::ParamEnv::reveal_all(),
+ def_id,
+ substs,
+ )
+ .polymorphize(bx.tcx()),
),
None,
),
@@ -1293,8 +1290,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
helper.funclet_br(self, bx, target, mergeable_succ())
}
- mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
- self.codegen_switchint_terminator(helper, bx, discr, switch_ty, targets);
+ mir::TerminatorKind::SwitchInt { ref discr, ref targets } => {
+ self.codegen_switchint_terminator(helper, bx, discr, targets);
MergingSucc::False
}
@@ -1635,24 +1632,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
let llpersonality = self.cx.eh_personality();
- let llretty = self.landing_pad_type();
- let lp = cleanup_bx.cleanup_landing_pad(llretty, llpersonality);
+ let (exn0, exn1) = cleanup_bx.cleanup_landing_pad(llpersonality);
let slot = self.get_personality_slot(&mut cleanup_bx);
slot.storage_live(&mut cleanup_bx);
- Pair(cleanup_bx.extract_value(lp, 0), cleanup_bx.extract_value(lp, 1))
- .store(&mut cleanup_bx, slot);
+ Pair(exn0, exn1).store(&mut cleanup_bx, slot);
cleanup_bx.br(llbb);
cleanup_llbb
}
}
- fn landing_pad_type(&self) -> Bx::Type {
- let cx = self.cx;
- cx.type_struct(&[cx.type_i8p(), cx.type_i32()], false)
- }
-
fn unreachable_block(&mut self) -> Bx::BasicBlock {
self.unreachable_block.unwrap_or_else(|| {
let llbb = Bx::append_block(self.cx, self.llfn, "unreachable");
@@ -1672,10 +1662,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
let llpersonality = self.cx.eh_personality();
- let llretty = self.landing_pad_type();
- bx.cleanup_landing_pad(llretty, llpersonality);
+ bx.cleanup_landing_pad(llpersonality);
- let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicNoUnwind);
+ let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], None);
@@ -1812,15 +1801,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
match (src.layout.abi, dst.layout.abi) {
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
- if (src_scalar.primitive() == abi::Pointer)
- == (dst_scalar.primitive() == abi::Pointer)
- {
+ let src_is_ptr = src_scalar.primitive() == abi::Pointer;
+ let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
+ if src_is_ptr == dst_is_ptr {
assert_eq!(src.layout.size, dst.layout.size);
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
// conversions allow handling `bool`s the same as `u8`s.
let src = bx.from_immediate(src.immediate());
- let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
+ // LLVM also doesn't like `bitcast`s between pointers in different address spaces.
+ let src_as_dst = if src_is_ptr {
+ bx.pointercast(src, bx.backend_type(dst.layout))
+ } else {
+ bx.bitcast(src, bx.backend_type(dst.layout))
+ };
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
return;
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 53ff3c240..14fe84a14 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -1,3 +1,4 @@
+use crate::errors;
use crate::mir::operand::OperandRef;
use crate::traits::*;
use rustc_middle::mir;
@@ -44,10 +45,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
match err {
ErrorHandled::Reported(_) => {
- self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
+ self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
}
ErrorHandled::TooGeneric => {
- span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err);
+ self.cx
+ .tcx()
+ .sess
+ .diagnostic()
+ .emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
}
}
err
@@ -87,7 +92,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
(llval, c.ty())
})
.unwrap_or_else(|_| {
- bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
+ bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span });
// We've errored, so we don't have to produce working code.
let ty = self.monomorphize(ty);
let llty = bx.backend_type(bx.layout_of(ty));
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 99283d3bb..e9bc40c33 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -3,12 +3,12 @@ use rustc_index::vec::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir;
use rustc_middle::ty;
+use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_session::config::DebugInfo;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{BytePos, Span};
-use rustc_target::abi::Abi;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Abi, Size, VariantIdx};
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
@@ -57,9 +57,9 @@ pub struct DebugScope<S, L> {
}
impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
- /// DILocations inherit source file name from the parent DIScope. Due to macro expansions
+ /// DILocations inherit source file name from the parent DIScope. Due to macro expansions
/// it may so happen that the current span belongs to a different file than the DIScope
- /// corresponding to span's containing source scope. If so, we need to create a DIScope
+ /// corresponding to span's containing source scope. If so, we need to create a DIScope
/// "extension" into that file.
pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>(
&self,
@@ -76,6 +76,106 @@ impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
}
}
+trait DebugInfoOffsetLocation<'tcx, Bx> {
+ fn deref(&self, bx: &mut Bx) -> Self;
+ fn layout(&self) -> TyAndLayout<'tcx>;
+ fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self;
+ fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self;
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
+ for PlaceRef<'tcx, Bx::Value>
+{
+ fn deref(&self, bx: &mut Bx) -> Self {
+ bx.load_operand(*self).deref(bx.cx())
+ }
+
+ fn layout(&self) -> TyAndLayout<'tcx> {
+ self.layout
+ }
+
+ fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self {
+ PlaceRef::project_field(*self, bx, field.index())
+ }
+
+ fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
+ self.project_downcast(bx, variant)
+ }
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
+ for TyAndLayout<'tcx>
+{
+ fn deref(&self, bx: &mut Bx) -> Self {
+ bx.cx().layout_of(
+ self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty,
+ )
+ }
+
+ fn layout(&self) -> TyAndLayout<'tcx> {
+ *self
+ }
+
+ fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self {
+ self.field(bx.cx(), field.index())
+ }
+
+ fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
+ self.for_variant(bx.cx(), variant)
+ }
+}
+
+struct DebugInfoOffset<T> {
+ /// Offset from the `base` used to calculate the debuginfo offset.
+ direct_offset: Size,
+ /// Each offset in this vector indicates one level of indirection from the base or previous
+ /// indirect offset plus a dereference.
+ indirect_offsets: Vec<Size>,
+ /// The final location debuginfo should point to.
+ result: T,
+}
+
+fn calculate_debuginfo_offset<
+ 'a,
+ 'tcx,
+ Bx: BuilderMethods<'a, 'tcx>,
+ L: DebugInfoOffsetLocation<'tcx, Bx>,
+>(
+ bx: &mut Bx,
+ local: mir::Local,
+ var: &PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
+ base: L,
+) -> DebugInfoOffset<L> {
+ let mut direct_offset = Size::ZERO;
+ // FIXME(eddyb) use smallvec here.
+ let mut indirect_offsets = vec![];
+ let mut place = base;
+
+ for elem in &var.projection[..] {
+ match *elem {
+ mir::ProjectionElem::Deref => {
+ indirect_offsets.push(Size::ZERO);
+ place = place.deref(bx);
+ }
+ mir::ProjectionElem::Field(field, _) => {
+ let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
+ *offset += place.layout().fields.offset(field.index());
+ place = place.project_field(bx, field);
+ }
+ mir::ProjectionElem::Downcast(_, variant) => {
+ place = place.downcast(bx, variant);
+ }
+ _ => span_bug!(
+ var.source_info.span,
+ "unsupported var debuginfo place `{:?}`",
+ mir::Place { local, projection: var.projection },
+ ),
+ }
+ }
+
+ DebugInfoOffset { direct_offset, indirect_offsets, result: place }
+}
+
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
bx.set_span(source_info.span);
@@ -262,33 +362,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let Some(dbg_var) = var.dbg_var else { continue };
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
- let mut direct_offset = Size::ZERO;
- // FIXME(eddyb) use smallvec here.
- let mut indirect_offsets = vec![];
- let mut place = base;
-
- for elem in &var.projection[..] {
- match *elem {
- mir::ProjectionElem::Deref => {
- indirect_offsets.push(Size::ZERO);
- place = bx.load_operand(place).deref(bx.cx());
- }
- mir::ProjectionElem::Field(field, _) => {
- let i = field.index();
- let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
- *offset += place.layout.fields.offset(i);
- place = place.project_field(bx, i);
- }
- mir::ProjectionElem::Downcast(_, variant) => {
- place = place.project_downcast(bx, variant);
- }
- _ => span_bug!(
- var.source_info.span,
- "unsupported var debuginfo place `{:?}`",
- mir::Place { local, projection: var.projection },
- ),
- }
- }
+ let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
+ calculate_debuginfo_offset(bx, local, &var, base.layout);
// When targeting MSVC, create extra allocas for arguments instead of pointing multiple
// dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
@@ -306,6 +381,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|| !matches!(&indirect_offsets[..], [Size::ZERO] | []));
if should_create_individual_allocas {
+ let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
+ calculate_debuginfo_offset(bx, local, &var, base);
+
// Create a variable which will be a pointer to the actual value
let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut {
mutbl: mir::Mutability::Mut,
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 215edbe02..766dc74cb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -1,7 +1,9 @@
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
use super::FunctionCx;
-use crate::common::{span_invalid_monomorphization_error, IntPredicate};
+use crate::common::IntPredicate;
+use crate::errors;
+use crate::errors::InvalidMonomorphization;
use crate::glue;
use crate::meth;
use crate::traits::*;
@@ -110,10 +112,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!(),
};
let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable);
- if name == sym::vtable_align {
+ match name {
+ // Size is always <= isize::MAX.
+ sym::vtable_size => {
+ let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+ bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
+ },
// Alignment is always nonzero.
- bx.range_metadata(value, WrappingRange { start: 1, end: !0 });
- };
+ sym::vtable_align => bx.range_metadata(value, WrappingRange { start: 1, end: !0 }),
+ _ => {}
+ }
value
}
sym::pref_align_of
@@ -299,15 +307,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!(),
},
None => {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
return;
}
}
@@ -323,15 +323,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!(),
},
None => {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic float type, found `{}`",
- name, arg_tys[0]
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { span, name, ty: arg_tys[0] });
return;
}
}
@@ -339,29 +331,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::float_to_int_unchecked => {
if float_type_width(arg_tys[0]).is_none() {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
- intrinsic: expected basic float type, \
- found `{}`",
- arg_tys[0]
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: arg_tys[0] });
return;
}
let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
- intrinsic: expected basic integer type, \
- found `{}`",
- ret_ty
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: ret_ty });
return;
};
if signed {
@@ -396,7 +370,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
use crate::common::{AtomicRmwBinOp, SynchronizationScope};
let Some((instruction, ordering)) = atomic.split_once('_') else {
- bx.sess().fatal("Atomic intrinsic missing memory ordering");
+ bx.sess().emit_fatal(errors::MissingMemoryOrdering);
};
let parse_ordering = |bx: &Bx, s| match s {
@@ -406,25 +380,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
"release" => Release,
"acqrel" => AcquireRelease,
"seqcst" => SequentiallyConsistent,
- _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
+ _ => bx.sess().emit_fatal(errors::UnknownAtomicOrdering),
};
let invalid_monomorphization = |ty| {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
};
match instruction {
"cxchg" | "cxchgweak" => {
let Some((success, failure)) = ordering.split_once('_') else {
- bx.sess().fatal("Atomic compare-exchange intrinsic missing failure memory ordering");
+ bx.sess().emit_fatal(errors::AtomicCompareExchange);
};
let ty = substs.type_at(0);
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
@@ -523,7 +489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
"min" => AtomicRmwBinOp::AtomicMin,
"umax" => AtomicRmwBinOp::AtomicUMax,
"umin" => AtomicRmwBinOp::AtomicUMin,
- _ => bx.sess().fatal("unknown atomic operation"),
+ _ => bx.sess().emit_fatal(errors::UnknownAtomicOperation),
};
let ty = substs.type_at(0);
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 9ad96f7a4..23196c8cb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
assert!(bx.cx().tcx().is_static(def_id));
let static_ = bx.get_static(def_id);
let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id));
- OperandRef::from_immediate_or_packed_pair(bx, static_, layout)
+ OperandRef { val: OperandValue::Immediate(static_), layout }
}
mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => {
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 301683e8e..739963fff 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,8 +1,19 @@
+use rustc_ast::ast;
+use rustc_attr::InstructionSetAttr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;
+use rustc_span::Span;
/// Features that control behaviour of rustc, rather than the codegen.
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
@@ -176,7 +187,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("bmi2", None),
("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
("ermsb", Some(sym::ermsb_target_feature)),
- ("f16c", Some(sym::f16c_target_feature)),
+ ("f16c", None),
("fma", None),
("fxsr", None),
("gfni", Some(sym::avx512_target_feature)),
@@ -322,15 +333,147 @@ pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]
}
}
-pub(crate) fn provide(providers: &mut Providers) {
- providers.supported_target_features = |tcx, cnum| {
- assert_eq!(cnum, LOCAL_CRATE);
- if tcx.sess.opts.actually_rustdoc {
- // rustdoc needs to be able to document functions that use all the features, so
- // whitelist them all
- all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
- } else {
- supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
- }
+pub fn from_target_feature(
+ tcx: TyCtxt<'_>,
+ attr: &ast::Attribute,
+ supported_target_features: &FxHashMap<String, Option<Symbol>>,
+ target_features: &mut Vec<Symbol>,
+) {
+ let Some(list) = attr.meta_item_list() else { return };
+ let bad_item = |span| {
+ let msg = "malformed `target_feature` attribute input";
+ let code = "enable = \"..\"";
+ tcx.sess
+ .struct_span_err(span, msg)
+ .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
+ .emit();
};
+ let rust_features = tcx.features();
+ for item in list {
+ // Only `enable = ...` is accepted in the meta-item list.
+ if !item.has_name(sym::enable) {
+ bad_item(item.span());
+ continue;
+ }
+
+ // Must be of the form `enable = "..."` (a string).
+ let Some(value) = item.value_str() else {
+ bad_item(item.span());
+ continue;
+ };
+
+ // We allow comma separation to enable multiple features.
+ target_features.extend(value.as_str().split(',').filter_map(|feature| {
+ let Some(feature_gate) = supported_target_features.get(feature) else {
+ let msg =
+ format!("the feature named `{}` is not valid for this target", feature);
+ let mut err = tcx.sess.struct_span_err(item.span(), &msg);
+ err.span_label(
+ item.span(),
+ format!("`{}` is not valid for this target", feature),
+ );
+ if let Some(stripped) = feature.strip_prefix('+') {
+ let valid = supported_target_features.contains_key(stripped);
+ if valid {
+ err.help("consider removing the leading `+` in the feature name");
+ }
+ }
+ err.emit();
+ return None;
+ };
+
+ // Only allow features whose feature gates have been enabled.
+ let allowed = match feature_gate.as_ref().copied() {
+ Some(sym::arm_target_feature) => rust_features.arm_target_feature,
+ Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
+ Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
+ Some(sym::mips_target_feature) => rust_features.mips_target_feature,
+ Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
+ Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
+ Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
+ Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
+ Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
+ Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
+ Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
+ Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
+ Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
+ Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
+ Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
+ Some(name) => bug!("unknown target feature gate {}", name),
+ None => true,
+ };
+ if !allowed {
+ feature_err(
+ &tcx.sess.parse_sess,
+ feature_gate.unwrap(),
+ item.span(),
+ &format!("the target feature `{}` is currently unstable", feature),
+ )
+ .emit();
+ }
+ Some(Symbol::intern(feature))
+ }));
+ }
+}
+
+/// Computes the set of target features used in a function for the purposes of
+/// inline assembly.
+fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxHashSet<Symbol> {
+ let mut target_features = tcx.sess.unstable_target_features.clone();
+ if tcx.def_kind(did).has_codegen_attrs() {
+ let attrs = tcx.codegen_fn_attrs(did);
+ target_features.extend(&attrs.target_features);
+ match attrs.instruction_set {
+ None => {}
+ Some(InstructionSetAttr::ArmA32) => {
+ target_features.remove(&sym::thumb_mode);
+ }
+ Some(InstructionSetAttr::ArmT32) => {
+ target_features.insert(sym::thumb_mode);
+ }
+ }
+ }
+
+ tcx.arena.alloc(target_features)
+}
+
+/// Checks the function annotated with `#[target_feature]` is not a safe
+/// trait method implementation, reporting an error if it is.
+pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(id);
+ let node = tcx.hir().get(hir_id);
+ if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
+ let parent_id = tcx.hir().get_parent_item(hir_id);
+ let parent_item = tcx.hir().expect_item(parent_id.def_id);
+ if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
+ tcx.sess
+ .struct_span_err(
+ attr_span,
+ "`#[target_feature(..)]` cannot be applied to safe trait method",
+ )
+ .span_label(attr_span, "cannot be applied to safe trait method")
+ .span_label(tcx.def_span(id), "not an `unsafe` function")
+ .emit();
+ }
+ }
+}
+
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ supported_target_features: |tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ if tcx.sess.opts.actually_rustdoc {
+ // rustdoc needs to be able to document functions that use all the features, so
+ // whitelist them all
+ all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
+ } else {
+ supported_target_features(tcx.sess)
+ .iter()
+ .map(|&(a, b)| (a.to_string(), b))
+ .collect()
+ }
+ },
+ asm_target_features,
+ ..*providers
+ }
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index bc679a5dc..194768d94 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -271,8 +271,8 @@ pub trait BuilderMethods<'a, 'tcx>:
fn set_personality_fn(&mut self, personality: Self::Value);
// These are used by everyone except msvc
- fn cleanup_landing_pad(&mut self, ty: Self::Type, pers_fn: Self::Value) -> Self::Value;
- fn resume(&mut self, exn: Self::Value);
+ fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
+ fn resume(&mut self, exn0: Self::Value, exn1: Self::Value);
// These are used only by msvc
fn cleanup_pad(&mut self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Funclet;
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 86481d5d7..109161ccc 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -122,6 +122,7 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> {
fn set_type_metadata(&self, function: Self::Function, typeid: String);
fn typeid_metadata(&self, typeid: String) -> Self::Value;
+ fn set_kcfi_type_metadata(&self, function: Self::Function, typeid: u32);
}
pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {