diff options
96 files changed, 2586 insertions, 482 deletions
diff --git a/Cargo.lock b/Cargo.lock index ff73b45634f..ed3e30342f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1726,18 +1726,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", "compiler_builtins", @@ -1896,12 +1887,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown", "rustc-rayon", "serde", ] @@ -2361,9 +2352,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13cdad8057b09a519c6c63e6d7c93ea854f5d7fbfe284df864d5e1140d215a2d" +checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9" dependencies = [ "ammonia", "anyhow", @@ -2389,9 +2380,9 @@ dependencies = [ [[package]] name = "measureme" -version = "10.0.0" +version = "10.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c" +checksum = "cbdc226fa10994e8f66a4d2f6f000148bc563a1c671b6dcd2135737018033d8a" dependencies = [ "log", "memmap2", @@ -2578,25 +2569,13 @@ dependencies = [ [[package]] name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "crc32fast", - "flate2", - "hashbrown 0.11.2", - "indexmap", - "memchr", -] - -[[package]] -name = "object" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "hashbrown 0.12.0", + "flate2", + "hashbrown", "indexmap", "memchr", ] @@ -4519,6 +4498,7 @@ dependencies = [ name = "rustc_symbol_mangling" version = "0.0.0" dependencies = [ + "bitflags", "punycode", "rustc-demangle", "rustc_data_structures", @@ -5067,7 +5047,7 @@ dependencies = [ "core", "dlmalloc", "fortanix-sgx-abi", - "hashbrown 0.12.0", + "hashbrown", "hermit-abi 0.2.0", "libc", "miniz_oxide 0.4.0", @@ -5278,13 +5258,13 @@ dependencies = [ [[package]] name = "thorin-dwp" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be" +checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254" dependencies = [ "gimli 0.26.1", - "hashbrown 0.11.2", - "object 0.28.4", + "hashbrown", + "object 0.29.0", "tracing", ] diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 334326e927f..60560b1c00e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1272,7 +1272,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_vis(&item.vis); self.visit_ident(item.ident); self.visit_generics(generics); - self.with_banned_tilde_const(|this| { + self.with_tilde_const_allowed(|this| { walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) }); walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait); diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index da18ac7eacb..2f5d1c0432f 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -163,15 +163,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "indexmap" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index ec2c1f2ca71..ff71d7a209e 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -19,7 +19,7 @@ gimli = { version = "0.26.0", default-features = false, features = ["write"]} object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } -indexmap = "1.8.0" +indexmap = "1.9.1" libloading = { version = "0.6.0", optional = true } once_cell = "1.10.0" smallvec = "1.8.1" diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 6221a7f6d93..4d40dd0994d 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -784,16 +784,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo) } - fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) { - // Unsupported. - } - - fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> { - // Unsupported. - self.context.new_rvalue_from_int(self.int_type, 0) - } - - fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { self.store_with_flags(val, ptr, align, MemFlags::empty()) } diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 002b95db36d..68bdb8d4e55 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -1,7 +1,7 @@ use std::convert::TryInto; use gccjit::{RValue, Struct, Type}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods}; use rustc_codegen_ssa::common::TypeKind; use rustc_middle::{bug, ty}; use rustc_middle::ty::layout::TyAndLayout; @@ -290,3 +290,14 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout (result, packed) } + +impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) { + // Unsupported. + } + + fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> { + // Unsupported. + self.context.new_rvalue_from_int(self.int_type, 0) + } +} diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index d8fbd0a84fb..f9a5463efcd 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -18,7 +18,6 @@ rustc_middle = { path = "../rustc_middle" } rustc-demangle = "0.1.21" rustc_attr = { path = "../rustc_attr" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } -rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fs_util = { path = "../rustc_fs_util" } @@ -30,6 +29,7 @@ rustc_metadata = { path = "../rustc_metadata" } rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_serialize = { path = "../rustc_serialize" } +rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 62da99ac3fb..1a96dd8bec4 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -69,6 +69,9 @@ pub fn sanitize_attrs<'ll>( if enabled.contains(SanitizerSet::HWADDRESS) { attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx)); } + if enabled.contains(SanitizerSet::SHADOWCALLSTACK) { + attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx)); + } if enabled.contains(SanitizerSet::MEMTAG) { // Check to make sure the mte target feature is actually enabled. let features = cx.tcx.global_backend_features(()); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4a4cccb490d..d3096c73a8a 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -626,32 +626,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn type_metadata(&mut self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid); - let v = [self.const_usize(0), typeid_metadata]; - unsafe { - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_type as c_uint, - llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( - self.cx.llcx, - v.as_ptr(), - v.len() as c_uint, - )), - ) - } - } - - fn typeid_metadata(&mut self, typeid: String) -> Self::Value { - unsafe { - llvm::LLVMMDStringInContext( - self.cx.llcx, - typeid.as_ptr() as *const c_char, - typeid.as_bytes().len() as c_uint, - ) - } - } - fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value { self.store_with_flags(val, ptr, align, MemFlags::empty()) } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 5a5c4f7f860..fa0ecd18fc8 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -18,7 +18,9 @@ use crate::llvm; use crate::llvm::AttributePlace::Function; use crate::type_::Type; use crate::value::Value; +use rustc_codegen_ssa::traits::TypeMembershipMethods; use rustc_middle::ty::Ty; +use rustc_symbol_mangling::typeid::typeid_for_fnabi; use smallvec::SmallVec; use tracing::debug; @@ -97,6 +99,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { fn_abi.llvm_type(self), ); fn_abi.apply_attrs_llfn(self, llfn); + + if self.tcx.sess.is_sanitizer_cfi_enabled() { + let typeid = typeid_for_fnabi(self.tcx, fn_abi); + self.set_type_metadata(llfn, typeid); + } + llfn } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 624ce8d9369..f64eb79b0a8 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -192,6 +192,7 @@ pub enum AttributeKind { NoUndef = 33, SanitizeMemTag = 34, NoCfCheck = 35, + ShadowCallStack = 36, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index cf2d3c423c3..eeb38d4ecf5 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -19,7 +19,7 @@ use rustc_target::abi::{AddressSpace, Align, Integer, Size}; use std::fmt; use std::ptr; -use libc::c_uint; +use libc::{c_char, c_uint}; impl PartialEq for Type { fn eq(&self, other: &Self) -> bool { @@ -289,3 +289,31 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty.llvm_type(self) } } + +impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> { + fn set_type_metadata(&self, function: &'ll Value, typeid: String) { + let typeid_metadata = self.typeid_metadata(typeid); + let v = [self.const_usize(0), typeid_metadata]; + unsafe { + llvm::LLVMGlobalSetMetadata( + function, + llvm::MD_type as c_uint, + llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( + self.llcx, + v.as_ptr(), + v.len() as c_uint, + )), + ) + } + } + + fn typeid_metadata(&self, typeid: String) -> &'ll Value { + unsafe { + llvm::LLVMMDStringInContext( + self.llcx, + typeid.as_ptr() as *const c_char, + typeid.len() as c_uint, + ) + } + } +} diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 81c8b9ceb13..46d6344dbb2 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -14,7 +14,7 @@ tracing = "0.1" libc = "0.2.50" jobserver = "0.1.22" tempfile = "3.2" -thorin-dwp = "0.2" +thorin-dwp = "0.3" pathdiff = "0.2.0" serde_json = "1.0.59" snap = "1" diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 773c55cf551..3eee58d9d1c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; -use rustc_symbol_mangling::typeid_for_fnabi; +use rustc_symbol_mangling::typeid::typeid_for_fnabi; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::abi::{self, HasDataLayout, WrappingRange}; use rustc_target::spec::abi::Abi; @@ -918,7 +918,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(rcvalle): Add support for generalized identifiers. // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers. let typeid = typeid_for_fnabi(bx.tcx(), fn_abi); - let typeid_metadata = bx.typeid_metadata(typeid); + let typeid_metadata = self.cx.typeid_metadata(typeid); // Test whether the function pointer is associated with the type identifier. let cond = bx.type_test(fn_ptr, typeid_metadata); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index ec3f7a2156a..8ee375fa9e3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -3,7 +3,6 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable}; -use rustc_symbol_mangling::typeid_for_fnabi; use rustc_target::abi::call::{FnAbi, PassMode}; use std::iter; @@ -247,13 +246,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( for (bb, _) in traversal::reverse_postorder(&mir) { fx.codegen_block(bb); } - - // For backends that support CFI using type membership (i.e., testing whether a given pointer - // is associated with a type identifier). - if cx.tcx().sess.is_sanitizer_cfi_enabled() { - let typeid = typeid_for_fnabi(cx.tcx(), fn_abi); - bx.type_metadata(llfn, typeid); - } } /// Produces, for each argument, a `Value` pointing at the diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 1bbe10141fc..9f49749bb41 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -160,8 +160,6 @@ pub trait BuilderMethods<'a, 'tcx>: fn range_metadata(&mut self, load: Self::Value, range: WrappingRange); fn nonnull_metadata(&mut self, load: Self::Value); - fn type_metadata(&mut self, function: Self::Function, typeid: String); - fn typeid_metadata(&mut self, typeid: String) -> Self::Value; fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value; fn store_with_flags( diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 396768e0a42..782fdadbfb8 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -40,7 +40,8 @@ pub use self::intrinsic::IntrinsicCallMethods; pub use self::misc::MiscMethods; pub use self::statics::{StaticBuilderMethods, StaticMethods}; pub use self::type_::{ - ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods, + ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMembershipMethods, + TypeMethods, }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 5d3f07317a3..8158e8dd011 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -117,6 +117,13 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { ) -> Self::Type; } +// For backends that support CFI using type membership (i.e., testing whether a given pointer is +// associated with a type identifier). +pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> { + fn set_type_metadata(&self, function: Self::Function, typeid: String); + fn typeid_metadata(&self, typeid: String) -> Self::Value; +} + pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { fn store_fn_arg( &mut self, @@ -133,6 +140,12 @@ pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type; } -pub trait TypeMethods<'tcx>: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {} +pub trait TypeMethods<'tcx>: + DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> +{ +} -impl<'tcx, T> TypeMethods<'tcx> for T where Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {} +impl<'tcx, T> TypeMethods<'tcx> for T where + Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> +{ +} diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 2a801d0e702..5c641f54f68 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] arrayvec = { version = "0.7", default-features = false } ena = "0.14" -indexmap = { version = "1.8.2" } +indexmap = { version = "1.9.1" } tracing = "0.1" jobserver_crate = { version = "0.1.13", package = "jobserver" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index b267140daa9..561d1354edd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,4 +1,4 @@ -use crate::infer::type_variable::TypeVariableOriginKind; +use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; @@ -8,12 +8,12 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::ConstVariableOriginKind; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, InferConst}; -use rustc_middle::ty::{Ty, TyCtxt, TypeckResults}; +use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; @@ -407,11 +407,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label(span, cannot_infer_msg); - let printer = fmt_printer(self, Namespace::TypeNS); - let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer(); + let args = fmt_printer(self, Namespace::TypeNS) + .comma_sep(generic_args.iter().copied().map(|arg| { + if arg.is_suggestable(self.tcx, true) { + return arg; + } + + match arg.unpack() { + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + GenericArgKind::Type(_) => self + .next_ty_var(TypeVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }) + .into(), + GenericArgKind::Const(arg) => self + .next_const_var( + arg.ty(), + ConstVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: ConstVariableOriginKind::MiscVariable, + }, + ) + .into(), + } + })) + .unwrap() + .into_buffer(); + err.span_suggestion_verbose( insert_span, - &format!("consider specifying the generic argument{}", pluralize!(args.len()),), + &format!( + "consider specifying the generic argument{}", + pluralize!(generic_args.len()), + ), format!("::<{}>", args), Applicability::HasPlaceholders, ); diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 674c75fdee5..38ff9343537 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -145,7 +145,12 @@ impl<'tcx> Elaborator<'tcx> { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); - let obligations = predicates.predicates.iter().map(|&(pred, _)| { + let obligations = predicates.predicates.iter().map(|&(mut pred, _)| { + // when parent predicate is non-const, elaborate it to non-const predicates. + if data.constness == ty::BoundConstness::NotConst { + pred = pred.without_const(tcx); + } + predicate_obligation( pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), obligation.param_env, diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 9fe84a6309b..bca5425e728 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -85,6 +85,7 @@ enum LLVMRustAttribute { NoUndef = 33, SanitizeMemTag = 34, NoCfCheck = 35, + ShadowCallStack = 36, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 2d35ee8976e..4615558b912 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -232,6 +232,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::NoUndef; case SanitizeMemTag: return Attribute::SanitizeMemTag; + case ShadowCallStack: + return Attribute::ShadowCallStack; } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index a72bcb9a2db..2c1c84b0be2 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -67,7 +67,7 @@ //! //! ## What criterion to select on? //! -//! This a pretty tricky area of loading crates. Given a file, how do we know +//! This is a pretty tricky area of loading crates. Given a file, how do we know //! whether it's the right crate? Currently, the rules look along these lines: //! //! 1. Does the filename match an rlib/dylib pattern? That is to say, does the diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 25bc6dc6167..dd2f4321060 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use crate::ty::{ - visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, + visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy, PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; @@ -82,15 +82,18 @@ pub trait IsSuggestable<'tcx> { /// meaningful rendered suggestions when pretty-printed. We leave some /// nonsense, such as region vars, since those render as `'_` and are /// usually okay to reinterpret as elided lifetimes. - fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool; + /// + /// Only if `infer_suggestable` is true, we consider type and const + /// inference variables to be suggestable. + fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool; } impl<'tcx, T> IsSuggestable<'tcx> for T where T: TypeVisitable<'tcx>, { - fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { - self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue() + fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool { + self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue() } } @@ -100,7 +103,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( err: &mut Diagnostic, trait_pred: PolyTraitPredicate<'tcx>, ) -> bool { - if !trait_pred.is_suggestable(tcx) { + if !trait_pred.is_suggestable(tcx, false) { return false; } @@ -419,6 +422,7 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { pub struct IsSuggestableVisitor<'tcx> { tcx: TyCtxt<'tcx>, + infer_suggestable: bool, } impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { @@ -426,6 +430,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { + Infer(InferTy::TyVar(_)) if self.infer_suggestable => {} + FnDef(..) | Closure(..) | Infer(..) @@ -479,6 +485,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { match c.kind() { + ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {} + ConstKind::Infer(..) | ConstKind::Bound(..) | ConstKind::Placeholder(..) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 49761023ec3..e739ed678d8 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2111,7 +2111,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let res = match kind { ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()), NormalRibKind => Res::Err, - _ => bug!("Unexpected rib kind {:?}", kind), + _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind), }; self.r.record_partial_res(param.id, PartialRes::new(res)); rib.bindings.insert(ident, res); diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 5056163b7fe..dbc5c15195c 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] -indexmap = "1.8.0" +indexmap = "1.9.1" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } [dev-dependencies] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 21b1b0b4ebf..1b583417ca0 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -377,7 +377,7 @@ mod desc { pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -683,6 +683,7 @@ mod parse { "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "memtag" => SanitizerSet::MEMTAG, + "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK, "thread" => SanitizerSet::THREAD, "hwaddress" => SanitizerSet::HWADDRESS, _ => return false, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d15b15f75dd..cb15132bd4b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1284,6 +1284,7 @@ symbols! { self_in_typedefs, self_struct_ctor, semitransparent, + shadow_call_stack, shl, shl_assign, should_panic, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index d5befa10e23..b104a40c231 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" doctest = false [dependencies] +bitflags = "1.2.1" tracing = "0.1" punycode = "0.4.0" rustc-demangle = "0.1.21" diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index bed0e81e66e..5fc992023ca 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -102,9 +102,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; -use rustc_target::abi::call::FnAbi; use tracing::debug; @@ -112,6 +111,7 @@ mod legacy; mod v0; pub mod test; +pub mod typeid; /// This function computes the symbol name for the given `instance` and the /// given instantiating crate. That is, if you know that instance X is @@ -150,11 +150,6 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty ty::SymbolName::new(tcx, &symbol_name) } -/// This function computes the typeid for the given function ABI. -pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { - v0::mangle_typeid_for_fnabi(tcx, fn_abi) -} - pub fn typeid_for_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyExistentialTraitRef<'tcx>, diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs new file mode 100644 index 00000000000..9228bea43f9 --- /dev/null +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -0,0 +1,18 @@ +// For more information about type metadata and type metadata identifiers for cross-language LLVM +// CFI support, see Type metadata in the design document in the tracking issue #89653. + +use rustc_middle::ty::{FnSig, Ty, TyCtxt}; +use rustc_target::abi::call::FnAbi; + +mod typeid_itanium_cxx_abi; +use typeid_itanium_cxx_abi::TypeIdOptions; + +/// Returns a type metadata identifier for the specified FnAbi. +pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { + typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS) +} + +/// Returns a type metadata identifier for the specified FnSig. +pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String { + typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS) +} diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs new file mode 100644 index 00000000000..a09b52fbfdf --- /dev/null +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -0,0 +1,929 @@ +// For more information about type metadata and type metadata identifiers for cross-language LLVM +// CFI support, see Type metadata in the design document in the tracking issue #89653. + +// FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective +// builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C" +// calling convention to use this encoding for cross-language LLVM CFI. + +use bitflags::bitflags; +use core::fmt::Display; +use rustc_data_structures::base_n; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; +use rustc_middle::ty::{ + self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, + Term, Ty, TyCtxt, UintTy, +}; +use rustc_span::def_id::DefId; +use rustc_span::symbol::sym; +use rustc_target::abi::call::{Conv, FnAbi}; +use rustc_target::spec::abi::Abi; +use std::fmt::Write as _; + +/// Type and extended type qualifiers. +#[derive(Eq, Hash, PartialEq)] +enum TyQ { + None, + Const, + Mut, +} + +/// Substitution dictionary key. +#[derive(Eq, Hash, PartialEq)] +enum DictKey<'tcx> { + Ty(Ty<'tcx>, TyQ), + Region(Region<'tcx>), + Const(Const<'tcx>), + Predicate(ExistentialPredicate<'tcx>), +} + +bitflags! { + /// Options for typeid_for_fnabi and typeid_for_fnsig. + pub struct TypeIdOptions: u32 { + const NO_OPTIONS = 0; + const GENERALIZE_POINTERS = 1; + const GENERALIZE_REPR_C = 2; + } +} + +/// Options for encode_ty. +type EncodeTyOptions = TypeIdOptions; + +/// Options for transform_ty. +type TransformTyOptions = TypeIdOptions; + +/// Converts a number to a disambiguator (see +/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>). +fn to_disambiguator(num: u64) -> String { + if let Some(num) = num.checked_sub(1) { + format!("s{}_", base_n::encode(num as u128, 62)) + } else { + "s_".to_string() + } +} + +/// Converts a number to a sequence number (see +/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>). +fn to_seq_id(num: usize) -> String { + if let Some(num) = num.checked_sub(1) { + base_n::encode(num as u128, 36).to_uppercase() + } else { + "".to_string() + } +} + +/// Substitutes a component if found in the substitution dictionary (see +/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression>). +fn compress<'tcx>( + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + key: DictKey<'tcx>, + comp: &mut String, +) { + match dict.get(&key) { + Some(num) => { + comp.clear(); + let _ = write!(comp, "S{}_", to_seq_id(*num)); + } + None => { + dict.insert(key, dict.len()); + } + } +} + +// FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly +// along with other is_c_type methods. +/// Returns whether a `ty::Ty` is `c_void`. +fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Adt(adt_def, ..) => { + let def_id = adt_def.0.did; + let crate_name = tcx.crate_name(def_id.krate); + if tcx.item_name(def_id).as_str() == "c_void" + && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc) + { + true + } else { + false + } + } + _ => false, + } +} + +/// Encodes a const using the Itanium C++ ABI as a literal argument (see +/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>). +fn encode_const<'tcx>( + tcx: TyCtxt<'tcx>, + c: Const<'tcx>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: EncodeTyOptions, +) -> String { + // L<element-type>[n]<element-value>E as literal argument + let mut s = String::from('L'); + + // Element type + s.push_str(&encode_ty(tcx, c.ty(), dict, options)); + + // The only allowed types of const parameters are bool, u8, u16, u32, u64, u128, usize i8, i16, + // i32, i64, i128, isize, and char. The bool value false is encoded as 0 and true as 1. + fn push_signed_value<T: Display + PartialOrd>(s: &mut String, value: T, zero: T) { + if value < zero { + s.push('n') + }; + let _ = write!(s, "{}", value); + } + + fn push_unsigned_value<T: Display>(s: &mut String, value: T) { + let _ = write!(s, "{}", value); + } + + if let Some(scalar_int) = c.kind().try_to_scalar_int() { + let signed = c.ty().is_signed(); + match scalar_int.size().bits() { + 8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0), + 16 if signed => push_signed_value(&mut s, scalar_int.try_to_i16().unwrap(), 0), + 32 if signed => push_signed_value(&mut s, scalar_int.try_to_i32().unwrap(), 0), + 64 if signed => push_signed_value(&mut s, scalar_int.try_to_i64().unwrap(), 0), + 128 if signed => push_signed_value(&mut s, scalar_int.try_to_i128().unwrap(), 0), + 8 => push_unsigned_value(&mut s, scalar_int.try_to_u8().unwrap()), + 16 => push_unsigned_value(&mut s, scalar_int.try_to_u16().unwrap()), + 32 => push_unsigned_value(&mut s, scalar_int.try_to_u32().unwrap()), + 64 => push_unsigned_value(&mut s, scalar_int.try_to_u64().unwrap()), + 128 => push_unsigned_value(&mut s, scalar_int.try_to_u128().unwrap()), + _ => { + bug!("encode_const: unexpected size `{:?}`", scalar_int.size().bits()); + } + }; + } else { + bug!("encode_const: unexpected type `{:?}`", c.ty()); + } + + // Close the "L..E" pair + s.push('E'); + + compress(dict, DictKey::Const(c), &mut s); + + s +} + +/// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for +/// Rust types that are not used at the FFI boundary. +fn encode_fnsig<'tcx>( + tcx: TyCtxt<'tcx>, + fn_sig: &FnSig<'tcx>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: TypeIdOptions, +) -> String { + // Function types are delimited by an "F..E" pair + let mut s = String::from("F"); + + let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits())); + match fn_sig.abi { + Abi::C { .. } => { + encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); + } + _ => { + encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); + } + } + + // Encode the return type + let transform_ty_options = TransformTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits())); + let ty = transform_ty(tcx, fn_sig.output(), transform_ty_options); + s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); + + // Encode the parameter types + let tys = fn_sig.inputs(); + if !tys.is_empty() { + for ty in tys { + let ty = transform_ty(tcx, *ty, transform_ty_options); + s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); + } + + if fn_sig.c_variadic { + s.push('z'); + } + } else { + if fn_sig.c_variadic { + s.push('z'); + } else { + // Empty parameter lists, whether declared as () or conventionally as (void), are + // encoded with a void parameter specifier "v". + s.push('v') + } + } + + // Close the "F..E" pair + s.push('E'); + + s +} + +/// Encodes a predicate using the Itanium C++ ABI with vendor extended type qualifiers and types for +/// Rust types that are not used at the FFI boundary. +fn encode_predicate<'tcx>( + tcx: TyCtxt<'tcx>, + predicate: Binder<'tcx, ExistentialPredicate<'tcx>>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: EncodeTyOptions, +) -> String { + // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>, as vendor + // extended type. + let mut s = String::new(); + match predicate.as_ref().skip_binder() { + ty::ExistentialPredicate::Trait(trait_ref) => { + let name = encode_ty_name(tcx, trait_ref.def_id); + let _ = write!(s, "u{}{}", name.len(), &name); + s.push_str(&encode_substs(tcx, trait_ref.substs, dict, options)); + } + ty::ExistentialPredicate::Projection(projection) => { + let name = encode_ty_name(tcx, projection.item_def_id); + let _ = write!(s, "u{}{}", name.len(), &name); + s.push_str(&encode_substs(tcx, projection.substs, dict, options)); + match projection.term { + Term::Ty(ty) => { + s.push_str(&encode_ty(tcx, ty, dict, options)); + } + Term::Const(c) => { + s.push_str(&encode_const(tcx, c, dict, options)); + } + } + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + let name = encode_ty_name(tcx, *def_id); + let _ = write!(s, "u{}{}", name.len(), &name); + } + }; + compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s); + s +} + +/// Encodes predicates using the Itanium C++ ABI with vendor extended type qualifiers and types for +/// Rust types that are not used at the FFI boundary. +fn encode_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List<Binder<'tcx, ExistentialPredicate<'tcx>>>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: EncodeTyOptions, +) -> String { + // <predicate1[..predicateN]>E as part of vendor extended type + let mut s = String::new(); + let predicates: Vec<Binder<'tcx, ExistentialPredicate<'tcx>>> = + predicates.iter().map(|predicate| predicate).collect(); + for predicate in predicates { + s.push_str(&encode_predicate(tcx, predicate, dict, options)); + } + s +} + +/// Encodes a region using the Itanium C++ ABI as a vendor extended type. +fn encode_region<'tcx>( + _tcx: TyCtxt<'tcx>, + region: Region<'tcx>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + _options: EncodeTyOptions, +) -> String { + // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type + let mut s = String::new(); + match region.kind() { + RegionKind::ReLateBound(debruijn, r) => { + s.push_str("u6regionI"); + // Debruijn index, which identifies the binder, as region disambiguator + let num = debruijn.index() as u64; + if num > 0 { + s.push_str(&to_disambiguator(num)); + } + // Index within the binder + let _ = write!(s, "{}", r.var.index() as u64); + s.push('E'); + compress(dict, DictKey::Region(region), &mut s); + } + RegionKind::ReErased => { + s.push_str("u6region"); + compress(dict, DictKey::Region(region), &mut s); + } + RegionKind::ReEarlyBound(..) + | RegionKind::ReFree(..) + | RegionKind::ReStatic + | RegionKind::ReVar(..) + | RegionKind::RePlaceholder(..) + | RegionKind::ReEmpty(..) => { + bug!("encode_region: unexpected `{:?}`", region.kind()); + } + } + s +} + +/// Encodes substs using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust +/// types that are not used at the FFI boundary. +fn encode_substs<'tcx>( + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: EncodeTyOptions, +) -> String { + // [I<subst1..substN>E] as part of vendor extended type + let mut s = String::new(); + let substs: Vec<GenericArg<'_>> = substs.iter().map(|subst| subst).collect(); + if !substs.is_empty() { + s.push('I'); + for subst in substs { + match subst.unpack() { + GenericArgKind::Lifetime(region) => { + s.push_str(&encode_region(tcx, region, dict, options)); + } + GenericArgKind::Type(ty) => { + s.push_str(&encode_ty(tcx, ty, dict, options)); + } + GenericArgKind::Const(c) => { + s.push_str(&encode_const(tcx, c, dict, options)); + } + } + } + s.push('E'); + } + s +} + +/// Encodes a ty:Ty name, including its crate and path disambiguators and names. +fn encode_ty_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> String { + // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where + // <element-type> is <subst>, using v0's <path> without v0's extended form of paths: + // + // N<namespace-tagN>..N<namespace-tag1> + // C<crate-disambiguator><crate-name> + // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN> + // + // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance: + // + // pub type Type1 = impl Send; + // let _: Type1 = <Struct1<i32>>::foo; + // fn foo1(_: Type1) { } + // + // pub type Type2 = impl Send; + // let _: Type2 = <Trait1<i32>>::foo; + // fn foo2(_: Type2) { } + // + // pub type Type3 = impl Send; + // let _: Type3 = <i32 as Trait1<i32>>::foo; + // fn foo3(_: Type3) { } + // + // pub type Type4 = impl Send; + // let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo; + // fn foo3(_: Type4) { } + // + // Are encoded as: + // + // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE + // + // The reason for not using v0's extended form of paths is to use a consistent and simpler + // encoding, as the reasoning for using it isn't relevand for type metadata identifiers (i.e., + // keep symbol names close to how methods are represented in error messages). See + // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods. + let mut s = String::new(); + + // Start and namespace tags + let mut def_path = tcx.def_path(def_id); + def_path.data.reverse(); + for disambiguated_data in &def_path.data { + s.push('N'); + s.push_str(match disambiguated_data.data { + hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace> + hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace> + hir::definitions::DefPathData::TypeNs(..) => "t", + hir::definitions::DefPathData::ValueNs(..) => "v", + hir::definitions::DefPathData::ClosureExpr => "C", + hir::definitions::DefPathData::Ctor => "c", + hir::definitions::DefPathData::AnonConst => "k", + hir::definitions::DefPathData::ImplTrait => "i", + hir::definitions::DefPathData::CrateRoot + | hir::definitions::DefPathData::Use + | hir::definitions::DefPathData::GlobalAsm + | hir::definitions::DefPathData::MacroNs(..) + | hir::definitions::DefPathData::LifetimeNs(..) => { + bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); + } + }); + } + + // Crate disambiguator and name + s.push('C'); + s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64())); + let crate_name = tcx.crate_name(def_path.krate).to_string(); + let _ = write!(s, "{}{}", crate_name.len(), &crate_name); + + // Disambiguators and names + def_path.data.reverse(); + for disambiguated_data in &def_path.data { + let num = disambiguated_data.disambiguator as u64; + if num > 0 { + s.push_str(&to_disambiguator(num)); + } + + let name = disambiguated_data.data.to_string(); + let _ = write!(s, "{}", name.len()); + + // Prepend a '_' if name starts with a digit or '_' + if let Some(first) = name.as_bytes().get(0) { + if first.is_ascii_digit() || *first == b'_' { + s.push('_'); + } + } else { + bug!("encode_ty_name: invalid name `{:?}`", name); + } + + s.push_str(&name); + } + + s +} + +/// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for +/// Rust types that are not used at the FFI boundary. +fn encode_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: EncodeTyOptions, +) -> String { + let mut typeid = String::new(); + + match ty.kind() { + // Primitive types + ty::Bool => { + typeid.push('b'); + } + + ty::Int(..) | ty::Uint(..) | ty::Float(..) => { + // u<length><type-name> as vendor extended type + let mut s = String::from(match ty.kind() { + ty::Int(IntTy::I8) => "u2i8", + ty::Int(IntTy::I16) => "u3i16", + ty::Int(IntTy::I32) => "u3i32", + ty::Int(IntTy::I64) => "u3i64", + ty::Int(IntTy::I128) => "u4i128", + ty::Int(IntTy::Isize) => "u5isize", + ty::Uint(UintTy::U8) => "u2u8", + ty::Uint(UintTy::U16) => "u3u16", + ty::Uint(UintTy::U32) => "u3u32", + ty::Uint(UintTy::U64) => "u3u64", + ty::Uint(UintTy::U128) => "u4u128", + ty::Uint(UintTy::Usize) => "u5usize", + ty::Float(FloatTy::F32) => "u3f32", + ty::Float(FloatTy::F64) => "u3f64", + _ => "", + }); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + ty::Char => { + // u4char as vendor extended type + let mut s = String::from("u4char"); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + ty::Str => { + // u3str as vendor extended type + let mut s = String::from("u3str"); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + ty::Never => { + // u5never as vendor extended type + let mut s = String::from("u5never"); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + // Compound types + // () in Rust is equivalent to void return type in C + _ if ty.is_unit() => { + typeid.push('v'); + } + + // Sequence types + ty::Tuple(tys) => { + // u5tupleI<element-type1..element-typeN>E as vendor extended type + let mut s = String::from("u5tupleI"); + for ty in tys.iter() { + s.push_str(&encode_ty(tcx, ty, dict, options)); + } + s.push('E'); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + ty::Array(ty0, len) => { + // A<array-length><element-type> + let mut s = String::from("A"); + let _ = write!(s, "{}", &len.kind().try_to_scalar().unwrap().to_u64().unwrap()); + s.push_str(&encode_ty(tcx, *ty0, dict, options)); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + ty::Slice(ty0) => { + // u5sliceI<element-type>E as vendor extended type + let mut s = String::from("u5sliceI"); + s.push_str(&encode_ty(tcx, *ty0, dict, options)); + s.push('E'); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + // User-defined types + ty::Adt(adt_def, substs) => { + let mut s = String::new(); + let def_id = adt_def.0.did; + if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() { + // For for cross-language CFI support, the encoding must be compatible at the FFI + // boundary. For instance: + // + // struct type1 {}; + // void foo(struct type1* bar) {} + // + // Is encoded as: + // + // _ZTSFvP5type1E + // + // So, encode any repr(C) user-defined type for extern function types with the "C" + // calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where + // <name> is <unscoped-name>. + let name = tcx.item_name(def_id).to_string(); + let _ = write!(s, "{}{}", name.len(), &name); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + } else { + // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is + // <subst>, as vendor extended type. + let name = encode_ty_name(tcx, def_id); + let _ = write!(s, "u{}{}", name.len(), &name); + s.push_str(&encode_substs(tcx, substs, dict, options)); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + } + typeid.push_str(&s); + } + + ty::Foreign(def_id) => { + // <length><name>, where <name> is <unscoped-name> + let mut s = String::new(); + let name = tcx.item_name(*def_id).to_string(); + let _ = write!(s, "{}{}", name.len(), &name); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + // Function types + ty::FnDef(def_id, substs) + | ty::Closure(def_id, substs) + | ty::Generator(def_id, substs, ..) => { + // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>, + // as vendor extended type. + let mut s = String::new(); + let name = encode_ty_name(tcx, *def_id); + let _ = write!(s, "u{}{}", name.len(), &name); + s.push_str(&encode_substs(tcx, substs, dict, options)); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + // Pointer types + ty::Ref(region, ty0, ..) => { + // [U3mut]u3refI<element-type>E as vendor extended type qualifier and type + let mut s = String::new(); + s.push_str("u3refI"); + s.push_str(&encode_ty(tcx, *ty0, dict, options)); + s.push('E'); + compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s); + if ty.is_mutable_ptr() { + s = format!("{}{}", "U3mut", &s); + compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s); + } + typeid.push_str(&s); + } + + ty::RawPtr(tm) => { + // P[K]<element-type> + let mut s = String::new(); + s.push_str(&encode_ty(tcx, tm.ty, dict, options)); + if !ty.is_mutable_ptr() { + s = format!("{}{}", "K", &s); + compress(dict, DictKey::Ty(tm.ty, TyQ::Const), &mut s); + }; + s = format!("{}{}", "P", &s); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + ty::FnPtr(fn_sig) => { + // PF<return-type><parameter-type1..parameter-typeN>E + let mut s = String::from("P"); + s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS)); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + // Trait types + ty::Dynamic(predicates, region) => { + // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as + // vendor extended type. + let mut s = String::from("u3dynI"); + s.push_str(&encode_predicates(tcx, predicates, dict, options)); + s.push_str(&encode_region(tcx, *region, dict, options)); + s.push('E'); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + + // Unexpected types + ty::Bound(..) + | ty::Error(..) + | ty::GeneratorWitness(..) + | ty::Infer(..) + | ty::Opaque(..) + | ty::Param(..) + | ty::Placeholder(..) + | ty::Projection(..) => { + bug!("encode_ty: unexpected `{:?}`", ty.kind()); + } + }; + + typeid +} + +// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all +// c_void types into unit types unconditionally, and generalizes all pointers if +// TransformTyOptions::GENERALIZE_POINTERS option is set. +fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> { + let mut ty = ty; + + match ty.kind() { + ty::Bool + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Char + | ty::Str + | ty::Never + | ty::Foreign(..) + | ty::Dynamic(..) => {} + + _ if ty.is_unit() => {} + + ty::Tuple(tys) => { + ty = tcx.mk_tup(tys.iter().map(|ty| transform_ty(tcx, ty, options))); + } + + ty::Array(ty0, len) => { + let len = len.kind().try_to_scalar().unwrap().to_u64().unwrap(); + ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len); + } + + ty::Slice(ty0) => { + ty = tcx.mk_slice(transform_ty(tcx, *ty0, options)); + } + + ty::Adt(adt_def, substs) => { + if is_c_void_ty(tcx, ty) { + ty = tcx.mk_unit(); + } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() + { + ty = tcx.mk_adt(*adt_def, ty::List::empty()); + } else if adt_def.repr().transparent() && adt_def.is_struct() { + let variant = adt_def.non_enum_variant(); + let param_env = tcx.param_env(variant.def_id); + let field = variant.fields.iter().find(|field| { + let ty = tcx.type_of(field.did); + let is_zst = + tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst()); + !is_zst + }); + if field.is_none() { + // Transform repr(transparent) types without non-ZST field into () + ty = tcx.mk_unit(); + } else { + let ty0 = tcx.type_of(field.unwrap().did); + // Generalize any repr(transparent) user-defined type that is either a pointer + // or reference, and either references itself or any other type that contains or + // references itself, to avoid a reference cycle. + if ty0.is_any_ptr() && ty0.contains(ty) { + ty = transform_ty( + tcx, + ty0, + options | TransformTyOptions::GENERALIZE_POINTERS, + ); + } else { + ty = transform_ty(tcx, ty0, options); + } + } + } else { + ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options)); + } + } + + ty::FnDef(def_id, substs) => { + ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options)); + } + + ty::Closure(def_id, substs) => { + ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options)); + } + + ty::Generator(def_id, substs, movability) => { + ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability); + } + + ty::Ref(region, ty0, ..) => { + if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if ty.is_mutable_ptr() { + ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit()); + } else { + ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit()); + } + } else { + if ty.is_mutable_ptr() { + ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options)); + } else { + ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options)); + } + } + } + + ty::RawPtr(tm) => { + if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if ty.is_mutable_ptr() { + ty = tcx.mk_mut_ptr(tcx.mk_unit()); + } else { + ty = tcx.mk_imm_ptr(tcx.mk_unit()); + } + } else { + if ty.is_mutable_ptr() { + ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options)); + } else { + ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options)); + } + } + } + + ty::FnPtr(fn_sig) => { + if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + ty = tcx.mk_imm_ptr(tcx.mk_unit()); + } else { + let parameters: Vec<Ty<'tcx>> = fn_sig + .skip_binder() + .inputs() + .iter() + .map(|ty| transform_ty(tcx, *ty, options)) + .collect(); + let output = transform_ty(tcx, fn_sig.skip_binder().output(), options); + ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars( + tcx.mk_fn_sig( + parameters.iter(), + &output, + fn_sig.c_variadic(), + fn_sig.unsafety(), + fn_sig.abi(), + ), + fn_sig.bound_vars(), + )); + } + } + + ty::Bound(..) + | ty::Error(..) + | ty::GeneratorWitness(..) + | ty::Infer(..) + | ty::Opaque(..) + | ty::Param(..) + | ty::Placeholder(..) + | ty::Projection(..) => { + bug!("transform_ty: unexpected `{:?}`", ty.kind()); + } + } + + ty +} + +/// Transforms substs for being encoded and used in the substitution dictionary. +fn transform_substs<'tcx>( + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + options: TransformTyOptions, +) -> SubstsRef<'tcx> { + let substs: Vec<GenericArg<'tcx>> = substs + .iter() + .map(|subst| { + if let GenericArgKind::Type(ty) = subst.unpack() { + if is_c_void_ty(tcx, ty) { + tcx.mk_unit().into() + } else { + transform_ty(tcx, ty, options).into() + } + } else { + subst + } + }) + .collect(); + tcx.mk_substs(substs.iter()) +} + +/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor +/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. +pub fn typeid_for_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + options: TypeIdOptions, +) -> String { + // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions + // its type. + let mut typeid = String::from("_Z"); + + // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type + // metadata identifiers for function pointers. The typeinfo name encoding is a two-character + // code (i.e., 'TS') prefixed to the type encoding for the function. + typeid.push_str("TS"); + + // Function types are delimited by an "F..E" pair + typeid.push('F'); + + // A dictionary of substitution candidates used for compression (see + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). + let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default(); + + let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); + match fn_abi.conv { + Conv::C => { + encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); + } + _ => { + encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); + } + } + + // Encode the return type + let transform_ty_options = TransformTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); + let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + + // Encode the parameter types + if !fn_abi.c_variadic { + if !fn_abi.args.is_empty() { + for arg in fn_abi.args.iter() { + let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + } else { + // Empty parameter lists, whether declared as () or conventionally as (void), are + // encoded with a void parameter specifier "v". + typeid.push('v'); + } + } else { + for n in 0..fn_abi.fixed_count { + let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + + typeid.push('z'); + } + + // Close the "F..E" pair + typeid.push('E'); + + typeid +} + +/// Returns a type metadata identifier for the specified FnSig using the Itanium C++ ABI with vendor +/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. +pub fn typeid_for_fnsig<'tcx>( + tcx: TyCtxt<'tcx>, + fn_sig: &FnSig<'tcx>, + options: TypeIdOptions, +) -> String { + // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions + // its type. + let mut typeid = String::from("_Z"); + + // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type + // metadata identifiers for function pointers. The typeinfo name encoding is a two-character + // code (i.e., 'TS') prefixed to the type encoding for the function. + typeid.push_str("TS"); + + // A dictionary of substitution candidates used for compression (see + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). + let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default(); + + // Encode the function signature + typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options)); + + typeid +} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 79e3f10526c..71fa5a44887 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -12,7 +12,6 @@ use rustc_middle::ty::{ self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy, }; use rustc_span::symbol::kw; -use rustc_target::abi::call::FnAbi; use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; @@ -59,41 +58,6 @@ pub(super) fn mangle<'tcx>( std::mem::take(&mut cx.out) } -pub(super) fn mangle_typeid_for_fnabi<'tcx>( - _tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, -) -> String { - // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This - // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is - // associated with a type identifier (i.e., test type membership). - // - // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as - // type metadata identifiers for function pointers. The typeinfo name encoding is a - // two-character code (i.e., “TS”) prefixed to the type encoding for the function. - // - // For cross-language LLVM CFI support, a compatible encoding must be used by either - // - // a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's - // type encodings[4]), or at least types used at the FFI boundary. - // b. Reducing the types to the least common denominator between types used by Clang (or at - // least types used at the FFI boundary) and Rust compilers (if even possible). - // c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and - // possibly other compilers). - // - // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided - // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled - // code. Option (c) would require changes to Clang to use the new ABI. - // - // [1] https://llvm.org/docs/TypeMetadata.html - // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html - // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables - // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type - // - // FIXME(rcvalle): See comment above. - let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - format!("typeid{}", arg_count) -} - pub(super) fn mangle_typeid_for_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyExistentialTraitRef<'tcx>, diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs index 5e31859aaef..c85f7f62a42 100644 --- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs @@ -17,6 +17,7 @@ pub fn target() -> Target { supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS | SanitizerSet::MEMTAG + | SanitizerSet::SHADOWCALLSTACK | SanitizerSet::ADDRESS, ..super::android_base::opts() }, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1a6bb4a2eaf..f7abeafd38f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -618,6 +618,7 @@ bitflags::bitflags! { const HWADDRESS = 1 << 4; const CFI = 1 << 5; const MEMTAG = 1 << 6; + const SHADOWCALLSTACK = 1 << 7; } } @@ -632,6 +633,7 @@ impl SanitizerSet { SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::MEMTAG => "memtag", + SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack", SanitizerSet::THREAD => "thread", SanitizerSet::HWADDRESS => "hwaddress", _ => return None, @@ -666,6 +668,7 @@ impl IntoIterator for SanitizerSet { SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::MEMTAG, + SanitizerSet::SHADOWCALLSTACK, SanitizerSet::THREAD, SanitizerSet::HWADDRESS, ] @@ -1960,6 +1963,7 @@ impl Target { Some("leak") => SanitizerSet::LEAK, Some("memory") => SanitizerSet::MEMORY, Some("memtag") => SanitizerSet::MEMTAG, + Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK, Some("thread") => SanitizerSet::THREAD, Some("hwaddress") => SanitizerSet::HWADDRESS, Some(s) => return Err(format!("unknown sanitizer {}", s)), diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index e6284b1c4ac..decbf013311 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -185,14 +185,20 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span)); match concrete { - Err(ErrorHandled::TooGeneric) => Err(if !uv.has_infer_types_or_consts() { + Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() { + NotConstEvaluatable::MentionsInfer + } else if uv.has_param_types_or_consts() { infcx .tcx .sess .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv)); NotConstEvaluatable::MentionsParam } else { - NotConstEvaluatable::MentionsInfer + let guar = infcx.tcx.sess.delay_span_bug( + span, + format!("Missing value for constant, but no error reported?"), + ); + NotConstEvaluatable::Error(guar) }), Err(ErrorHandled::Linted) => { let reported = infcx @@ -240,8 +246,11 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() { NotConstEvaluatable::MentionsInfer - } else { + } else if uv.has_param_types_or_consts() { NotConstEvaluatable::MentionsParam + } else { + let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?")); + NotConstEvaluatable::Error(guar) }), Err(ErrorHandled::Linted) => { let reported = diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5636c74452c..7ab85e7fa66 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -378,7 +378,7 @@ fn suggest_restriction<'tcx>( replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name)) .to_ty(tcx), }); - if !trait_pred.is_suggestable(tcx) { + if !trait_pred.is_suggestable(tcx, false) { return; } // We know we have an `impl Trait` that doesn't satisfy a required projection. @@ -417,7 +417,7 @@ fn suggest_restriction<'tcx>( Applicability::MaybeIncorrect, ); } else { - if !trait_pred.is_suggestable(tcx) { + if !trait_pred.is_suggestable(tcx, false) { return; } // Trivial case: `T` needs an extra bound: `T: Bound`. @@ -586,7 +586,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // else in the predicate. if !trait_pred.skip_binder().trait_ref.substs[1..] .iter() - .all(|g| g.is_suggestable(self.tcx)) + .all(|g| g.is_suggestable(self.tcx, false)) { return; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 6b758ba63cd..414857f0acc 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -85,7 +85,7 @@ pub fn trait_obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, - trait_ref: &ty::TraitRef<'tcx>, + trait_pred: &ty::TraitPredicate<'tcx>, span: Span, item: &'tcx hir::Item<'tcx>, ) -> Vec<traits::PredicateObligation<'tcx>> { @@ -98,7 +98,7 @@ pub fn trait_obligations<'a, 'tcx>( recursion_depth: 0, item: Some(item), }; - wf.compute_trait_ref(trait_ref, Elaborate::All); + wf.compute_trait_pred(trait_pred, Elaborate::All); debug!(obligations = ?wf.out); wf.normalize(infcx) } @@ -123,7 +123,7 @@ pub fn predicate_obligations<'a, 'tcx>( // It's ok to skip the binder here because wf code is prepared for it match predicate.kind().skip_binder() { ty::PredicateKind::Trait(t) => { - wf.compute_trait_ref(&t.trait_ref, Elaborate::None); + wf.compute_trait_pred(&t, Elaborate::None); } ty::PredicateKind::RegionOutlives(..) => {} ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { @@ -301,11 +301,18 @@ impl<'tcx> WfPredicates<'tcx> { } /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { + fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) { let tcx = self.tcx; - let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); + let trait_ref = &trait_pred.trait_ref; - debug!("compute_trait_ref obligations {:?}", obligations); + // if the trait predicate is not const, the wf obligations should not be const as well. + let obligations = if trait_pred.constness == ty::BoundConstness::NotConst { + self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs) + } else { + self.nominal_obligations(trait_ref.def_id, trait_ref.substs) + }; + + debug!("compute_trait_pred obligations {:?}", obligations); let param_env = self.param_env; let depth = self.recursion_depth; @@ -685,10 +692,11 @@ impl<'tcx> WfPredicates<'tcx> { } #[instrument(level = "debug", skip(self))] - fn nominal_obligations( + fn nominal_obligations_inner( &mut self, def_id: DefId, substs: SubstsRef<'tcx>, + remap_constness: bool, ) -> Vec<traits::PredicateObligation<'tcx>> { let predicates = self.tcx.predicates_of(def_id); let mut origins = vec![def_id; predicates.predicates.len()]; @@ -703,19 +711,38 @@ impl<'tcx> WfPredicates<'tcx> { debug_assert_eq!(predicates.predicates.len(), origins.len()); iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) - .map(|((pred, span), origin_def_id)| { + .map(|((mut pred, span), origin_def_id)| { let code = if span.is_dummy() { traits::MiscObligation } else { traits::BindingObligation(origin_def_id, span) }; let cause = self.cause(code); + if remap_constness { + pred = pred.without_const(self.tcx); + } traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred) }) .filter(|pred| !pred.has_escaping_bound_vars()) .collect() } + fn nominal_obligations( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Vec<traits::PredicateObligation<'tcx>> { + self.nominal_obligations_inner(def_id, substs, false) + } + + fn nominal_obligations_without_const( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Vec<traits::PredicateObligation<'tcx>> { + self.nominal_obligations_inner(def_id, substs, true) + } + fn from_object_ty( &mut self, ty: Ty<'tcx>, diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 5e58f237982..979e997f244 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -280,6 +280,11 @@ fn resolve_associated_item<'tcx>( return Ok(None); } + // If the item does not have a value, then we cannot return an instance. + if !leaf_def.item.defaultness.has_value() { + return Ok(None); + } + let substs = tcx.erase_regions(substs); // Check if we just resolved an associated `const` declaration from diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 612dc384521..40aa27a29e9 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_type = tcx.infer_ctxt().enter(|infcx| { infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id)) }); - if param_type.is_suggestable(tcx) { + if param_type.is_suggestable(tcx, false) { err.span_suggestion( tcx.def_span(src_def_id), "consider changing this type parameter to be a `const` generic", diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 9e4da058052..7111812f0b0 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2676,7 +2676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, ty, opt_sugg: Some((span, Applicability::MachineApplicable)) - .filter(|_| ty.is_suggestable(tcx)), + .filter(|_| ty.is_suggestable(tcx, false)), }); ty diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 1555f4f3fd6..84d2878308a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1070,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; if expected_ty.is_unit() { "()".to_string() - } else if expected_ty.is_suggestable(tcx) { + } else if expected_ty.is_suggestable(tcx, false) { format!("/* {} */", expected_ty) } else { "/* value */".to_string() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 3e6ff72204f..097fff6418e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -506,7 +506,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); // Only suggest changing the return type for methods that // haven't set a return type at all (and aren't `fn main()` or an impl). - match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) { + match ( + &fn_decl.output, + found.is_suggestable(self.tcx, false), + can_suggest, + expected.is_unit(), + ) { (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found }); true diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 1b80e4edca9..b8e998229ba 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -183,7 +183,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match (tcx.impl_polarity(def_id), impl_.polarity) { (ty::ImplPolarity::Positive, _) => { - check_impl(tcx, item, impl_.self_ty, &impl_.of_trait); + check_impl(tcx, item, impl_.self_ty, &impl_.of_trait, impl_.constness); } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { // FIXME(#27579): what amount of WF checking do we need for neg impls? @@ -1242,6 +1242,7 @@ fn check_impl<'tcx>( item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option<hir::TraitRef<'_>>, + constness: hir::Constness, ) { enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { match *ast_trait_ref { @@ -1251,11 +1252,19 @@ fn check_impl<'tcx>( // won't hold). let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap(); let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref); + let trait_pred = ty::TraitPredicate { + trait_ref, + constness: match constness { + hir::Constness::Const => ty::BoundConstness::ConstIfConst, + hir::Constness::NotConst => ty::BoundConstness::NotConst, + }, + polarity: ty::ImplPolarity::Positive, + }; let obligations = traits::wf::trait_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_id, - &trait_ref, + &trait_pred, ast_trait_ref.path.span, item, ); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 24e6a5d3047..c562599e2cc 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1929,7 +1929,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( visitor.visit_ty(ty); let mut diag = bad_placeholder(tcx, visitor.0, "return type"); let ret_ty = fn_sig.skip_binder().output(); - if ret_ty.is_suggestable(tcx) { + if ret_ty.is_suggestable(tcx, false) { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -1938,7 +1938,12 @@ fn infer_return_ty_for_fn_sig<'tcx>( ); } else if matches!(ret_ty.kind(), ty::FnDef(..)) { let fn_sig = ret_ty.fn_sig(tcx); - if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) { + if fn_sig + .skip_binder() + .inputs_and_output + .iter() + .all(|t| t.is_suggestable(tcx, false)) + { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -2969,6 +2974,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { 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) { @@ -2976,7 +2983,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } else { tcx.sess .struct_span_err(item.span(), "invalid argument for `no_sanitize`") - .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`") + .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") .emit(); } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index dc82b32214c..9ae31a31aaa 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2625,6 +2625,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 55f781ce022..6cdbab30589 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1144,6 +1144,7 @@ impl<T: ?Sized> *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(self) -> T where T: Sized, @@ -1164,6 +1165,7 @@ impl<T: ?Sized> *const T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1183,6 +1185,7 @@ impl<T: ?Sized> *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(self) -> T where T: Sized, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 62548b5fadd..40e28e636d8 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1095,6 +1095,7 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read<T>(src: *const T) -> T { // We are calling the intrinsics directly to avoid function calls in the generated code // as `intrinsics::copy_nonoverlapping` is a wrapper function. @@ -1194,6 +1195,7 @@ pub const unsafe fn read<T>(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned<T>(src: *const T) -> T { let mut tmp = MaybeUninit::<T>::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. @@ -1290,6 +1292,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write<T>(dst: *mut T, src: T) { // We are calling the intrinsics directly to avoid function calls in the generated code // as `intrinsics::copy_nonoverlapping` is a wrapper function. @@ -1387,6 +1390,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access @@ -1460,6 +1464,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn read_volatile<T>(src: *const T) -> T { // SAFETY: the caller must uphold the safety contract for `volatile_load`. unsafe { @@ -1530,6 +1535,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn write_volatile<T>(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. unsafe { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 27e8b20b3c5..e323f63115b 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1258,6 +1258,7 @@ impl<T: ?Sized> *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(self) -> T where T: Sized, @@ -1278,6 +1279,7 @@ impl<T: ?Sized> *mut T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1297,6 +1299,7 @@ impl<T: ?Sized> *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1402,6 +1405,7 @@ impl<T: ?Sized> *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write(self, val: T) where T: Sized, @@ -1420,6 +1424,7 @@ impl<T: ?Sized> *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, @@ -1440,6 +1445,7 @@ impl<T: ?Sized> *mut T { /// [`ptr::write_volatile`]: crate::ptr::write_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn write_volatile(self, val: T) where T: Sized, @@ -1459,6 +1465,7 @@ impl<T: ?Sized> *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_unaligned(self, val: T) where T: Sized, diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index b636dc491a4..5e2e0c4d8cc 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -449,6 +449,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn load(&self, order: Ordering) -> bool { // SAFETY: any data races are prevented by atomic intrinsics and the raw // pointer passed in is valid because we got it from a reference. @@ -476,6 +477,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn store(&self, val: bool, order: Ordering) { // SAFETY: any data races are prevented by atomic intrinsics and the raw // pointer passed in is valid because we got it from a reference. @@ -507,6 +509,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn swap(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 } @@ -563,6 +566,7 @@ impl AtomicBool { note = "Use `compare_exchange` or `compare_exchange_weak` instead" )] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -610,6 +614,7 @@ impl AtomicBool { #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange( &self, current: bool, @@ -664,6 +669,7 @@ impl AtomicBool { #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange_weak( &self, current: bool, @@ -715,6 +721,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_and(self.v.get(), val as u8, order) != 0 } @@ -756,6 +763,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done @@ -807,6 +815,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_or(self.v.get(), val as u8, order) != 0 } @@ -847,6 +856,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } @@ -884,6 +894,7 @@ impl AtomicBool { #[inline] #[unstable(feature = "atomic_bool_fetch_not", issue = "98485")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_not(&self, order: Ordering) -> bool { self.fetch_xor(true, order) } @@ -958,6 +969,7 @@ impl AtomicBool { #[inline] #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_update<F>( &self, set_order: Ordering, @@ -1165,6 +1177,7 @@ impl<T> AtomicPtr<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn load(&self, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_load(self.p.get(), order) } @@ -1193,6 +1206,7 @@ impl<T> AtomicPtr<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn store(&self, ptr: *mut T, order: Ordering) { // SAFETY: data races are prevented by atomic intrinsics. unsafe { @@ -1225,6 +1239,7 @@ impl<T> AtomicPtr<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.p.get(), ptr, order) } @@ -1280,6 +1295,7 @@ impl<T> AtomicPtr<T> { note = "Use `compare_exchange` or `compare_exchange_weak` instead" )] #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -1319,6 +1335,7 @@ impl<T> AtomicPtr<T> { #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange( &self, current: *mut T, @@ -1367,6 +1384,7 @@ impl<T> AtomicPtr<T> { #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange_weak( &self, current: *mut T, @@ -1427,6 +1445,7 @@ impl<T> AtomicPtr<T> { #[inline] #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_update<F>( &self, set_order: Ordering, @@ -1482,6 +1501,7 @@ impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::<T>()), order) } @@ -1526,6 +1546,7 @@ impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::<T>()), order) } @@ -1561,6 +1582,7 @@ impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1604,6 +1626,7 @@ impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1662,6 +1685,7 @@ impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1719,6 +1743,7 @@ impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -1774,6 +1799,7 @@ impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. @@ -2085,6 +2111,7 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn load(&self, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_load(self.v.get(), order) } @@ -2111,6 +2138,7 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn store(&self, val: $int_type, order: Ordering) { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_store(self.v.get(), val, order); } @@ -2138,6 +2166,7 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.v.get(), val, order) } @@ -2195,6 +2224,7 @@ macro_rules! atomic_int { note = "Use `compare_exchange` or `compare_exchange_weak` instead") ] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_and_swap(&self, current: $int_type, new: $int_type, @@ -2248,6 +2278,7 @@ macro_rules! atomic_int { #[inline] #[$stable_cxchg] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange(&self, current: $int_type, new: $int_type, @@ -2296,6 +2327,7 @@ macro_rules! atomic_int { #[inline] #[$stable_cxchg] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compare_exchange_weak(&self, current: $int_type, new: $int_type, @@ -2331,6 +2363,7 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_add(self.v.get(), val, order) } @@ -2360,6 +2393,7 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_sub(self.v.get(), val, order) } @@ -2392,6 +2426,7 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_and(self.v.get(), val, order) } @@ -2424,6 +2459,7 @@ macro_rules! atomic_int { #[inline] #[$stable_nand] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_nand(self.v.get(), val, order) } @@ -2456,6 +2492,7 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_or(self.v.get(), val, order) } @@ -2488,6 +2525,7 @@ macro_rules! atomic_int { #[inline] #[$stable] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.v.get(), val, order) } @@ -2528,6 +2566,7 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "no_more_cas", since = "1.45.0")] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_update<F>(&self, set_order: Ordering, fetch_order: Ordering, @@ -2581,6 +2620,7 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "atomic_min_max", since = "1.45.0")] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { $max_fn(self.v.get(), val, order) } @@ -2626,6 +2666,7 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "atomic_min_max", since = "1.45.0")] #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { $min_fn(self.v.get(), val, order) } @@ -2939,6 +2980,7 @@ fn strongest_failure_ordering(order: Ordering) -> Ordering { } #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) { // SAFETY: the caller must uphold the safety contract for `atomic_store`. unsafe { @@ -2953,6 +2995,7 @@ unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) { } #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_load`. unsafe { @@ -2968,6 +3011,7 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_swap`. unsafe { @@ -2984,6 +3028,7 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_add). #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_add`. unsafe { @@ -3000,6 +3045,7 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_sub). #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_sub`. unsafe { @@ -3015,6 +3061,7 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange<T: Copy>( dst: *mut T, old: T, @@ -3057,6 +3104,7 @@ unsafe fn atomic_compare_exchange<T: Copy>( #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange_weak<T: Copy>( dst: *mut T, old: T, @@ -3099,6 +3147,7 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>( #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_and` unsafe { @@ -3114,6 +3163,7 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_nand` unsafe { @@ -3129,6 +3179,7 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_or` unsafe { @@ -3144,6 +3195,7 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_xor` unsafe { @@ -3160,6 +3212,7 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (signed comparison) #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_max` unsafe { @@ -3176,6 +3229,7 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (signed comparison) #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_min` unsafe { @@ -3192,6 +3246,7 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (unsigned comparison) #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umax` unsafe { @@ -3208,6 +3263,7 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (unsigned comparison) #[inline] #[cfg(target_has_atomic = "8")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umin` unsafe { @@ -3298,6 +3354,7 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "fence"] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { @@ -3380,6 +3437,7 @@ pub fn fence(order: Ordering) { #[inline] #[stable(feature = "compiler_fences", since = "1.21.0")] #[rustc_diagnostic_item = "compiler_fence"] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn compiler_fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9fd426d3ac4..6b0c0ad7c21 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -276,6 +276,7 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(int_error_internals)] +#![feature(is_some_with)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_write_slice)] #![feature(mixed_integer_ops)] diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 6533625876f..36a3fa6023b 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -285,7 +285,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { ))] { #[cfg(any(target_os = "android", target_os = "linux"))] { - let quota = cgroup2_quota().max(1); + let quota = cgroups::quota().max(1); let mut set: libc::cpu_set_t = unsafe { mem::zeroed() }; unsafe { if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 { @@ -379,49 +379,88 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { } } -/// Returns cgroup CPU quota in core-equivalents, rounded down, or usize::MAX if the quota cannot -/// be determined or is not set. #[cfg(any(target_os = "android", target_os = "linux"))] -fn cgroup2_quota() -> usize { +mod cgroups { + //! Currently not covered + //! * cgroup v2 in non-standard mountpoints + //! * paths containing control characters or spaces, since those would be escaped in procfs + //! output and we don't unescape + use crate::borrow::Cow; use crate::ffi::OsString; use crate::fs::{try_exists, File}; use crate::io::Read; + use crate::io::{BufRead, BufReader}; use crate::os::unix::ffi::OsStringExt; + use crate::path::Path; use crate::path::PathBuf; + use crate::str::from_utf8; - let mut quota = usize::MAX; - if cfg!(miri) { - // Attempting to open a file fails under default flags due to isolation. - // And Miri does not have parallelism anyway. - return quota; - } - - let _: Option<()> = try { - let mut buf = Vec::with_capacity(128); - // find our place in the cgroup hierarchy - File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?; - let cgroup_path = buf - .split(|&c| c == b'\n') - .filter_map(|line| { - let mut fields = line.splitn(3, |&c| c == b':'); - // expect cgroupv2 which has an empty 2nd field - if fields.nth(1) != Some(b"") { - return None; - } - let path = fields.last()?; - // skip leading slash - Some(path[1..].to_owned()) - }) - .next()?; - let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path)); + #[derive(PartialEq)] + enum Cgroup { + V1, + V2, + } + + /// Returns cgroup CPU quota in core-equivalents, rounded down or usize::MAX if the quota cannot + /// be determined or is not set. + pub(super) fn quota() -> usize { + let mut quota = usize::MAX; + if cfg!(miri) { + // Attempting to open a file fails under default flags due to isolation. + // And Miri does not have parallelism anyway. + return quota; + } + + let _: Option<()> = try { + let mut buf = Vec::with_capacity(128); + // find our place in the cgroup hierarchy + File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?; + let (cgroup_path, version) = + buf.split(|&c| c == b'\n').fold(None, |previous, line| { + let mut fields = line.splitn(3, |&c| c == b':'); + // 2nd field is a list of controllers for v1 or empty for v2 + let version = match fields.nth(1) { + Some(b"") => Cgroup::V2, + Some(controllers) + if from_utf8(controllers) + .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) => + { + Cgroup::V1 + } + _ => return previous, + }; + + // already-found v1 trumps v2 since it explicitly specifies its controllers + if previous.is_some() && version == Cgroup::V2 { + return previous; + } + + let path = fields.last()?; + // skip leading slash + Some((path[1..].to_owned(), version)) + })?; + let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path)); + + quota = match version { + Cgroup::V1 => quota_v1(cgroup_path), + Cgroup::V2 => quota_v2(cgroup_path), + }; + }; + + quota + } + + fn quota_v2(group_path: PathBuf) -> usize { + let mut quota = usize::MAX; let mut path = PathBuf::with_capacity(128); let mut read_buf = String::with_capacity(20); + // standard mount location defined in file-hierarchy(7) manpage let cgroup_mount = "/sys/fs/cgroup"; path.push(cgroup_mount); - path.push(&cgroup_path); + path.push(&group_path); path.push("cgroup.controllers"); @@ -432,30 +471,134 @@ fn cgroup2_quota() -> usize { path.pop(); - while path.starts_with(cgroup_mount) { - path.push("cpu.max"); + let _: Option<()> = try { + while path.starts_with(cgroup_mount) { + path.push("cpu.max"); + + read_buf.clear(); + + if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() { + let raw_quota = read_buf.lines().next()?; + let mut raw_quota = raw_quota.split(' '); + let limit = raw_quota.next()?; + let period = raw_quota.next()?; + match (limit.parse::<usize>(), period.parse::<usize>()) { + (Ok(limit), Ok(period)) => { + quota = quota.min(limit / period); + } + _ => {} + } + } - read_buf.clear(); + path.pop(); // pop filename + path.pop(); // pop dir + } + }; - if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() { - let raw_quota = read_buf.lines().next()?; - let mut raw_quota = raw_quota.split(' '); - let limit = raw_quota.next()?; - let period = raw_quota.next()?; - match (limit.parse::<usize>(), period.parse::<usize>()) { - (Ok(limit), Ok(period)) => { - quota = quota.min(limit / period); - } + quota + } + + fn quota_v1(group_path: PathBuf) -> usize { + let mut quota = usize::MAX; + let mut path = PathBuf::with_capacity(128); + let mut read_buf = String::with_capacity(20); + + // Hardcode commonly used locations mentioned in the cgroups(7) manpage + // if that doesn't work scan mountinfo and adjust `group_path` for bind-mounts + let mounts: &[fn(&Path) -> Option<(_, &Path)>] = &[ + |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu"), p)), + |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu,cpuacct"), p)), + // this can be expensive on systems with tons of mountpoints + // but we only get to this point when /proc/self/cgroups explicitly indicated + // this process belongs to a cpu-controller cgroup v1 and the defaults didn't work + find_mountpoint, + ]; + + for mount in mounts { + let Some((mount, group_path)) = mount(&group_path) else { continue }; + + path.clear(); + path.push(mount.as_ref()); + path.push(&group_path); + + // skip if we guessed the mount incorrectly + if matches!(try_exists(&path), Err(_) | Ok(false)) { + continue; + } + + while path.starts_with(mount.as_ref()) { + let mut parse_file = |name| { + path.push(name); + read_buf.clear(); + + let f = File::open(&path); + path.pop(); // restore buffer before any early returns + f.ok()?.read_to_string(&mut read_buf).ok()?; + let parsed = read_buf.trim().parse::<usize>().ok()?; + + Some(parsed) + }; + + let limit = parse_file("cpu.cfs_quota_us"); + let period = parse_file("cpu.cfs_period_us"); + + match (limit, period) { + (Some(limit), Some(period)) => quota = quota.min(limit / period), _ => {} } + + path.pop(); } - path.pop(); // pop filename - path.pop(); // pop dir + // we passed the try_exists above so we should have traversed the correct hierarchy + // when reaching this line + break; } - }; - quota + quota + } + + /// Scan mountinfo for cgroup v1 mountpoint with a cpu controller + /// + /// If the cgroupfs is a bind mount then `group_path` is adjusted to skip + /// over the already-included prefix + fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> { + let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?); + let mut line = String::with_capacity(256); + loop { + line.clear(); + if reader.read_line(&mut line).ok()? == 0 { + break; + } + + let line = line.trim(); + let mut items = line.split(' '); + + let sub_path = items.nth(3)?; + let mount_point = items.next()?; + let mount_opts = items.next_back()?; + let filesystem_type = items.nth_back(1)?; + + if filesystem_type != "cgroup" || !mount_opts.split(',').any(|opt| opt == "cpu") { + // not a cgroup / not a cpu-controller + continue; + } + + let sub_path = Path::new(sub_path).strip_prefix("/").ok()?; + + if !group_path.starts_with(sub_path) { + // this is a bind-mount and the bound subdirectory + // does not contain the cgroup this process belongs to + continue; + } + + let trimmed_group_path = group_path.strip_prefix(sub_path).ok()?; + + return Some((Cow::Owned(mount_point.to_owned()), trimmed_group_path)); + } + + None + } } #[cfg(all( diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index d28c7b58b20..44c8a50fd86 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1577,10 +1577,15 @@ fn _assert_sync_and_send() { /// /// On Linux: /// - It may overcount the amount of parallelism available when limited by a -/// process-wide affinity mask or cgroup quotas and cgroup2 fs or `sched_getaffinity()` can't be +/// process-wide affinity mask or cgroup quotas and `sched_getaffinity()` or cgroup fs can't be /// queried, e.g. due to sandboxing. /// - It may undercount the amount of parallelism if the current thread's affinity mask /// does not reflect the process' cpuset, e.g. due to pinned threads. +/// - If the process is in a cgroup v1 cpu controller, this may need to +/// scan mountpoints to find the corresponding cgroup v1 controller, +/// which may take time on systems with large numbers of mountpoints. +/// (This does not apply to cgroup v2, or to processes not in a +/// cgroup.) /// /// On all targets: /// - It may overcount the amount of parallelism available when running in a VM diff --git a/library/test/src/console.rs b/library/test/src/console.rs index dc0123cf432..e9dda98966d 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -137,7 +137,7 @@ impl ConsoleTestState { // List the tests to console, and optionally to logfile. Filters are honored. pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> { let mut output = match term::stdout() { - None => OutputLocation::Raw(io::stdout()), + None => OutputLocation::Raw(io::stdout().lock()), Some(t) => OutputLocation::Pretty(t), }; diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index e83c4d98cc7..7f7549aaf5a 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -18,11 +18,13 @@ This feature allows for use of one of following sanitizers: * [MemorySanitizer][clang-msan] a detector of uninitialized reads. * [MemTagSanitizer][clang-memtag] fast memory error detector based on Armv8.5-A Memory Tagging Extension. +* [ShadowCallStack][clang-scs] provides backward-edge control flow protection. * [ThreadSanitizer][clang-tsan] a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`, -`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example: +`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`. +You might also need the `--target` and `build-std` flags. Example: ```shell $ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu ``` @@ -191,7 +193,8 @@ Shadow byte legend (one shadow byte represents 8 application bytes): The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially provides forward-edge control flow protection for Rust-compiled code only by -aggregating function pointers in groups identified by their number of arguments. +aggregating function pointers in groups identified by their return and parameter +types. Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same @@ -243,7 +246,7 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { fn main() { let answer = do_twice(add_one, 5); - println!("The answer is: {answer}"); + println!("The answer is: {}", answer); println!("With CFI enabled, you should not see the next answer"); let f: fn(i32) -> i32 = unsafe { @@ -253,18 +256,18 @@ fn main() { }; let next_answer = do_twice(f, 5); - println!("The next answer is: {next_answer}"); + println!("The next answer is: {}", next_answer); } ``` Fig. 1. Modified example from the [Advanced Functions and Closures][rust-book-ch19-05] chapter of the [The Rust Programming Language][rust-book] book. -[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) - ```shell -$ rustc rust_cfi.rs -o rust_cfi -$ ./rust_cfi +$ cargo run --release + Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1) + Finished release [optimized] target(s) in 0.76s + Running `target/release/rust-cfi-1` The answer is: 12 With CFI enabled, you should not see the next answer The next answer is: 14 @@ -272,11 +275,11 @@ $ ``` Fig. 2. Build and execution of the modified example with LLVM CFI disabled. -[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) - ```shell -$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi -$ ./rust_cfi +$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release + Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1) + Finished release [optimized] target(s) in 3.39s + Running `target/release/rust-cfi-1` The answer is: 12 With CFI enabled, you should not see the next answer Illegal instruction @@ -306,25 +309,25 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { fn main() { let answer = do_twice(add_one, 5); - println!("The answer is: {answer}"); + println!("The answer is: {}", answer); println!("With CFI enabled, you should not see the next answer"); let f: fn(i32) -> i32 = unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; let next_answer = do_twice(f, 5); - println!("The next answer is: {next_answer}"); + println!("The next answer is: {}", next_answer); } ``` Fig. 4. Another modified example from the [Advanced Functions and Closures][rust-book-ch19-05] chapter of the [The Rust Programming Language][rust-book] book. -[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) - ```shell -$ rustc rust_cfi.rs -o rust_cfi -$ ./rust_cfi +$ cargo run --release + Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2) + Finished release [optimized] target(s) in 0.76s + Running `target/release/rust-cfi-2` The answer is: 12 With CFI enabled, you should not see the next answer The next answer is: 14 @@ -332,11 +335,11 @@ $ ``` Fig. 5. Build and execution of the modified example with LLVM CFI disabled. -[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged) - ```shell -$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi -$ ./rust_cfi +$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release + Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2) + Finished release [optimized] target(s) in 3.38s + Running `target/release/rust-cfi-2` The answer is: 12 With CFI enabled, you should not see the next answer Illegal instruction @@ -346,14 +349,69 @@ Fig. 6. Build and execution of the modified example with LLVM CFI enabled. When LLVM CFI is enabled, if there are any attempts to change/hijack control flow using an indirect branch/call to a function with different number of -arguments than intended/passed in the call/branch site, the execution is also -terminated (see Fig. 6). +parameters than arguments intended/passed in the call/branch site, the +execution is also terminated (see Fig. 6). + +```rust +use std::mem; + +fn add_one(x: i32) -> i32 { + x + 1 +} + +fn add_two(x: i64) -> i64 { + x + 2 +} + +fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { + f(arg) + f(arg) +} + +fn main() { + let answer = do_twice(add_one, 5); + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: fn(i32) -> i32 = + unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; + let next_answer = do_twice(f, 5); -Forward-edge control flow protection not only by aggregating function pointers -in groups identified by their number of arguments, but also their argument -types, will also be provided in later work by defining and using compatible type -identifiers (see Type metadata in the design document in the tracking -issue [#89653](https://github.com/rust-lang/rust/issues/89653)). + println!("The next answer is: {}", next_answer); +} +``` +Fig. 7. Another modified example from the [Advanced Functions and +Closures][rust-book-ch19-05] chapter of the [The Rust Programming +Language][rust-book] book. + +```shell + cargo run --release + Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3) + Finished release [optimized] target(s) in 0.74s + Running `target/release/rust-cfi-3` +The answer is: 12 +With CFI enabled, you should not see the next answer +The next answer is: 14 +$ +``` +Fig. 8. Build and execution of the modified example with LLVM CFI disabled. + +```shell +$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release + Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3) + Finished release [optimized] target(s) in 3.40s + Running `target/release/rust-cfi-3` +The answer is: 12 +With CFI enabled, you should not see the next answer +Illegal instruction +$ +``` +Fig. 9. Build and execution of the modified example with LLVM CFI enabled. + +When LLVM CFI is enabled, if there are any attempts to change/hijack control +flow using an indirect branch/call to a function with different return and +parameter types than the return type expected and arguments intended/passed in +the call/branch site, the execution is also terminated (see Fig. 9). [rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html [rust-book]: https://doc.rust-lang.org/book/title-page.html @@ -513,6 +571,18 @@ To enable this target feature compile with `-C target-feature="+mte"`. More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html). +# ShadowCallStack + +ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack. + +ShadowCallStack requires a platform ABI which reserves `x18` as the instrumentation makes use of this register. + +ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and is supported on the following targets: + +* `aarch64-linux-android` + +A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details. + # ThreadSanitizer ThreadSanitizer is a data race detection tool. It is supported on the following @@ -610,4 +680,5 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html +[clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index e6f006135e2..c43fd1ad241 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -121,7 +121,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { unsafety: hir::Unsafety::Normal, generics: new_generics, trait_: Some(trait_ref.clean(self.cx)), - for_: ty.clean(self.cx), + for_: clean_middle_ty(ty, self.cx, None), items: Vec::new(), polarity, kind: ImplKind::Auto, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 12137667e7b..c64c5895079 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -116,14 +116,14 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. trait_: Some(trait_ref.0.clean(cx)), - for_: ty.0.clean(cx), + for_: clean_middle_ty(ty.0, cx, None), items: cx.tcx .associated_items(impl_def_id) .in_definition_order() .map(|x| x.clean(cx)) .collect::<Vec<_>>(), polarity: ty::ImplPolarity::Positive, - kind: ImplKind::Blanket(Box::new(trait_ref.0.self_ty().clean(cx))), + kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))), })), cfg: None, }); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6b37b8e4db4..7a4ec889ac7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -16,8 +16,8 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ - self, clean_fn_decl_from_did_and_sig, clean_ty_generics, utils, Attributes, AttributesExt, - Clean, ImplKind, ItemId, Type, Visibility, + self, clean_fn_decl_from_did_and_sig, clean_middle_ty, clean_ty, clean_ty_generics, utils, + Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -261,7 +261,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef { let predicates = cx.tcx.explicit_predicates_of(did); - let type_ = cx.tcx.type_of(did).clean(cx); + let type_ = clean_middle_ty(cx.tcx.type_of(did), cx, Some(did)); clean::Typedef { type_, @@ -357,8 +357,8 @@ pub(crate) fn build_impl( }; let for_ = match &impl_item { - Some(impl_) => impl_.self_ty.clean(cx), - None => tcx.type_of(did).clean(cx), + Some(impl_) => clean_ty(impl_.self_ty, cx), + None => clean_middle_ty(tcx.type_of(did), cx, Some(did)), }; // Only inline impl if the implementing type is @@ -577,14 +577,14 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { clean::Constant { - type_: cx.tcx.type_of(def_id).clean(cx), + type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)), kind: clean::ConstantKind::Extern { def_id }, } } fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: cx.tcx.type_of(did).clean(cx), + type_: clean_middle_ty(cx.tcx.type_of(did), cx, Some(did)), mutability: if mutable { Mutability::Mut } else { Mutability::Not }, expr: None, } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 43ebaab98db..6160783f652 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -239,11 +239,9 @@ impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime { impl<'tcx> Clean<'tcx, Constant> for hir::ConstArg { fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant { + let def_id = cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id(); Constant { - type_: cx - .tcx - .type_of(cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id()) - .clean(cx), + type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)), kind: ConstantKind::Anonymous { body: self.value.body }, } } @@ -297,7 +295,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> { }) .collect(); WherePredicate::BoundPredicate { - ty: wbp.bounded_ty.clean(cx), + ty: clean_ty(wbp.bounded_ty, cx), bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(), bound_params, } @@ -309,8 +307,8 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> { }, hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate { - lhs: wrp.lhs_ty.clean(cx), - rhs: wrp.rhs_ty.clean(cx).into(), + lhs: clean_ty(wrp.lhs_ty, cx), + rhs: clean_ty(wrp.rhs_ty, cx).into(), }, }) } @@ -348,7 +346,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::PolyTraitPredicate<'tcx> let poly_trait_ref = self.map_bound(|pred| pred.trait_ref); Some(WherePredicate::BoundPredicate { - ty: poly_trait_ref.skip_binder().self_ty().clean(cx), + ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None), bounds: vec![poly_trait_ref.clean(cx)], bound_params: Vec::new(), }) @@ -383,7 +381,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> } Some(WherePredicate::BoundPredicate { - ty: ty.clean(cx), + ty: clean_middle_ty(*ty, cx, None), bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))], bound_params: Vec::new(), }) @@ -393,7 +391,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Term { match self { - ty::Term::Ty(ty) => Term::Type(ty.clean(cx)), + ty::Term::Ty(ty) => Term::Type(clean_middle_ty(*ty, cx, None)), ty::Term::Const(c) => Term::Constant(c.clean(cx)), } } @@ -402,7 +400,7 @@ impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> { impl<'tcx> Clean<'tcx, Term> for hir::Term<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Term { match self { - hir::Term::Ty(ty) => Term::Type(ty.clean(cx)), + hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), hir::Term::Const(c) => { let def_id = cx.tcx.hir().local_def_id(c.hir_id); Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx)) @@ -425,7 +423,7 @@ fn clean_projection<'tcx>( ) -> Type { let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); let trait_ = lifted.trait_ref(cx.tcx).clean(cx); - let self_type = ty.self_ty().clean(cx); + let self_type = clean_middle_ty(ty.self_ty(), cx, None); let self_def_id = if let Some(def_id) = def_id { cx.tcx.opt_parent(def_id).or(Some(def_id)) } else { @@ -476,7 +474,7 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef { } ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { let default = if has_default { - Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id))) + Some(clean_middle_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id))) } else { None }; @@ -494,7 +492,11 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef { self.name, GenericParamDefKind::Const { did: self.def_id, - ty: Box::new(cx.tcx.type_of(self.def_id).clean(cx)), + ty: Box::new(clean_middle_ty( + cx.tcx.type_of(self.def_id), + cx, + Some(self.def_id), + )), default: match has_default { true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())), false => None, @@ -546,7 +548,7 @@ fn clean_generic_param<'tcx>( GenericParamDefKind::Type { did: did.to_def_id(), bounds, - default: default.map(|t| t.clean(cx)).map(Box::new), + default: default.map(|t| clean_ty(t, cx)).map(Box::new), synthetic, }, ) @@ -555,7 +557,7 @@ fn clean_generic_param<'tcx>( param.name.ident().name, GenericParamDefKind::Const { did: did.to_def_id(), - ty: Box::new(ty.clean(cx)), + ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { let def_id = cx.tcx.hir().local_def_id(ct.hir_id); Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string()) @@ -752,7 +754,7 @@ fn clean_ty_generics<'tcx>( if let crate::core::ImplTraitParam::ParamIndex(idx) = param { if let Some(proj) = impl_trait_proj.remove(&idx) { for (trait_did, name, rhs) in proj { - let rhs = rhs.clean(cx); + let rhs = clean_middle_ty(rhs, cx, None); simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs)); } } @@ -926,7 +928,7 @@ fn clean_args_from_types_and_names<'tcx>( if name.is_empty() { name = kw::Underscore; } - Argument { name, type_: ty.clean(cx), is_const: false } + Argument { name, type_: clean_ty(ty, cx), is_const: false } }) .collect(), } @@ -945,7 +947,7 @@ fn clean_args_from_types_and_body_id<'tcx>( .enumerate() .map(|(i, ty)| Argument { name: name_from_pat(body.params[i].pat), - type_: ty.clean(cx), + type_: clean_ty(ty, cx), is_const: false, }) .collect(), @@ -969,7 +971,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( // We assume all empty tuples are default return type. This theoretically can discard `-> ()`, // but shouldn't change any code meaning. - let output = match sig.skip_binder().output().clean(cx) { + let output = match clean_middle_ty(sig.skip_binder().output(), cx, None) { Type::Tuple(inner) if inner.is_empty() => DefaultReturn, ty => Return(ty), }; @@ -983,7 +985,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( .inputs() .iter() .map(|t| Argument { - type_: t.clean(cx), + type_: clean_middle_ty(*t, cx, None), name: names.next().map_or(kw::Empty, |i| i.name), is_const: false, }) @@ -995,7 +997,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy { match *self { - Self::Return(typ) => Return(typ.clean(cx)), + Self::Return(typ) => Return(clean_ty(typ, cx)), Self::DefaultReturn(..) => DefaultReturn, } } @@ -1038,10 +1040,10 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> { cx.with_param_env(local_did, |cx| { let inner = match self.kind { hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem( - ty.clean(cx), + clean_ty(ty, cx), ConstantKind::Local { def_id: local_did, body: default }, ), - hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(ty.clean(cx)), + hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)), hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let m = clean_function(cx, sig, self.generics, body); MethodItem(m, None) @@ -1059,9 +1061,13 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> { hir::TraitItemKind::Type(bounds, Some(default)) => { let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); - let item_type = hir_ty_to_ty(cx.tcx, default).clean(cx); + let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None); AssocTypeItem( - Typedef { type_: default.clean(cx), generics, item_type: Some(item_type) }, + Typedef { + type_: clean_ty(default, cx), + generics, + item_type: Some(item_type), + }, bounds, ) } @@ -1086,7 +1092,7 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> { let inner = match self.kind { hir::ImplItemKind::Const(ty, expr) => { let default = ConstantKind::Local { def_id: local_did, body: expr }; - AssocConstItem(ty.clean(cx), default) + AssocConstItem(clean_ty(ty, cx), default) } hir::ImplItemKind::Fn(ref sig, body) => { let m = clean_function(cx, sig, self.generics, body); @@ -1094,9 +1100,9 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> { MethodItem(m, Some(defaultness)) } hir::ImplItemKind::TyAlias(hir_ty) => { - let type_ = hir_ty.clean(cx); + let type_ = clean_ty(hir_ty, cx); let generics = self.generics.clean(cx); - let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx); + let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); AssocTypeItem( Typedef { type_, generics, item_type: Some(item_type) }, Vec::new(), @@ -1125,7 +1131,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { let tcx = cx.tcx; let kind = match self.kind { ty::AssocKind::Const => { - let ty = tcx.type_of(self.def_id).clean(cx); + let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)); let provided = match self.container { ty::ImplContainer(_) => true, @@ -1272,7 +1278,11 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { if self.defaultness.has_value() { AssocTypeItem( Typedef { - type_: tcx.type_of(self.def_id).clean(cx), + type_: clean_middle_ty( + tcx.type_of(self.def_id), + cx, + Some(self.def_id), + ), generics, // FIXME: should we obtain the Type from HIR and pass it on here? item_type: None, @@ -1286,7 +1296,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { // FIXME: when could this happen? Associated items in inherent impls? AssocTypeItem( Typedef { - type_: tcx.type_of(self.def_id).clean(cx), + type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)), generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, item_type: None, }, @@ -1337,7 +1347,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type // Try to normalize `<X as Y>::T` to a type let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let Some(normalized_value) = normalize(cx, ty) { - return normalized_value.clean(cx); + return clean_middle_ty(normalized_value, cx, None); } let trait_segments = &p.segments[..p.segments.len() - 1]; @@ -1348,7 +1358,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type }; register_res(cx, trait_.res); let self_def_id = DefId::local(qself.hir_id.owner.local_def_index); - let self_type = qself.clean(cx); + let self_type = clean_ty(qself, cx); let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type); Type::QPath { assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)), @@ -1368,7 +1378,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type let trait_ = hir::Path { span, res, segments: &[] }.clean(cx); register_res(cx, trait_.res); let self_def_id = res.opt_def_id(); - let self_type = qself.clean(cx); + let self_type = clean_ty(qself, cx); let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type); Type::QPath { assoc: Box::new(segment.clean(cx)), @@ -1435,9 +1445,12 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(ty) = type_ { - substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx))); + substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx))); } else if let Some(default) = *default { - substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx))); + substs.insert( + ty_param_def_id.to_def_id(), + SubstParam::Type(clean_ty(default, cx)), + ); } indices.types += 1; } @@ -1464,70 +1477,68 @@ fn maybe_expand_private_type_alias<'tcx>( } } - Some(cx.enter_alias(substs, |cx| ty.clean(cx))) + Some(cx.enter_alias(substs, |cx| clean_ty(ty, cx))) } -impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Type { - use rustc_hir::*; - - match self.kind { - TyKind::Never => Primitive(PrimitiveType::Never), - TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))), - TyKind::Rptr(ref l, ref m) => { - // There are two times a `Fresh` lifetime can be created: - // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. - // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`. - // See #59286 for more information. - // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it. - // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; - // there's no case where it could cause the function to fail to compile. - let elided = - l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh)); - let lifetime = if elided { None } else { Some(l.clean(cx)) }; - BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) } - } - TyKind::Slice(ty) => Slice(Box::new(ty.clean(cx))), - TyKind::Array(ty, ref length) => { - let length = match length { - hir::ArrayLen::Infer(_, _) => "_".to_string(), - hir::ArrayLen::Body(anon_const) => { - let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); - // NOTE(min_const_generics): We can't use `const_eval_poly` for constants - // as we currently do not supply the parent generics to anonymous constants - // but do allow `ConstKind::Param`. - // - // `const_eval_poly` tries to to first substitute generic parameters which - // results in an ICE while manually constructing the constant and using `eval` - // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_anon_const(cx.tcx, def_id); - let param_env = cx.tcx.param_env(def_id); - print_const(cx, ct.eval(cx.tcx, param_env)) - } - }; +pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { + use rustc_hir::*; - Array(Box::new(ty.clean(cx)), length) - } - TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()), - TyKind::OpaqueDef(item_id, _) => { - let item = cx.tcx.hir().item(item_id); - if let hir::ItemKind::OpaqueTy(ref ty) = item.kind { - ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect()) - } else { - unreachable!() + match ty.kind { + TyKind::Never => Primitive(PrimitiveType::Never), + TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))), + TyKind::Rptr(ref l, ref m) => { + // There are two times a `Fresh` lifetime can be created: + // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. + // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`. + // See #59286 for more information. + // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it. + // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; + // there's no case where it could cause the function to fail to compile. + let elided = + l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh)); + let lifetime = if elided { None } else { Some(l.clean(cx)) }; + BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) } + } + TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), + TyKind::Array(ty, ref length) => { + let length = match length { + hir::ArrayLen::Infer(_, _) => "_".to_string(), + hir::ArrayLen::Body(anon_const) => { + let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + print_const(cx, ct.eval(cx.tcx, param_env)) } + }; + + Array(Box::new(clean_ty(ty, cx)), length) + } + TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), + TyKind::OpaqueDef(item_id, _) => { + let item = cx.tcx.hir().item(item_id); + if let hir::ItemKind::OpaqueTy(ref ty) = item.kind { + ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect()) + } else { + unreachable!() } - TyKind::Path(_) => clean_qpath(self, cx), - TyKind::TraitObject(bounds, ref lifetime, _) => { - let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect(); - let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None }; - DynTrait(bounds, lifetime) - } - TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))), - // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. - TyKind::Infer | TyKind::Err => Infer, - TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind), } + TyKind::Path(_) => clean_qpath(ty, cx), + TyKind::TraitObject(bounds, ref lifetime, _) => { + let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect(); + let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None }; + DynTrait(bounds, lifetime) + } + TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))), + // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. + TyKind::Infer | TyKind::Err => Infer, + TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind), } } @@ -1562,7 +1573,11 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> { } } -fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefId>) -> Type { +pub(crate) fn clean_middle_ty<'tcx>( + this: Ty<'tcx>, + cx: &mut DocContext<'tcx>, + def_id: Option<DefId>, +) -> Type { trace!("cleaning type: {:?}", this); let ty = normalize(cx, this).unwrap_or(this); match *ty.kind() { @@ -1573,17 +1588,19 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI ty::Uint(uint_ty) => Primitive(uint_ty.into()), ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str), - ty::Slice(ty) => Slice(Box::new(ty.clean(cx))), + ty::Slice(ty) => Slice(Box::new(clean_middle_ty(ty, cx, None))), ty::Array(ty, n) => { let mut n = cx.tcx.lift(n).expect("array lift failed"); n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); - Array(Box::new(ty.clean(cx)), n) - } - ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))), - ty::Ref(r, ty, mutbl) => { - BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: Box::new(ty.clean(cx)) } + Array(Box::new(clean_middle_ty(ty, cx, None)), n) } + ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))), + ty::Ref(r, ty, mutbl) => BorrowedRef { + lifetime: r.clean(cx), + mutability: mutbl, + type_: Box::new(clean_middle_ty(ty, cx, None)), + }, ty::FnDef(..) | ty::FnPtr(_) => { let ty = cx.tcx.lift(this).expect("FnPtr lift failed"); let sig = ty.fn_sig(cx.tcx); @@ -1660,7 +1677,7 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI DynTrait(bounds, lifetime) } - ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()), + ty::Tuple(t) => Tuple(t.iter().map(|t| clean_middle_ty(t, cx, None)).collect()), ty::Projection(ref data) => clean_projection(*data, cx, def_id), @@ -1747,17 +1764,11 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI } } -impl<'tcx> Clean<'tcx, Type> for Ty<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Type { - clean_ty(*self, cx, None) - } -} - impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant { // FIXME: instead of storing the stringified expression, store `self` directly instead. Constant { - type_: self.ty().clean(cx), + type_: clean_middle_ty(self.ty(), cx, None), kind: ConstantKind::TyConst { expr: self.to_string() }, } } @@ -1766,13 +1777,18 @@ impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> { impl<'tcx> Clean<'tcx, Item> for hir::FieldDef<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { let def_id = cx.tcx.hir().local_def_id(self.hir_id).to_def_id(); - clean_field(def_id, self.ident.name, self.ty.clean(cx), cx) + clean_field(def_id, self.ident.name, clean_ty(self.ty, cx), cx) } } impl<'tcx> Clean<'tcx, Item> for ty::FieldDef { fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - clean_field(self.did, self.name, cx.tcx.type_of(self.did).clean(cx), cx) + clean_field( + self.did, + self.name, + clean_middle_ty(cx.tcx.type_of(self.did), cx, Some(self.did)), + cx, + ) } } @@ -1863,10 +1879,10 @@ impl<'tcx> Clean<'tcx, Path> for hir::Path<'tcx> { impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs { if self.parenthesized { - let output = self.bindings[0].ty().clean(cx); + let output = clean_ty(self.bindings[0].ty(), cx); let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None }; - let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect::<Vec<_>>().into(); + let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into(); GenericArgs::Parenthesized { inputs, output } } else { let args = self @@ -1877,7 +1893,7 @@ impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> { GenericArg::Lifetime(lt.clean(cx)) } hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), - hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)), + hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))), hir::GenericArg::Infer(_inf) => GenericArg::Infer, }) @@ -1925,10 +1941,10 @@ fn clean_maybe_renamed_item<'tcx>( cx.with_param_env(def_id, |cx| { let kind = match item.kind { ItemKind::Static(ty, mutability, body_id) => { - StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) }) + StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) }) } ItemKind::Const(ty, body_id) => ConstantItem(Constant { - type_: ty.clean(cx), + type_: clean_ty(ty, cx), kind: ConstantKind::Local { body: body_id, def_id }, }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { @@ -1936,8 +1952,8 @@ fn clean_maybe_renamed_item<'tcx>( generics: ty.generics.clean(cx), }), ItemKind::TyAlias(hir_ty, generics) => { - let rustdoc_ty = hir_ty.clean(cx); - let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx); + let rustdoc_ty = clean_ty(hir_ty, cx); + let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); TypedefItem(Typedef { type_: rustdoc_ty, generics: generics.clean(cx), @@ -2023,9 +2039,9 @@ fn clean_impl<'tcx>( build_deref_target_impls(cx, &items, &mut ret); } - let for_ = impl_.self_ty.clean(cx); + let for_ = clean_ty(impl_.self_ty, cx); let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) { - DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)), + DefKind::TyAlias => Some(clean_middle_ty(tcx.type_of(did), cx, Some(did))), _ => None, }); let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| { @@ -2234,7 +2250,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( ForeignFunctionItem(Function { decl, generics }) } hir::ForeignItemKind::Static(ty, mutability) => { - ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None }) + ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None }) } hir::ForeignItemKind::Type => ForeignTypeItem, }; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index fa449a21b0c..00d62b37484 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,8 +2,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ - inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, - ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility, + clean_middle_ty, inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, + ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, + TypeBinding, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -91,7 +92,7 @@ pub(crate) fn substs_to_args<'tcx>( skip_first = false; None } - GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))), + GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty(ty, cx, None))), GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))), })); ret_val @@ -110,7 +111,7 @@ fn external_generic_args<'tcx>( let inputs = // The trait's first substitution is the one after self, if there is one. match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() { - ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect::<Vec<_>>().into(), + ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::<Vec<_>>().into(), _ => return GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() }, }; let output = None; diff --git a/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs b/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs index 68f81808861..c42fbba7425 100644 --- a/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs +++ b/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs @@ -1,10 +1,7 @@ // Verifies that "CFI Canonical Jump Tables" module flag is added. // -// ignore-windows // needs-sanitizer-cfi -// only-aarch64 -// only-x86_64 -// compile-flags: -Clto -Zsanitizer=cfi +// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi #![crate_type="lib"] diff --git a/src/test/codegen/sanitizer_cfi_emit_type_checks.rs b/src/test/codegen/sanitizer-cfi-emit-type-checks.rs index 9ed0422ceff..082f0f121ff 100644 --- a/src/test/codegen/sanitizer_cfi_emit_type_checks.rs +++ b/src/test/codegen/sanitizer-cfi-emit-type-checks.rs @@ -1,10 +1,7 @@ // Verifies that pointer type membership tests for indirect calls are emitted. // -// ignore-windows // needs-sanitizer-cfi -// only-aarch64 -// only-x86_64 -// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi #![crate_type="lib"] diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs new file mode 100644 index 00000000000..ece2adbdf43 --- /dev/null +++ b/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -0,0 +1,575 @@ +// Verifies that type metadata identifiers for functions are emitted correctly. +// +// needs-sanitizer-cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi + +#![crate_type="lib"] +#![allow(dead_code)] +#![allow(incomplete_features)] +#![allow(unused_must_use)] +#![feature(adt_const_params, extern_types, inline_const, type_alias_impl_trait)] + +extern crate core; +use core::ffi::c_void; +use std::marker::PhantomData; + +// User-defined type (structure) +pub struct Struct1<T> { + member1: T, +} + +// User-defined type (enum) +pub enum Enum1<T> { + Variant1(T), +} + +// User-defined type (union) +pub union Union1<T> { + member1: std::mem::ManuallyDrop<T>, +} + +// Extern type +extern { + pub type type1; +} + +// Trait +pub trait Trait1<T> { + fn foo(&self) { } +} + +// Trait implementation +impl<T> Trait1<T> for i32 { + fn foo(&self) { } +} + +// Trait implementation +impl<T> Trait1<T> for Struct1<T> { + fn foo(&self) { } +} + +// impl Trait type aliases for helping with defining other types (see below) +pub type Type1 = impl Send; +pub type Type2 = impl Send; +pub type Type3 = impl Send; +pub type Type4 = impl Send; +pub type Type5 = impl Send; +pub type Type6 = impl Send; +pub type Type7 = impl Send; +pub type Type8 = impl Send; +pub type Type9 = impl Send; +pub type Type10 = impl Send; +pub type Type11 = impl Send; + +pub fn fn1<'a>() { + // Closure + let closure1 = || { }; + let _: Type1 = closure1; + + // Constructor + pub struct Foo(i32); + let _: Type2 = Foo; + + // Type in extern path + extern { + fn foo(); + } + let _: Type3 = foo; + + // Type in closure path + || { + pub struct Foo; + let _: Type4 = Foo; + }; + + // Type in const path + const { + pub struct Foo; + fn foo() -> Type5 { Foo } + }; + + // Type in impl path + impl<T> Struct1<T> { + fn foo(&self) { } + } + let _: Type6 = <Struct1<i32>>::foo; + + // Trait method + let _: Type7 = <dyn Trait1<i32>>::foo; + + // Trait method + let _: Type8 = <i32 as Trait1<i32>>::foo; + + // Trait method + let _: Type9 = <Struct1<i32> as Trait1<i32>>::foo; + + // Const generics + pub struct Qux<T, const N: usize>([T; N]); + let _: Type10 = Qux([0; 32]); + + // Lifetimes/regions + pub struct Quux<'a>(&'a i32); + pub struct Quuux<'a, 'b>(&'a i32, &'b Quux<'b>); + let _: Type11 = Quuux; +} + +// repr(transparent) user-defined type +struct Foo(i32); + +#[repr(transparent)] +pub struct Type12 { + member1: (), + member2: PhantomData<i32>, + member3: Foo, +} + +// Self-referencing repr(transparent) user-defined type +#[repr(transparent)] +pub struct Type13<'a> { + member1: (), + member2: PhantomData<i32>, + member3: &'a Type13<'a>, +} + +pub fn foo0(_: ()) { } +// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] +pub fn foo1(_: c_void, _: ()) { } +// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] +pub fn foo2(_: (), _: c_void, _: c_void) { } +// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] +pub fn foo3(_: *mut c_void) { } +// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] +pub fn foo4(_: *mut c_void, _: *mut ()) { } +// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] +pub fn foo5(_: *mut (), _: *mut c_void, _: *mut c_void) { } +// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] +pub fn foo6(_: *const c_void) { } +// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] +pub fn foo7(_: *const c_void, _: *const ()) { } +// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] +pub fn foo8(_: *const (), _: *const c_void, _: *const c_void) { } +// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] +pub fn foo9(_: bool) { } +// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] +pub fn foo10(_: bool, _: bool) { } +// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] +pub fn foo11(_: bool, _: bool, _: bool) { } +// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] +pub fn foo12(_: i8) { } +// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] +pub fn foo13(_: i8, _: i8) { } +// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] +pub fn foo14(_: i8, _: i8, _: i8) { } +// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] +pub fn foo15(_: i16) { } +// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]] +pub fn foo16(_: i16, _: i16) { } +// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]] +pub fn foo17(_: i16, _: i16, _: i16) { } +// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]] +pub fn foo18(_: i32) { } +// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]] +pub fn foo19(_: i32, _: i32) { } +// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]] +pub fn foo20(_: i32, _: i32, _: i32) { } +// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]] +pub fn foo21(_: i64) { } +// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]] +pub fn foo22(_: i64, _: i64) { } +// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]] +pub fn foo23(_: i64, _: i64, _: i64) { } +// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]] +pub fn foo24(_: i128) { } +// CHECK: define{{.*}}foo24{{.*}}!type ![[TYPE24:[0-9]+]] +pub fn foo25(_: i128, _: i128) { } +// CHECK: define{{.*}}foo25{{.*}}!type ![[TYPE25:[0-9]+]] +pub fn foo26(_: i128, _: i128, _: i128) { } +// CHECK: define{{.*}}foo26{{.*}}!type ![[TYPE26:[0-9]+]] +pub fn foo27(_: isize) { } +// CHECK: define{{.*}}foo27{{.*}}!type ![[TYPE27:[0-9]+]] +pub fn foo28(_: isize, _: isize) { } +// CHECK: define{{.*}}foo28{{.*}}!type ![[TYPE28:[0-9]+]] +pub fn foo29(_: isize, _: isize, _: isize) { } +// CHECK: define{{.*}}foo29{{.*}}!type ![[TYPE29:[0-9]+]] +pub fn foo30(_: u8) { } +// CHECK: define{{.*}}foo30{{.*}}!type ![[TYPE30:[0-9]+]] +pub fn foo31(_: u8, _: u8) { } +// CHECK: define{{.*}}foo31{{.*}}!type ![[TYPE31:[0-9]+]] +pub fn foo32(_: u8, _: u8, _: u8) { } +// CHECK: define{{.*}}foo32{{.*}}!type ![[TYPE32:[0-9]+]] +pub fn foo33(_: u16) { } +// CHECK: define{{.*}}foo33{{.*}}!type ![[TYPE33:[0-9]+]] +pub fn foo34(_: u16, _: u16) { } +// CHECK: define{{.*}}foo34{{.*}}!type ![[TYPE34:[0-9]+]] +pub fn foo35(_: u16, _: u16, _: u16) { } +// CHECK: define{{.*}}foo35{{.*}}!type ![[TYPE35:[0-9]+]] +pub fn foo36(_: u32) { } +// CHECK: define{{.*}}foo36{{.*}}!type ![[TYPE36:[0-9]+]] +pub fn foo37(_: u32, _: u32) { } +// CHECK: define{{.*}}foo37{{.*}}!type ![[TYPE37:[0-9]+]] +pub fn foo38(_: u32, _: u32, _: u32) { } +// CHECK: define{{.*}}foo38{{.*}}!type ![[TYPE38:[0-9]+]] +pub fn foo39(_: u64) { } +// CHECK: define{{.*}}foo39{{.*}}!type ![[TYPE39:[0-9]+]] +pub fn foo40(_: u64, _: u64) { } +// CHECK: define{{.*}}foo40{{.*}}!type ![[TYPE40:[0-9]+]] +pub fn foo41(_: u64, _: u64, _: u64) { } +// CHECK: define{{.*}}foo41{{.*}}!type ![[TYPE41:[0-9]+]] +pub fn foo42(_: u128) { } +// CHECK: define{{.*}}foo42{{.*}}!type ![[TYPE42:[0-9]+]] +pub fn foo43(_: u128, _: u128) { } +// CHECK: define{{.*}}foo43{{.*}}!type ![[TYPE43:[0-9]+]] +pub fn foo44(_: u128, _: u128, _: u128) { } +// CHECK: define{{.*}}foo44{{.*}}!type ![[TYPE44:[0-9]+]] +pub fn foo45(_: usize) { } +// CHECK: define{{.*}}foo45{{.*}}!type ![[TYPE45:[0-9]+]] +pub fn foo46(_: usize, _: usize) { } +// CHECK: define{{.*}}foo46{{.*}}!type ![[TYPE46:[0-9]+]] +pub fn foo47(_: usize, _: usize, _: usize) { } +// CHECK: define{{.*}}foo47{{.*}}!type ![[TYPE47:[0-9]+]] +pub fn foo48(_: f32) { } +// CHECK: define{{.*}}foo48{{.*}}!type ![[TYPE48:[0-9]+]] +pub fn foo49(_: f32, _: f32) { } +// CHECK: define{{.*}}foo49{{.*}}!type ![[TYPE49:[0-9]+]] +pub fn foo50(_: f32, _: f32, _: f32) { } +// CHECK: define{{.*}}foo50{{.*}}!type ![[TYPE50:[0-9]+]] +pub fn foo51(_: f64) { } +// CHECK: define{{.*}}foo51{{.*}}!type ![[TYPE51:[0-9]+]] +pub fn foo52(_: f64, _: f64) { } +// CHECK: define{{.*}}foo52{{.*}}!type ![[TYPE52:[0-9]+]] +pub fn foo53(_: f64, _: f64, _: f64) { } +// CHECK: define{{.*}}foo53{{.*}}!type ![[TYPE53:[0-9]+]] +pub fn foo54(_: char) { } +// CHECK: define{{.*}}foo54{{.*}}!type ![[TYPE54:[0-9]+]] +pub fn foo55(_: char, _: char) { } +// CHECK: define{{.*}}foo55{{.*}}!type ![[TYPE55:[0-9]+]] +pub fn foo56(_: char, _: char, _: char) { } +// CHECK: define{{.*}}foo56{{.*}}!type ![[TYPE56:[0-9]+]] +pub fn foo57(_: &str) { } +// CHECK: define{{.*}}foo57{{.*}}!type ![[TYPE57:[0-9]+]] +pub fn foo58(_: &str, _: &str) { } +// CHECK: define{{.*}}foo58{{.*}}!type ![[TYPE58:[0-9]+]] +pub fn foo59(_: &str, _: &str, _: &str) { } +// CHECK: define{{.*}}foo59{{.*}}!type ![[TYPE59:[0-9]+]] +pub fn foo60(_: (i32, i32)) { } +// CHECK: define{{.*}}foo60{{.*}}!type ![[TYPE60:[0-9]+]] +pub fn foo61(_: (i32, i32), _: (i32, i32)) { } +// CHECK: define{{.*}}foo61{{.*}}!type ![[TYPE61:[0-9]+]] +pub fn foo62(_: (i32, i32), _: (i32, i32), _: (i32, i32)) { } +// CHECK: define{{.*}}foo62{{.*}}!type ![[TYPE62:[0-9]+]] +pub fn foo63(_: [i32; 32]) { } +// CHECK: define{{.*}}foo63{{.*}}!type ![[TYPE63:[0-9]+]] +pub fn foo64(_: [i32; 32], _: [i32; 32]) { } +// CHECK: define{{.*}}foo64{{.*}}!type ![[TYPE64:[0-9]+]] +pub fn foo65(_: [i32; 32], _: [i32; 32], _: [i32; 32]) { } +// CHECK: define{{.*}}foo65{{.*}}!type ![[TYPE65:[0-9]+]] +pub fn foo66(_: &[i32]) { } +// CHECK: define{{.*}}foo66{{.*}}!type ![[TYPE66:[0-9]+]] +pub fn foo67(_: &[i32], _: &[i32]) { } +// CHECK: define{{.*}}foo67{{.*}}!type ![[TYPE67:[0-9]+]] +pub fn foo68(_: &[i32], _: &[i32], _: &[i32]) { } +// CHECK: define{{.*}}foo68{{.*}}!type ![[TYPE68:[0-9]+]] +pub fn foo69(_: &Struct1::<i32>) { } +// CHECK: define{{.*}}foo69{{.*}}!type ![[TYPE69:[0-9]+]] +pub fn foo70(_: &Struct1::<i32>, _: &Struct1::<i32>) { } +// CHECK: define{{.*}}foo70{{.*}}!type ![[TYPE70:[0-9]+]] +pub fn foo71(_: &Struct1::<i32>, _: &Struct1::<i32>, _: &Struct1::<i32>) { } +// CHECK: define{{.*}}foo71{{.*}}!type ![[TYPE71:[0-9]+]] +pub fn foo72(_: &Enum1::<i32>) { } +// CHECK: define{{.*}}foo72{{.*}}!type ![[TYPE72:[0-9]+]] +pub fn foo73(_: &Enum1::<i32>, _: &Enum1::<i32>) { } +// CHECK: define{{.*}}foo73{{.*}}!type ![[TYPE73:[0-9]+]] +pub fn foo74(_: &Enum1::<i32>, _: &Enum1::<i32>, _: &Enum1::<i32>) { } +// CHECK: define{{.*}}foo74{{.*}}!type ![[TYPE74:[0-9]+]] +pub fn foo75(_: &Union1::<i32>) { } +// CHECK: define{{.*}}foo75{{.*}}!type ![[TYPE75:[0-9]+]] +pub fn foo76(_: &Union1::<i32>, _: &Union1::<i32>) { } +// CHECK: define{{.*}}foo76{{.*}}!type ![[TYPE76:[0-9]+]] +pub fn foo77(_: &Union1::<i32>, _: &Union1::<i32>, _: &Union1::<i32>) { } +// CHECK: define{{.*}}foo77{{.*}}!type ![[TYPE77:[0-9]+]] +pub fn foo78(_: *mut type1) { } +// CHECK: define{{.*}}foo78{{.*}}!type ![[TYPE78:[0-9]+]] +pub fn foo79(_: *mut type1, _: *mut type1) { } +// CHECK: define{{.*}}foo79{{.*}}!type ![[TYPE79:[0-9]+]] +pub fn foo80(_: *mut type1, _: *mut type1, _: *mut type1) { } +// CHECK: define{{.*}}foo80{{.*}}!type ![[TYPE80:[0-9]+]] +pub fn foo81(_: &mut i32) { } +// CHECK: define{{.*}}foo81{{.*}}!type ![[TYPE81:[0-9]+]] +pub fn foo82(_: &mut i32, _: &i32) { } +// CHECK: define{{.*}}foo82{{.*}}!type ![[TYPE82:[0-9]+]] +pub fn foo83(_: &mut i32, _: &i32, _: &i32) { } +// CHECK: define{{.*}}foo83{{.*}}!type ![[TYPE83:[0-9]+]] +pub fn foo84(_: &i32) { } +// CHECK: define{{.*}}foo84{{.*}}!type ![[TYPE84:[0-9]+]] +pub fn foo85(_: &i32, _: &mut i32) { } +// CHECK: define{{.*}}foo85{{.*}}!type ![[TYPE85:[0-9]+]] +pub fn foo86(_: &i32, _: &mut i32, _: &mut i32) { } +// CHECK: define{{.*}}foo86{{.*}}!type ![[TYPE86:[0-9]+]] +pub fn foo87(_: *mut i32) { } +// CHECK: define{{.*}}foo87{{.*}}!type ![[TYPE87:[0-9]+]] +pub fn foo88(_: *mut i32, _: *const i32) { } +// CHECK: define{{.*}}foo88{{.*}}!type ![[TYPE88:[0-9]+]] +pub fn foo89(_: *mut i32, _: *const i32, _: *const i32) { } +// CHECK: define{{.*}}foo89{{.*}}!type ![[TYPE89:[0-9]+]] +pub fn foo90(_: *const i32) { } +// CHECK: define{{.*}}foo90{{.*}}!type ![[TYPE90:[0-9]+]] +pub fn foo91(_: *const i32, _: *mut i32) { } +// CHECK: define{{.*}}foo91{{.*}}!type ![[TYPE91:[0-9]+]] +pub fn foo92(_: *const i32, _: *mut i32, _: *mut i32) { } +// CHECK: define{{.*}}foo92{{.*}}!type ![[TYPE92:[0-9]+]] +pub fn foo93(_: fn(i32) -> i32) { } +// CHECK: define{{.*}}foo93{{.*}}!type ![[TYPE93:[0-9]+]] +pub fn foo94(_: fn(i32) -> i32, _: fn(i32) -> i32) { } +// CHECK: define{{.*}}foo94{{.*}}!type ![[TYPE94:[0-9]+]] +pub fn foo95(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) { } +// CHECK: define{{.*}}foo95{{.*}}!type ![[TYPE95:[0-9]+]] +pub fn foo96(_: &dyn Fn(i32) -> i32) { } +// CHECK: define{{.*}}foo96{{.*}}!type ![[TYPE96:[0-9]+]] +pub fn foo97(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { } +// CHECK: define{{.*}}foo97{{.*}}!type ![[TYPE97:[0-9]+]] +pub fn foo98(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { } +// CHECK: define{{.*}}foo98{{.*}}!type ![[TYPE98:[0-9]+]] +pub fn foo99(_: &dyn FnMut(i32) -> i32) { } +// CHECK: define{{.*}}foo99{{.*}}!type ![[TYPE99:[0-9]+]] +pub fn foo100(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { } +// CHECK: define{{.*}}foo100{{.*}}!type ![[TYPE100:[0-9]+]] +pub fn foo101(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { } +// CHECK: define{{.*}}foo101{{.*}}!type ![[TYPE101:[0-9]+]] +pub fn foo102(_: &dyn FnOnce(i32) -> i32) { } +// CHECK: define{{.*}}foo102{{.*}}!type ![[TYPE102:[0-9]+]] +pub fn foo103(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) { } +// CHECK: define{{.*}}foo103{{.*}}!type ![[TYPE103:[0-9]+]] +pub fn foo104(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {} +// CHECK: define{{.*}}foo104{{.*}}!type ![[TYPE104:[0-9]+]] +pub fn foo105(_: &dyn Send) { } +// CHECK: define{{.*}}foo105{{.*}}!type ![[TYPE105:[0-9]+]] +pub fn foo106(_: &dyn Send, _: &dyn Send) { } +// CHECK: define{{.*}}foo106{{.*}}!type ![[TYPE106:[0-9]+]] +pub fn foo107(_: &dyn Send, _: &dyn Send, _: &dyn Send) { } +// CHECK: define{{.*}}foo107{{.*}}!type ![[TYPE107:[0-9]+]] +pub fn foo108(_: Type1) { } +// CHECK: define{{.*}}foo108{{.*}}!type ![[TYPE108:[0-9]+]] +pub fn foo109(_: Type1, _: Type1) { } +// CHECK: define{{.*}}foo109{{.*}}!type ![[TYPE109:[0-9]+]] +pub fn foo110(_: Type1, _: Type1, _: Type1) { } +// CHECK: define{{.*}}foo110{{.*}}!type ![[TYPE110:[0-9]+]] +pub fn foo111(_: Type2) { } +// CHECK: define{{.*}}foo111{{.*}}!type ![[TYPE111:[0-9]+]] +pub fn foo112(_: Type2, _: Type2) { } +// CHECK: define{{.*}}foo112{{.*}}!type ![[TYPE112:[0-9]+]] +pub fn foo113(_: Type2, _: Type2, _: Type2) { } +// CHECK: define{{.*}}foo113{{.*}}!type ![[TYPE113:[0-9]+]] +pub fn foo114(_: Type3) { } +// CHECK: define{{.*}}foo114{{.*}}!type ![[TYPE114:[0-9]+]] +pub fn foo115(_: Type3, _: Type3) { } +// CHECK: define{{.*}}foo115{{.*}}!type ![[TYPE115:[0-9]+]] +pub fn foo116(_: Type3, _: Type3, _: Type3) { } +// CHECK: define{{.*}}foo116{{.*}}!type ![[TYPE116:[0-9]+]] +pub fn foo117(_: Type4) { } +// CHECK: define{{.*}}foo117{{.*}}!type ![[TYPE117:[0-9]+]] +pub fn foo118(_: Type4, _: Type4) { } +// CHECK: define{{.*}}foo118{{.*}}!type ![[TYPE118:[0-9]+]] +pub fn foo119(_: Type4, _: Type4, _: Type4) { } +// CHECK: define{{.*}}foo119{{.*}}!type ![[TYPE119:[0-9]+]] +pub fn foo120(_: Type5) { } +// CHECK: define{{.*}}foo120{{.*}}!type ![[TYPE120:[0-9]+]] +pub fn foo121(_: Type5, _: Type5) { } +// CHECK: define{{.*}}foo121{{.*}}!type ![[TYPE121:[0-9]+]] +pub fn foo122(_: Type5, _: Type5, _: Type5) { } +// CHECK: define{{.*}}foo122{{.*}}!type ![[TYPE122:[0-9]+]] +pub fn foo123(_: Type6) { } +// CHECK: define{{.*}}foo123{{.*}}!type ![[TYPE123:[0-9]+]] +pub fn foo124(_: Type6, _: Type6) { } +// CHECK: define{{.*}}foo124{{.*}}!type ![[TYPE124:[0-9]+]] +pub fn foo125(_: Type6, _: Type6, _: Type6) { } +// CHECK: define{{.*}}foo125{{.*}}!type ![[TYPE125:[0-9]+]] +pub fn foo126(_: Type7) { } +// CHECK: define{{.*}}foo126{{.*}}!type ![[TYPE126:[0-9]+]] +pub fn foo127(_: Type7, _: Type7) { } +// CHECK: define{{.*}}foo127{{.*}}!type ![[TYPE127:[0-9]+]] +pub fn foo128(_: Type7, _: Type7, _: Type7) { } +// CHECK: define{{.*}}foo128{{.*}}!type ![[TYPE128:[0-9]+]] +pub fn foo129(_: Type8) { } +// CHECK: define{{.*}}foo129{{.*}}!type ![[TYPE129:[0-9]+]] +pub fn foo130(_: Type8, _: Type8) { } +// CHECK: define{{.*}}foo130{{.*}}!type ![[TYPE130:[0-9]+]] +pub fn foo131(_: Type8, _: Type8, _: Type8) { } +// CHECK: define{{.*}}foo131{{.*}}!type ![[TYPE131:[0-9]+]] +pub fn foo132(_: Type9) { } +// CHECK: define{{.*}}foo132{{.*}}!type ![[TYPE132:[0-9]+]] +pub fn foo133(_: Type9, _: Type9) { } +// CHECK: define{{.*}}foo133{{.*}}!type ![[TYPE133:[0-9]+]] +pub fn foo134(_: Type9, _: Type9, _: Type9) { } +// CHECK: define{{.*}}foo134{{.*}}!type ![[TYPE134:[0-9]+]] +pub fn foo135(_: Type10) { } +// CHECK: define{{.*}}foo135{{.*}}!type ![[TYPE135:[0-9]+]] +pub fn foo136(_: Type10, _: Type10) { } +// CHECK: define{{.*}}foo136{{.*}}!type ![[TYPE136:[0-9]+]] +pub fn foo137(_: Type10, _: Type10, _: Type10) { } +// CHECK: define{{.*}}foo137{{.*}}!type ![[TYPE137:[0-9]+]] +pub fn foo138(_: Type11) { } +// CHECK: define{{.*}}foo138{{.*}}!type ![[TYPE138:[0-9]+]] +pub fn foo139(_: Type11, _: Type11) { } +// CHECK: define{{.*}}foo139{{.*}}!type ![[TYPE139:[0-9]+]] +pub fn foo140(_: Type11, _: Type11, _: Type11) { } +// CHECK: define{{.*}}foo140{{.*}}!type ![[TYPE140:[0-9]+]] +pub fn foo141(_: Type12) { } +// CHECK: define{{.*}}foo141{{.*}}!type ![[TYPE141:[0-9]+]] +pub fn foo142(_: Type12, _: Type12) { } +// CHECK: define{{.*}}foo142{{.*}}!type ![[TYPE142:[0-9]+]] +pub fn foo143(_: Type12, _: Type12, _: Type12) { } +// CHECK: define{{.*}}foo143{{.*}}!type ![[TYPE143:[0-9]+]] +pub fn foo144(_: Type13) { } +// CHECK: define{{.*}}foo144{{.*}}!type ![[TYPE144:[0-9]+]] +pub fn foo145(_: Type13, _: Type13) { } +// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]] +pub fn foo146(_: Type13, _: Type13, _: Type13) { } +// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]] + +// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvvE"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPvE"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvS_E"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_S_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPKvE"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvS0_E"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvbE"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbbE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbbE"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu2i8E"} +// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8S_E"} +// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_S_E"} +// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3i16E"} +// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16S_E"} +// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_S_E"} +// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i32E"} +// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32S_E"} +// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_S_E"} +// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i64E"} +// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64S_E"} +// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_S_E"} +// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu4i128E"} +// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128S_E"} +// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_S_E"} +// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu5isizeE"} +// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeS_E"} +// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"} +// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu2u8E"} +// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8S_E"} +// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_S_E"} +// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu3u16E"} +// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16S_E"} +// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_S_E"} +// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u32E"} +// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32S_E"} +// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_S_E"} +// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u64E"} +// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64S_E"} +// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_S_E"} +// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu4u128E"} +// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128S_E"} +// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_S_E"} +// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu5usizeE"} +// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeS_E"} +// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"} +// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu3f32E"} +// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvu3f32S_E"} +// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvu3f32S_S_E"} +// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvu3f64E"} +// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvu3f64S_E"} +// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvu3f64S_S_E"} +// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvu4charE"} +// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charS_E"} +// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_S_E"} +// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu3refIu3strEE"} +// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"} +// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"} +// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"} +// CHECK: ![[TYPE61]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"} +// CHECK: ![[TYPE62]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"} +// CHECK: ![[TYPE63]] = !{i64 0, !"_ZTSFvA32u3i32E"} +// CHECK: ![[TYPE64]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"} +// CHECK: ![[TYPE65]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"} +// CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"} +// CHECK: ![[TYPE67]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"} +// CHECK: ![[TYPE68]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"} +// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EEE"} +// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_E"} +// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EEE"} +// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_E"} +// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EEE"} +// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_E"} +// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE78]] = !{i64 0, !"_ZTSFvP5type1E"} +// CHECK: ![[TYPE79]] = !{i64 0, !"_ZTSFvP5type1S0_E"} +// CHECK: ![[TYPE80]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"} +// CHECK: ![[TYPE81]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"} +// CHECK: ![[TYPE82]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"} +// CHECK: ![[TYPE83]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"} +// CHECK: ![[TYPE84]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"} +// CHECK: ![[TYPE85]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"} +// CHECK: ![[TYPE86]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"} +// CHECK: ![[TYPE87]] = !{i64 0, !"_ZTSFvPu3i32E"} +// CHECK: ![[TYPE88]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"} +// CHECK: ![[TYPE89]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"} +// CHECK: ![[TYPE90]] = !{i64 0, !"_ZTSFvPKu3i32E"} +// CHECK: ![[TYPE91]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"} +// CHECK: ![[TYPE92]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"} +// CHECK: ![[TYPE93]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} +// CHECK: ![[TYPE94]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} +// CHECK: ![[TYPE95]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} +// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} +// CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} +// CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} +// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"} +// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"} +// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"} +// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"} +// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"} +// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"} +// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"} +// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"} +// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"} +// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"} +// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"} +// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"} +// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"} +// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"} +// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"} +// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"} +// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"} +// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"} +// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_EE"} +// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_E"} +// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_S3_E"} +// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"} +// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"} +// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"} +// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_EE"} +// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_E"} +// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_S1_E"} +// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EEE"} +// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_E"} +// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_S2_E"} +// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"} +// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"} +// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"} +// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"} +// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"} +// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"} +// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIu3refIvEEE"} +// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_E"} +// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_S0_E"} diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs new file mode 100644 index 00000000000..09310ba9f60 --- /dev/null +++ b/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs @@ -0,0 +1,31 @@ +// Verifies that type metadata for functions are emitted. +// +// needs-sanitizer-cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi + +#![crate_type="lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] + // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_E") + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] + // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_S_E") + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] + // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_S_S_E") + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"} diff --git a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs b/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs deleted file mode 100644 index 96fced47e78..00000000000 --- a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that type metadata for functions are emitted. -// -// ignore-windows -// needs-sanitizer-cfi -// only-aarch64 -// only-x86_64 -// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi - -#![crate_type="lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} - // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid1") - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}} - // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid2") - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}} - // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid3") - f(arg1, arg2, arg3) -} - -// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid2"} -// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid3"} -// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid4"} diff --git a/src/test/codegen/sanitizer_scs_attr_check.rs b/src/test/codegen/sanitizer_scs_attr_check.rs new file mode 100644 index 00000000000..0b53db3b767 --- /dev/null +++ b/src/test/codegen/sanitizer_scs_attr_check.rs @@ -0,0 +1,17 @@ +// This tests that the shadowcallstack attribute is +// applied when enabling the shadow-call-stack sanitizer. +// +// needs-sanitizer-shadow-call-stack +// compile-flags: -Zsanitizer=shadow-call-stack + +#![crate_type = "lib"] +#![feature(no_sanitize)] + +// CHECK: ; Function Attrs:{{.*}}shadowcallstack +// CHECK-NEXT: scs +pub fn scs() {} + +// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack +// CHECK-NEXT: no_scs +#[no_sanitize(shadow_call_stack)] +pub fn no_scs() {} diff --git a/src/test/ui-fulldeps/gated-plugin.rs b/src/test/ui-fulldeps/gated-plugin.rs index 445469f8733..85eaf533643 100644 --- a/src/test/ui-fulldeps/gated-plugin.rs +++ b/src/test/ui-fulldeps/gated-plugin.rs @@ -1,4 +1,5 @@ // aux-build:empty-plugin.rs +// ignore-stage1 #![plugin(empty_plugin)] //~^ ERROR compiler plugins are deprecated diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr index b8b7dd23c1c..f48f1eab60b 100644 --- a/src/test/ui-fulldeps/gated-plugin.stderr +++ b/src/test/ui-fulldeps/gated-plugin.stderr @@ -1,5 +1,5 @@ error[E0658]: compiler plugins are deprecated - --> $DIR/gated-plugin.rs:3:1 + --> $DIR/gated-plugin.rs:4:1 | LL | #![plugin(empty_plugin)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![plugin(empty_plugin)] = help: add `#![feature(plugin)]` to the crate attributes to enable warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/gated-plugin.rs:3:1 + --> $DIR/gated-plugin.rs:4:1 | LL | #![plugin(empty_plugin)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version diff --git a/src/test/ui-fulldeps/multiple-plugins.rs b/src/test/ui-fulldeps/multiple-plugins.rs index 25d2c8bc123..9af3ebd570c 100644 --- a/src/test/ui-fulldeps/multiple-plugins.rs +++ b/src/test/ui-fulldeps/multiple-plugins.rs @@ -1,6 +1,7 @@ // run-pass // aux-build:multiple-plugins-1.rs // aux-build:multiple-plugins-2.rs +// ignore-stage1 // Check that the plugin registrar of multiple plugins doesn't conflict diff --git a/src/test/ui-fulldeps/multiple-plugins.stderr b/src/test/ui-fulldeps/multiple-plugins.stderr index 99151933c4b..878ffabfc7f 100644 --- a/src/test/ui-fulldeps/multiple-plugins.stderr +++ b/src/test/ui-fulldeps/multiple-plugins.stderr @@ -1,5 +1,5 @@ warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/multiple-plugins.rs:8:1 + --> $DIR/multiple-plugins.rs:9:1 | LL | #![plugin(multiple_plugins_1)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version @@ -7,7 +7,7 @@ LL | #![plugin(multiple_plugins_1)] = note: `#[warn(deprecated)]` on by default warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/multiple-plugins.rs:9:1 + --> $DIR/multiple-plugins.rs:10:1 | LL | #![plugin(multiple_plugins_2)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version diff --git a/src/test/ui/argument-suggestions/issue-98894.rs b/src/test/ui/argument-suggestions/issue-98894.rs new file mode 100644 index 00000000000..c2618a96716 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-98894.rs @@ -0,0 +1,4 @@ +fn main() { + (|_, ()| ())(if true {} else {return;}); + //~^ ERROR this function takes 2 arguments but 1 argument was supplied +} diff --git a/src/test/ui/argument-suggestions/issue-98894.stderr b/src/test/ui/argument-suggestions/issue-98894.stderr new file mode 100644 index 00000000000..0c8b94901e1 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-98894.stderr @@ -0,0 +1,19 @@ +error[E0057]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/issue-98894.rs:2:5 + | +LL | (|_, ()| ())(if true {} else {return;}); + | ^^^^^^^^^^^^--------------------------- an argument of type `()` is missing + | +note: closure defined here + --> $DIR/issue-98894.rs:2:6 + | +LL | (|_, ()| ())(if true {} else {return;}); + | ^^^^^^^ +help: provide the argument + | +LL | (|_, ()| ())(if true {} else {return;}, ()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0057`. diff --git a/src/test/ui/argument-suggestions/issue-98897.rs b/src/test/ui/argument-suggestions/issue-98897.rs new file mode 100644 index 00000000000..c55f495d698 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-98897.rs @@ -0,0 +1,4 @@ +fn main() { + (|_, ()| ())([return, ()]); + //~^ ERROR this function takes 2 arguments but 1 argument was supplied +} diff --git a/src/test/ui/argument-suggestions/issue-98897.stderr b/src/test/ui/argument-suggestions/issue-98897.stderr new file mode 100644 index 00000000000..8f0d98d09e8 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-98897.stderr @@ -0,0 +1,19 @@ +error[E0057]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/issue-98897.rs:2:5 + | +LL | (|_, ()| ())([return, ()]); + | ^^^^^^^^^^^^-------------- an argument of type `()` is missing + | +note: closure defined here + --> $DIR/issue-98897.rs:2:6 + | +LL | (|_, ()| ())([return, ()]); + | ^^^^^^^ +help: provide the argument + | +LL | (|_, ()| ())([return, ()], ()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0057`. diff --git a/src/test/ui/closures/issue-99565.rs b/src/test/ui/closures/issue-99565.rs new file mode 100644 index 00000000000..3a30d2ee034 --- /dev/null +++ b/src/test/ui/closures/issue-99565.rs @@ -0,0 +1,7 @@ +#![crate_type = "lib"] + +fn foo<T, U>(_: U) {} + +fn bar() { + foo(|| {}); //~ ERROR type annotations needed +} diff --git a/src/test/ui/closures/issue-99565.stderr b/src/test/ui/closures/issue-99565.stderr new file mode 100644 index 00000000000..0d940aa9a2f --- /dev/null +++ b/src/test/ui/closures/issue-99565.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/issue-99565.rs:6:5 + | +LL | foo(|| {}); + | ^^^ cannot infer type of the type parameter `T` declared on the function `foo` + | +help: consider specifying the generic arguments + | +LL | foo::<T, _>(|| {}); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/issues/issue-86530.rs b/src/test/ui/const-generics/issues/issue-86530.rs index 4a6ffd1f300..b024decd4e1 100644 --- a/src/test/ui/const-generics/issues/issue-86530.rs +++ b/src/test/ui/const-generics/issues/issue-86530.rs @@ -15,7 +15,6 @@ where fn unit_literals() { z(" "); //~^ ERROR: the trait bound `&str: X` is not satisfied - //~| ERROR: unconstrained generic constant } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-86530.stderr b/src/test/ui/const-generics/issues/issue-86530.stderr index c688f838dab..c63857b2314 100644 --- a/src/test/ui/const-generics/issues/issue-86530.stderr +++ b/src/test/ui/const-generics/issues/issue-86530.stderr @@ -15,22 +15,6 @@ LL | where LL | T: X, | ^ required by this bound in `z` -error: unconstrained generic constant - --> $DIR/issue-86530.rs:16:5 - | -LL | z(" "); - | ^ - | - = help: try adding a `where` bound using this expression: `where [(); T::Y]:` -note: required by a bound in `z` - --> $DIR/issue-86530.rs:11:10 - | -LL | fn z<T>(t: T) - | - required by a bound in this -... -LL | [(); T::Y]: , - | ^^^^ required by this bound in `z` - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-98629.rs b/src/test/ui/const-generics/issues/issue-98629.rs new file mode 100644 index 00000000000..fc8666bbcdb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-98629.rs @@ -0,0 +1,15 @@ +#![feature(const_trait_impl)] + +trait Trait { + const N: usize; +} + +impl const Trait for i32 {} +//~^ ERROR not all trait items implemented, missing: `N` + +fn f() +where + [(); <i32 as Trait>::N]:, +{} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-98629.stderr b/src/test/ui/const-generics/issues/issue-98629.stderr new file mode 100644 index 00000000000..53570220882 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-98629.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `N` + --> $DIR/issue-98629.rs:7:1 + | +LL | const N: usize; + | -------------- `N` from trait +... +LL | impl const Trait for i32 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ missing `N` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr index 5a92555eb32..d328cafa00b 100644 --- a/src/test/ui/invalid/invalid-no-sanitize.stderr +++ b/src/test/ui/invalid/invalid-no-sanitize.stderr @@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize` LL | #[no_sanitize(brontosaurus)] | ^^^^^^^^^^^^ | - = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread` + = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr index 7b9a1634a0d..6592b76a39f 100644 --- a/src/test/ui/issues/issue-23041.stderr +++ b/src/test/ui/issues/issue-23041.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | b.downcast_ref::<fn(_)->_>(); | ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref` | -help: consider specifying the generic arguments +help: consider specifying the generic argument | LL | b.downcast_ref::<fn(_) -> _>(); | ~~~~~~~~~~~~~~ diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr index 863993f4509..995dce552e3 100644 --- a/src/test/ui/issues/issue-24013.stderr +++ b/src/test/ui/issues/issue-24013.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap` | -help: consider specifying the generic arguments +help: consider specifying the generic argument | LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; | ~~~~~~~~~~ diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs index 1d5d5930731..966d76d148a 100644 --- a/src/test/ui/issues/issue-77919.rs +++ b/src/test/ui/issues/issue-77919.rs @@ -1,6 +1,5 @@ fn main() { [1; <Multiply<Five, Five>>::VAL]; - //~^ ERROR: constant expression depends on a generic parameter } trait TypeVal<T> { const VAL: T; diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index b4c877a2d74..ca256847b1f 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `PhantomData` in this scope - --> $DIR/issue-77919.rs:10:9 + --> $DIR/issue-77919.rs:9:9 | LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | use std::marker::PhantomData; | error[E0412]: cannot find type `VAL` in this scope - --> $DIR/issue-77919.rs:12:63 + --> $DIR/issue-77919.rs:11:63 | LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | - ^^^ not found in this scope @@ -18,7 +18,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | help: you might be missing a type parameter: `, VAL` error[E0046]: not all trait items implemented, missing: `VAL` - --> $DIR/issue-77919.rs:12:1 + --> $DIR/issue-77919.rs:11:1 | LL | const VAL: T; | ------------ `VAL` from trait @@ -26,15 +26,7 @@ LL | const VAL: T; LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: constant expression depends on a generic parameter - --> $DIR/issue-77919.rs:2:9 - | -LL | [1; <Multiply<Five, Five>>::VAL]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs new file mode 100644 index 00000000000..7b38c15afc2 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -0,0 +1,14 @@ +#![feature(const_trait_impl)] + +trait Foo { + fn a(&self); +} +trait Bar: ~const Foo {} + +const fn foo<T: Bar>(x: &T) { + x.a(); + //~^ ERROR the trait bound + //~| ERROR cannot call +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr new file mode 100644 index 00000000000..1766cdbee8a --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `T: ~const Foo` is not satisfied + --> $DIR/super-traits-fail-2.rs:9:7 + | +LL | x.a(); + | ^^^ the trait `~const Foo` is not implemented for `T` + | +note: the trait `Foo` is implemented for `T`, but that implementation is not `const` + --> $DIR/super-traits-fail-2.rs:9:7 + | +LL | x.a(); + | ^^^ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> $DIR/super-traits-fail-2.rs:9:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs new file mode 100644 index 00000000000..af465cad3d2 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -0,0 +1,16 @@ +#![feature(const_trait_impl)] + +trait Foo { + fn a(&self); +} +trait Bar: ~const Foo {} + +struct S; +impl Foo for S { + fn a(&self) {} +} + +impl const Bar for S {} +//~^ ERROR the trait bound + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr new file mode 100644 index 00000000000..9e8b8f8c6ba --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `S: ~const Foo` is not satisfied + --> $DIR/super-traits-fail.rs:13:12 + | +LL | impl const Bar for S {} + | ^^^ the trait `~const Foo` is not implemented for `S` + | +note: the trait `Foo` is implemented for `S`, but that implementation is not `const` + --> $DIR/super-traits-fail.rs:13:12 + | +LL | impl const Bar for S {} + | ^^^ +note: required by a bound in `Bar` + --> $DIR/super-traits-fail.rs:6:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^ required by this bound in `Bar` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | impl const Bar for S where S: ~const Foo {} + | +++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs new file mode 100644 index 00000000000..aded4ca9a99 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs @@ -0,0 +1,22 @@ +// check-pass +#![feature(const_trait_impl)] + +trait Foo { + fn a(&self); +} +trait Bar: ~const Foo {} + +struct S; +impl const Foo for S { + fn a(&self) {} +} + +impl const Bar for S {} + +const fn foo<T: ~const Bar>(t: &T) { + t.a(); +} + +const _: () = foo(&S); + +fn main() {} diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index 352a8555614..758b1b139ad 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] anyhow = "1.0.34" curl = "0.4.38" -indexmap = { version = "1.7.0", features = ["serde"] } +indexmap = { version = "1.9.1", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } serde_json = { version = "1.0.59", features = ["preserve_order"] } toml = "0.5.7" diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index a1e37e7317b..638e4a54849 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -30,15 +30,7 @@ LL | const VAL: T; LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: constant expression depends on a generic parameter - --> $DIR/ice-6252.rs:13:9 - | -LL | [1; <Multiply<Five, Five>>::VAL]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 02f4d29a2f0..f8f193ddf83 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -871,11 +871,13 @@ pub fn make_test_description<R: Read>( let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); let has_asm_support = util::has_asm_support(&config.target); let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target); + let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target); let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target); + let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target); // for `-Z gcc-ld=lld` let has_rust_lld = config .compile_lib_path @@ -908,11 +910,14 @@ pub fn make_test_description<R: Read>( ignore |= !rustc_has_sanitizer_support && config.parse_name_directive(ln, "needs-sanitizer-support"); ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"); + ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"); ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"); ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"); ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"); ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"); ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"); + ignore |= !has_shadow_call_stack + && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack"); ignore |= config.target_panic == PanicStrategy::Abort && config.parse_name_directive(ln, "needs-unwind"); ignore |= config.target == "wasm32-unknown-unknown" diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 215af347f17..22df18ee9fb 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -96,6 +96,23 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-unknown-linux-gnu", ]; +// FIXME(rcvalle): More targets are likely supported. +pub const CFI_SUPPORTED_TARGETS: &[&str] = &[ + "aarch64-apple-darwin", + "aarch64-fuchsia", + "aarch64-linux-android", + "aarch64-unknown-freebsd", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-fuchsia", + "x86_64-pc-solaris", + "x86_64-unknown-freebsd", + "x86_64-unknown-illumos", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", +]; + pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[ // FIXME: currently broken, see #88132 // "aarch64-apple-darwin", @@ -121,6 +138,8 @@ pub const HWASAN_SUPPORTED_TARGETS: &[&str] = pub const MEMTAG_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android", "aarch64-unknown-linux-gnu"]; +pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"]; + const BIG_ENDIAN: &[&str] = &[ "aarch64_be", "armebv7r", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index bd08e0ede0b..33c05180408 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,6 @@ clap = "3.1.1" env_logger = "0.7.1" [dependencies.mdbook] -version = "0.4.18" +version = "0.4.21" default-features = false features = ["search"] |
