diff --git a/Cargo.lock b/Cargo.lock index 20b715e59a6e6..d31ef9c4b17e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3409,7 +3409,6 @@ dependencies = [ "rustc_parse", "rustc_session", "rustc_span", - "rustc_target", "thin-vec", ] @@ -4423,6 +4422,7 @@ version = "0.0.0" dependencies = [ "parking_lot", "rustc-rayon-core", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4434,7 +4434,6 @@ dependencies = [ "rustc_serialize", "rustc_session", "rustc_span", - "rustc_target", "smallvec", "thin-vec", "tracing", diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index f3cf7f583cebd..c29db522511d8 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -1,14 +1,19 @@ +use std::cmp::Ordering; use std::fmt; +use std::hash::{Hash, Hasher}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +#[cfg(feature = "nightly")] +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd}; +#[cfg(feature = "nightly")] +use rustc_macros::{Decodable, Encodable}; #[cfg(test)] mod tests; use ExternAbi as Abi; -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)] -#[derive(HashStable_Generic, Encodable, Decodable)] +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))] pub enum ExternAbi { // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the // hashing tests. These are used in many places, so giving them stable values reduces test @@ -68,7 +73,124 @@ pub enum ExternAbi { RiscvInterruptS, } -impl Abi { +macro_rules! abi_impls { + ($e_name:ident = { + $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)* + }) => { + impl $e_name { + pub const ALL_VARIANTS: &[Self] = &[ + $($e_name::$variant $({ unwind: $uw })*,)* + ]; + pub const fn as_str(&self) -> &'static str { + match self { + $($e_name::$variant $( { unwind: $uw } )* => $tok,)* + } + } + } + + impl ::core::str::FromStr for $e_name { + type Err = AbiFromStrErr; + fn from_str(s: &str) -> Result<$e_name, Self::Err> { + match s { + $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)* + _ => Err(AbiFromStrErr::Unknown), + } + } + } + } +} + +#[derive(Debug)] +pub enum AbiFromStrErr { + Unknown, +} + +abi_impls! { + ExternAbi = { + C { unwind: false } =><= "C", + CCmseNonSecureCall =><= "C-cmse-nonsecure-call", + CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry", + C { unwind: true } =><= "C-unwind", + Rust =><= "Rust", + Aapcs { unwind: false } =><= "aapcs", + Aapcs { unwind: true } =><= "aapcs-unwind", + AvrInterrupt =><= "avr-interrupt", + AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt", + Cdecl { unwind: false } =><= "cdecl", + Cdecl { unwind: true } =><= "cdecl-unwind", + EfiApi =><= "efiapi", + Fastcall { unwind: false } =><= "fastcall", + Fastcall { unwind: true } =><= "fastcall-unwind", + GpuKernel =><= "gpu-kernel", + Msp430Interrupt =><= "msp430-interrupt", + PtxKernel =><= "ptx-kernel", + RiscvInterruptM =><= "riscv-interrupt-m", + RiscvInterruptS =><= "riscv-interrupt-s", + RustCall =><= "rust-call", + RustCold =><= "rust-cold", + RustIntrinsic =><= "rust-intrinsic", + Stdcall { unwind: false } =><= "stdcall", + Stdcall { unwind: true } =><= "stdcall-unwind", + System { unwind: false } =><= "system", + System { unwind: true } =><= "system-unwind", + SysV64 { unwind: false } =><= "sysv64", + SysV64 { unwind: true } =><= "sysv64-unwind", + Thiscall { unwind: false } =><= "thiscall", + Thiscall { unwind: true } =><= "thiscall-unwind", + Unadjusted =><= "unadjusted", + Vectorcall { unwind: false } =><= "vectorcall", + Vectorcall { unwind: true } =><= "vectorcall-unwind", + Win64 { unwind: false } =><= "win64", + Win64 { unwind: true } =><= "win64-unwind", + X86Interrupt =><= "x86-interrupt", + } +} + +impl Ord for ExternAbi { + fn cmp(&self, rhs: &Self) -> Ordering { + self.as_str().cmp(rhs.as_str()) + } +} + +impl PartialOrd for ExternAbi { + fn partial_cmp(&self, rhs: &Self) -> Option { + Some(self.cmp(rhs)) + } +} + +impl PartialEq for ExternAbi { + fn eq(&self, rhs: &Self) -> bool { + self.cmp(rhs) == Ordering::Equal + } +} + +impl Eq for ExternAbi {} + +impl Hash for ExternAbi { + fn hash(&self, state: &mut H) { + self.as_str().hash(state); + // double-assurance of a prefix breaker + u32::from_be_bytes(*b"ABI\0").hash(state); + } +} + +#[cfg(feature = "nightly")] +impl HashStable for ExternAbi { + #[inline] + fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) { + Hash::hash(self, hasher); + } +} + +#[cfg(feature = "nightly")] +impl StableOrd for ExternAbi { + const CAN_USE_UNSTABLE_SORT: bool = true; + + // because each ABI is hashed like a string, there is no possible instability + const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); +} + +impl ExternAbi { pub fn supports_varargs(self) -> bool { // * C and Cdecl obviously support varargs. // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs. @@ -92,144 +214,21 @@ impl Abi { } } -#[derive(Copy, Clone)] -pub struct AbiData { - pub abi: Abi, - - /// Name of this ABI as we like it called. - pub name: &'static str, -} - -#[allow(non_upper_case_globals)] -pub const AbiDatas: &[AbiData] = &[ - AbiData { abi: Abi::Rust, name: "Rust" }, - AbiData { abi: Abi::C { unwind: false }, name: "C" }, - AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" }, - AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" }, - AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" }, - AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" }, - AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" }, - AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" }, - AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" }, - AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" }, - AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" }, - AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" }, - AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" }, - AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" }, - AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" }, - AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" }, - AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" }, - AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" }, - AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" }, - AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" }, - AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" }, - AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" }, - AbiData { abi: Abi::GpuKernel, name: "gpu-kernel" }, - AbiData { abi: Abi::EfiApi, name: "efiapi" }, - AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" }, - AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" }, - AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" }, - AbiData { abi: Abi::CCmseNonSecureEntry, name: "C-cmse-nonsecure-entry" }, - AbiData { abi: Abi::System { unwind: false }, name: "system" }, - AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" }, - AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" }, - AbiData { abi: Abi::RustCall, name: "rust-call" }, - AbiData { abi: Abi::Unadjusted, name: "unadjusted" }, - AbiData { abi: Abi::RustCold, name: "rust-cold" }, - AbiData { abi: Abi::RiscvInterruptM, name: "riscv-interrupt-m" }, - AbiData { abi: Abi::RiscvInterruptS, name: "riscv-interrupt-s" }, -]; - -#[derive(Copy, Clone, Debug)] -pub struct AbiUnsupported {} -/// Returns the ABI with the given name (if any). -pub fn lookup(name: &str) -> Result { - AbiDatas - .iter() - .find(|abi_data| name == abi_data.name) - .map(|&x| x.abi) - .ok_or_else(|| AbiUnsupported {}) -} - pub fn all_names() -> Vec<&'static str> { - AbiDatas.iter().map(|d| d.name).collect() + ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect() } -impl Abi { +impl ExternAbi { /// Default ABI chosen for `extern fn` declarations without an explicit ABI. pub const FALLBACK: Abi = Abi::C { unwind: false }; - #[inline] - pub fn index(self) -> usize { - // N.B., this ordering MUST match the AbiDatas array above. - // (This is ensured by the test indices_are_correct().) - use Abi::*; - let i = match self { - // Cross-platform ABIs - Rust => 0, - C { unwind: false } => 1, - C { unwind: true } => 2, - // Platform-specific ABIs - Cdecl { unwind: false } => 3, - Cdecl { unwind: true } => 4, - Stdcall { unwind: false } => 5, - Stdcall { unwind: true } => 6, - Fastcall { unwind: false } => 7, - Fastcall { unwind: true } => 8, - Vectorcall { unwind: false } => 9, - Vectorcall { unwind: true } => 10, - Thiscall { unwind: false } => 11, - Thiscall { unwind: true } => 12, - Aapcs { unwind: false } => 13, - Aapcs { unwind: true } => 14, - Win64 { unwind: false } => 15, - Win64 { unwind: true } => 16, - SysV64 { unwind: false } => 17, - SysV64 { unwind: true } => 18, - PtxKernel => 19, - Msp430Interrupt => 20, - X86Interrupt => 21, - GpuKernel => 22, - EfiApi => 23, - AvrInterrupt => 24, - AvrNonBlockingInterrupt => 25, - CCmseNonSecureCall => 26, - CCmseNonSecureEntry => 27, - // Cross-platform ABIs - System { unwind: false } => 28, - System { unwind: true } => 29, - RustIntrinsic => 30, - RustCall => 31, - Unadjusted => 32, - RustCold => 33, - RiscvInterruptM => 34, - RiscvInterruptS => 35, - }; - debug_assert!( - AbiDatas - .iter() - .enumerate() - .find(|(_, AbiData { abi, .. })| *abi == self) - .map(|(index, _)| index) - .expect("abi variant has associated data") - == i, - "Abi index did not match `AbiDatas` ordering" - ); - i - } - - #[inline] - pub fn data(self) -> &'static AbiData { - &AbiDatas[self.index()] - } - pub fn name(self) -> &'static str { - self.data().name + self.as_str() } } -impl fmt::Display for Abi { +impl fmt::Display for ExternAbi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"{}\"", self.name()) + write!(f, "\"{}\"", self.as_str()) } } diff --git a/compiler/rustc_abi/src/extern_abi/tests.rs b/compiler/rustc_abi/src/extern_abi/tests.rs index 72c0f183d50c1..fc546a6570f0a 100644 --- a/compiler/rustc_abi/src/extern_abi/tests.rs +++ b/compiler/rustc_abi/src/extern_abi/tests.rs @@ -1,29 +1,31 @@ use std::assert_matches::assert_matches; +use std::str::FromStr; use super::*; #[allow(non_snake_case)] #[test] fn lookup_Rust() { - let abi = lookup("Rust"); - assert!(abi.is_ok() && abi.unwrap().data().name == "Rust"); + let abi = ExternAbi::from_str("Rust"); + assert!(abi.is_ok() && abi.unwrap().as_str() == "Rust"); } #[test] fn lookup_cdecl() { - let abi = lookup("cdecl"); - assert!(abi.is_ok() && abi.unwrap().data().name == "cdecl"); + let abi = ExternAbi::from_str("cdecl"); + assert!(abi.is_ok() && abi.unwrap().as_str() == "cdecl"); } #[test] fn lookup_baz() { - let abi = lookup("baz"); - assert_matches!(abi, Err(AbiUnsupported {})); + let abi = ExternAbi::from_str("baz"); + assert_matches!(abi, Err(AbiFromStrErr::Unknown)); } #[test] -fn indices_are_correct() { - for (i, abi_data) in AbiDatas.iter().enumerate() { - assert_eq!(i, abi_data.abi.index()); - } +fn guarantee_lexicographic_ordering() { + let abis = ExternAbi::ALL_VARIANTS; + let mut sorted_abis = abis.to_vec(); + sorted_abis.sort_unstable(); + assert_eq!(abis, sorted_abis); } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 259f1c18ea8e9..da1c706d67cc4 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -52,21 +52,17 @@ use bitflags::bitflags; use rustc_data_structures::stable_hasher::StableOrd; use rustc_index::{Idx, IndexSlice, IndexVec}; #[cfg(feature = "nightly")] -use rustc_macros::HashStable_Generic; -#[cfg(feature = "nightly")] -use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_macros::{Decodable_Generic, Encodable_Generic, HashStable_Generic}; mod callconv; mod layout; #[cfg(test)] mod tests; -#[cfg(feature = "nightly")] mod extern_abi; pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; -#[cfg(feature = "nightly")] -pub use extern_abi::{AbiDatas, AbiUnsupported, ExternAbi, all_names, lookup}; +pub use extern_abi::{ExternAbi, all_names}; #[cfg(feature = "nightly")] pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; pub use layout::{LayoutCalculator, LayoutCalculatorError}; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 85642c8ccb56e..bc2db41546989 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1475,7 +1475,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi { let ast::StrLit { symbol_unescaped, span, .. } = abi_str; - let extern_abi = rustc_abi::lookup(symbol_unescaped.as_str()).unwrap_or_else(|_| { + let extern_abi = symbol_unescaped.as_str().parse().unwrap_or_else(|_| { self.error_on_invalid_abi(abi_str); ExternAbi::Rust }); diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index e7c166850a46b..a2004bbb39f09 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -8,10 +8,10 @@ use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> { - rustc_abi::AbiDatas - .iter() - .filter(|data| extern_abi_enabled(features, span, data.abi).is_ok()) - .map(|d| d.name) + ExternAbi::ALL_VARIANTS + .into_iter() + .filter(|abi| extern_abi_enabled(features, span, **abi).is_ok()) + .map(|abi| abi.as_str()) .collect() } @@ -54,17 +54,12 @@ enum GateReason { impl fmt::Display for UnstableAbi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { abi, .. } = self; - let name = abi.to_string(); - let name = name.trim_matches('"'); match self.explain { GateReason::Experimental => { - write!(f, r#"the extern "{name}" ABI is experimental and subject to change"#) + write!(f, "the extern {abi} ABI is experimental and subject to change") } GateReason::ImplDetail => { - write!( - f, - r#"the extern "{name}" ABI is an implementation detail and perma-unstable"# - ) + write!(f, "the extern {abi} ABI is an implementation detail and perma-unstable") } } } diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 19c379c8599a8..e4c227532085f 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -18,6 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 6efd11a8c3c07..2bcc33241dfa1 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -747,8 +747,7 @@ fn print_crate_info( } } CallingConventions => { - let mut calling_conventions = rustc_abi::all_names(); - calling_conventions.sort_unstable(); + let calling_conventions = rustc_abi::all_names(); println_info!("{}", calling_conventions.join("\n")); } RelocationModels diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index db0d0fcf3b916..d7c8a3d5c0a5f 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -10,9 +10,7 @@ use crate::hir_id::{HirId, ItemLocalId}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: - rustc_ast::HashStableContext + rustc_target::HashStableContext -{ +pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext { fn hash_attr(&mut self, _: &Attribute, hasher: &mut StableHasher); } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index ded1c58057272..09c16222be19c 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -1,6 +1,3 @@ -middle_adjust_for_foreign_abi_error = - target architecture {$arch} does not support `extern {$abi}` ABI - middle_assert_async_resume_after_panic = `async fn` resumed after panicking middle_assert_async_resume_after_return = `async fn` resumed after completion diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index b30d3a950c6a3..91b18295b43b3 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -11,7 +11,7 @@ use crate::ty::Ty; #[derive(Diagnostic)] #[diag(middle_drop_check_overflow, code = E0320)] #[note] -pub struct DropCheckOverflow<'tcx> { +pub(crate) struct DropCheckOverflow<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, @@ -20,14 +20,14 @@ pub struct DropCheckOverflow<'tcx> { #[derive(Diagnostic)] #[diag(middle_failed_writing_file)] -pub struct FailedWritingFile<'a> { +pub(crate) struct FailedWritingFile<'a> { pub path: &'a Path, pub error: io::Error, } #[derive(Diagnostic)] #[diag(middle_opaque_hidden_type_mismatch)] -pub struct OpaqueHiddenTypeMismatch<'tcx> { +pub(crate) struct OpaqueHiddenTypeMismatch<'tcx> { pub self_ty: Ty<'tcx>, pub other_ty: Ty<'tcx>, #[primary_span] @@ -37,12 +37,14 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> { pub sub: TypeMismatchReason, } +// FIXME(autodiff): I should get used somewhere #[derive(Diagnostic)] #[diag(middle_unsupported_union)] pub struct UnsupportedUnion { pub ty_name: String, } +// FIXME(autodiff): I should get used somewhere #[derive(Diagnostic)] #[diag(middle_autodiff_unsafe_inner_const_ref)] pub struct AutodiffUnsafeInnerConstRef { @@ -67,7 +69,7 @@ pub enum TypeMismatchReason { #[derive(Diagnostic)] #[diag(middle_limit_invalid)] -pub struct LimitInvalid<'a> { +pub(crate) struct LimitInvalid<'a> { #[primary_span] pub span: Span, #[label] @@ -78,14 +80,14 @@ pub struct LimitInvalid<'a> { #[derive(Diagnostic)] #[diag(middle_recursion_limit_reached)] #[help] -pub struct RecursionLimitReached<'tcx> { +pub(crate) struct RecursionLimitReached<'tcx> { pub ty: Ty<'tcx>, pub suggested_limit: rustc_session::Limit, } #[derive(Diagnostic)] #[diag(middle_const_eval_non_int)] -pub struct ConstEvalNonIntError { +pub(crate) struct ConstEvalNonIntError { #[primary_span] pub span: Span, } @@ -159,27 +161,17 @@ pub enum LayoutError<'tcx> { ReferencesError, } -#[derive(Diagnostic)] -#[diag(middle_adjust_for_foreign_abi_error)] -pub struct UnsupportedFnAbi { - pub arch: Symbol, - pub abi: &'static str, -} - #[derive(Diagnostic)] #[diag(middle_erroneous_constant)] -pub struct ErroneousConstant { +pub(crate) struct ErroneousConstant { #[primary_span] pub span: Span, } -/// Used by `rustc_const_eval` -pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error; - #[derive(Diagnostic)] #[diag(middle_type_length_limit)] #[help(middle_consider_type_length_limit)] -pub struct TypeLengthLimit { +pub(crate) struct TypeLengthLimit { #[primary_span] pub span: Span, pub shrunk: String, diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 96b210accdb37..a42329b4614f0 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start parking_lot = "0.12" rustc-rayon-core = { version = "0.5.0" } +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -18,7 +19,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 480fd49772833..7d508b8201bdf 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -8,7 +8,7 @@ use smallvec::SmallVec; use crate::ich::StableHashingContext; -impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {} +impl<'ctx> rustc_abi::HashStableContext for StableHashingContext<'ctx> {} impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {} impl<'a> HashStable> for [hir::Attribute] { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0ac6f17b97bd0..4fafd1ac3509a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -480,7 +480,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ExternAbi::C { unwind: false } => cx.push("KC"), abi => { cx.push("K"); - let name = abi.name(); + let name = abi.as_str(); if name.contains('-') { cx.push_ident(&name.replace('-', "_")); } else { diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index bde4af643fa6c..7ebe96960ed0f 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -30,7 +30,7 @@ pub mod target_features; #[cfg(test)] mod tests; -pub use rustc_abi::HashStableContext; +use rustc_abi::HashStableContext; /// The name of rustc's own place to organize libraries. /// diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e495bdbf7825c..bfab009a7e35c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -920,11 +920,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // T: Trait // so it seems ok if we (conservatively) fail to accept that `Unsize` // obligation above. Should be possible to extend this in the future. - let Some(source) = obligation.self_ty().no_bound_vars() else { + let Some(trait_pred) = obligation.predicate.no_bound_vars() else { // Don't add any candidates if there are bound regions. return; }; - let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1); + let source = trait_pred.self_ty(); + let target = trait_pred.trait_ref.args.type_at(1); debug!(?source, ?target, "assemble_candidates_for_unsizing"); diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index e1348552b65c3..eb99be817a2ca 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1070,7 +1070,7 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { ub_checks::assert_unsafe_precondition!( - check_language_ub, + check_library_ub, "ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \ and the specified memory ranges do not overlap", ( diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 29342cc5a2c5b..1c8cc4025df11 100644 --- a/src/bootstrap/src/utils/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -1,3 +1,17 @@ +//! This module helps you efficiently store and retrieve values using interning. +//! +//! Interning is a neat trick that keeps only one copy of identical values, saving memory +//! and making comparisons super fast. Here, we provide the `Interned` struct and the `Internable` trait +//! to make interning easy for different data types. +//! +//! The `Interner` struct handles caching for common types like `String`, `PathBuf`, and `Vec`, +//! while the `Cache` struct acts as a write-once storage for linking computation steps with their results. +//! +//! # Thread Safety +//! +//! We use `Mutex` to make sure interning and retrieval are thread-safe. But keep in mind—once a value is +//! interned, it sticks around for the entire lifetime of the program. + use std::any::{Any, TypeId}; use std::borrow::Borrow; use std::cell::RefCell; @@ -12,6 +26,9 @@ use std::{fmt, mem}; use crate::core::builder::Step; +/// Represents an interned value of type `T`, allowing for efficient comparisons and retrieval. +/// +/// This struct stores a unique index referencing the interned value within an internal cache. pub struct Interned(usize, PhantomData<*const T>); impl Default for Interned { @@ -111,6 +128,10 @@ impl Ord for Interned { } } +/// A structure for managing the interning of values of type `T`. +/// +/// `TyIntern` maintains a mapping between values and their interned representations, +/// ensuring that duplicate values are not stored multiple times. struct TyIntern { items: Vec, set: HashMap>, @@ -123,6 +144,9 @@ impl Default for TyIntern { } impl TyIntern { + /// Interns a borrowed value, ensuring it is stored uniquely. + /// + /// If the value has been previously interned, the same `Interned` instance is returned. fn intern_borrow(&mut self, item: &B) -> Interned where B: Eq + Hash + ToOwned + ?Sized, @@ -138,6 +162,9 @@ impl TyIntern { interned } + /// Interns an owned value, storing it uniquely. + /// + /// If the value has been previously interned, the existing `Interned` is returned. fn intern(&mut self, item: T) -> Interned { if let Some(i) = self.set.get(&item) { return *i; @@ -148,11 +175,16 @@ impl TyIntern { interned } + /// Retrieves a reference to the interned value associated with the given `Interned` instance. fn get(&self, i: Interned) -> &T { &self.items[i.0] } } +/// A global interner for managing interned values of common types. +/// +/// This structure maintains caches for `String`, `PathBuf`, and `Vec`, ensuring efficient storage +/// and retrieval of frequently used values. #[derive(Default)] pub struct Interner { strs: Mutex>, @@ -160,6 +192,10 @@ pub struct Interner { lists: Mutex>>, } +/// Defines the behavior required for a type to be internable. +/// +/// Types implementing this trait must provide access to a static cache and define an `intern` method +/// that ensures values are stored uniquely. trait Internable: Clone + Eq + Hash + 'static { fn intern_cache() -> &'static Mutex>; @@ -187,11 +223,15 @@ impl Internable for Vec { } impl Interner { + /// Interns a string reference, ensuring it is stored uniquely. + /// + /// If the string has been previously interned, the same `Interned` instance is returned. pub fn intern_str(&self, s: &str) -> Interned { self.strs.lock().unwrap().intern_borrow(s) } } +/// A global instance of `Interner` that caches common interned values. pub static INTERNER: LazyLock = LazyLock::new(Interner::default); /// This is essentially a `HashMap` which allows storing any type in its input and @@ -209,10 +249,12 @@ pub struct Cache( ); impl Cache { + /// Creates a new empty cache. pub fn new() -> Cache { Cache(RefCell::new(HashMap::new())) } + /// Stores the result of a computation step in the cache. pub fn put(&self, step: S, value: S::Output) { let mut cache = self.0.borrow_mut(); let type_id = TypeId::of::(); @@ -225,6 +267,7 @@ impl Cache { stepcache.insert(step, value); } + /// Retrieves a cached result for the given step, if available. pub fn get(&self, step: &S) -> Option { let mut cache = self.0.borrow_mut(); let type_id = TypeId::of::(); @@ -255,3 +298,6 @@ impl Cache { self.0.borrow().contains_key(&TypeId::of::()) } } + +#[cfg(test)] +mod tests; diff --git a/src/bootstrap/src/utils/cache/tests.rs b/src/bootstrap/src/utils/cache/tests.rs new file mode 100644 index 0000000000000..28f5563a589b1 --- /dev/null +++ b/src/bootstrap/src/utils/cache/tests.rs @@ -0,0 +1,52 @@ +use std::path::PathBuf; + +use crate::utils::cache::{INTERNER, Internable, TyIntern}; + +#[test] +fn test_string_interning() { + let s1 = INTERNER.intern_str("Hello"); + let s2 = INTERNER.intern_str("Hello"); + let s3 = INTERNER.intern_str("world"); + + assert_eq!(s1, s2, "Same strings should be interned to the same instance"); + assert_ne!(s1, s3, "Different strings should have different interned values"); +} + +#[test] +fn test_path_interning() { + let p1 = PathBuf::from("/tmp/file").intern(); + let p2 = PathBuf::from("/tmp/file").intern(); + let p3 = PathBuf::from("/tmp/other").intern(); + + assert_eq!(p1, p2); + assert_ne!(p1, p3); +} + +#[test] +fn test_vec_interning() { + let v1 = vec!["a".to_string(), "b".to_string()].intern(); + let v2 = vec!["a".to_string(), "b".to_string()].intern(); + let v3 = vec!["c".to_string()].intern(); + + assert_eq!(v1, v2); + assert_ne!(v1, v3); +} + +#[test] +fn test_interned_equality() { + let s1 = INTERNER.intern_str("test"); + let s2 = INTERNER.intern_str("test"); + + assert_eq!(s1, s2); + assert_eq!(s1, "test"); +} + +#[test] +fn test_ty_intern_intern_borrow() { + let mut interner = TyIntern::default(); + let s1 = interner.intern_borrow("borrowed"); + let s2 = interner.intern("borrowed".to_string()); + + assert_eq!(s1, s2); + assert_eq!(interner.get(s1), "borrowed"); +} diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index f6afd50afcef0..45797c1276c58 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -29,11 +29,8 @@ use crate::core::config::TargetSelection; use crate::utils::exec::{BootstrapCommand, command}; use crate::{Build, CLang, GitRepo}; -// The `cc` crate doesn't provide a way to obtain a path to the detected archiver, -// so use some simplified logic here. First we respect the environment variable `AR`, then -// try to infer the archiver path from the C compiler path. -// In the future this logic should be replaced by calling into the `cc` crate. -fn cc2ar(cc: &Path, target: TargetSelection) -> Option { +/// FIXME(onur-ozkan): This logic should be replaced by calling into the `cc` crate. +fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option { if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace('-', "_"))) { Some(PathBuf::from(ar)) } else if let Some(ar) = env::var_os("AR") { @@ -57,16 +54,7 @@ fn cc2ar(cc: &Path, target: TargetSelection) -> Option { } else if target.contains("android") || target.contains("-wasi") { Some(cc.parent().unwrap().join(PathBuf::from("llvm-ar"))) } else { - let parent = cc.parent().unwrap(); - let file = cc.file_name().unwrap().to_str().unwrap(); - for suffix in &["gcc", "cc", "clang"] { - if let Some(idx) = file.rfind(suffix) { - let mut file = file[..idx].to_owned(); - file.push_str("ar"); - return Some(parent.join(&file)); - } - } - Some(parent.join(file)) + Some(default_ar) } } @@ -138,7 +126,7 @@ pub fn find_target(build: &Build, target: TargetSelection) { let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { ar } else { - cc2ar(compiler.path(), target) + cc2ar(compiler.path(), target, PathBuf::from(cfg.get_archiver().get_program())) }; build.cc.borrow_mut().insert(target, compiler.clone()); diff --git a/src/doc/rustc-dev-guide/src/implementing_new_features.md b/src/doc/rustc-dev-guide/src/implementing_new_features.md index d87afeaedce6e..5b67ccd7f4c5e 100644 --- a/src/doc/rustc-dev-guide/src/implementing_new_features.md +++ b/src/doc/rustc-dev-guide/src/implementing_new_features.md @@ -9,7 +9,11 @@ smoothly. **NOTE: this section is for *language* features, not *library* features, which use [a different process].** +See also [the Rust Language Design Team's procedures][lang-propose] for +proposing changes to the language. + [a different process]: ./stability.md +[lang-propose]: https://lang-team.rust-lang.org/how_to/propose.html ## The @rfcbot FCP process diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index b6a73602a322f..086a85aa616f6 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -37,113 +37,8 @@ use crate::html::render::Context; use crate::joined::Joined as _; use crate::passes::collect_intra_doc_links::UrlFragment; -pub(crate) trait Print { - fn print(self, buffer: &mut Buffer); -} - -impl Print for F -where - F: FnOnce(&mut Buffer), -{ - fn print(self, buffer: &mut Buffer) { - (self)(buffer) - } -} - -impl Print for String { - fn print(self, buffer: &mut Buffer) { - buffer.write_str(&self); - } -} - -impl Print for &'_ str { - fn print(self, buffer: &mut Buffer) { - buffer.write_str(self); - } -} - -#[derive(Debug, Clone)] -pub(crate) struct Buffer { - for_html: bool, - buffer: String, -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> fmt::Result { - self.buffer.write_str(s) - } - - #[inline] - fn write_char(&mut self, c: char) -> fmt::Result { - self.buffer.write_char(c) - } - - #[inline] - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { - self.buffer.write_fmt(args) - } -} - -impl Buffer { - pub(crate) fn empty_from(v: &Buffer) -> Buffer { - Buffer { for_html: v.for_html, buffer: String::new() } - } - - pub(crate) fn html() -> Buffer { - Buffer { for_html: true, buffer: String::new() } - } - - pub(crate) fn new() -> Buffer { - Buffer { for_html: false, buffer: String::new() } - } - - pub(crate) fn is_empty(&self) -> bool { - self.buffer.is_empty() - } - - pub(crate) fn into_inner(self) -> String { - self.buffer - } - - pub(crate) fn push(&mut self, c: char) { - self.buffer.push(c); - } - - pub(crate) fn push_str(&mut self, s: &str) { - self.buffer.push_str(s); - } - - pub(crate) fn push_buffer(&mut self, other: Buffer) { - self.buffer.push_str(&other.buffer); - } - - // Intended for consumption by write! and writeln! (std::fmt) but without - // the fmt::Result return type imposed by fmt::Write (and avoiding the trait - // import). - pub(crate) fn write_str(&mut self, s: &str) { - self.buffer.push_str(s); - } - - // Intended for consumption by write! and writeln! (std::fmt) but without - // the fmt::Result return type imposed by fmt::Write (and avoiding the trait - // import). - pub(crate) fn write_fmt(&mut self, v: fmt::Arguments<'_>) { - self.buffer.write_fmt(v).unwrap(); - } - - pub(crate) fn to_display(mut self, t: T) -> String { - t.print(&mut self); - self.into_inner() - } - - pub(crate) fn reserve(&mut self, additional: usize) { - self.buffer.reserve(additional) - } - - pub(crate) fn len(&self) -> usize { - self.buffer.len() - } +pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) { + s.write_fmt(f).unwrap(); } pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( @@ -772,7 +667,7 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Cont else { return String::new(); }; - let mut buf = Buffer::new(); + let mut buf = String::new(); let fqp = if *shortty == ItemType::Primitive { // primitives are documented in a crate, but not actually part of it &fqp[fqp.len() - 1..] @@ -780,19 +675,19 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Cont fqp }; if let &Some(UrlFragment::Item(id)) = fragment { - write!(buf, "{} ", cx.tcx().def_descr(id)); + write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id))); for component in fqp { - write!(buf, "{component}::"); + write_str(&mut buf, format_args!("{component}::")); } - write!(buf, "{}", cx.tcx().item_name(id)); + write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id))); } else if !fqp.is_empty() { let mut fqp_it = fqp.iter(); - write!(buf, "{shortty} {}", fqp_it.next().unwrap()); + write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap())); for component in fqp_it { - write!(buf, "::{component}"); + write_str(&mut buf, format_args!("::{component}")); } } - buf.into_inner() + buf } /// Used to render a [`clean::Path`]. diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 15bf968e0fc77..ed4b97d36252c 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -14,7 +14,7 @@ use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, DUMMY_SP, Span}; -use super::format::{self, Buffer}; +use super::format::{self, write_str}; use crate::clean::PrimitiveType; use crate::html::escape::EscapeBodyText; use crate::html::render::{Context, LinkFromSrc}; @@ -48,7 +48,7 @@ pub(crate) enum Tooltip { /// Highlights `src` as an inline example, returning the HTML output. pub(crate) fn render_example_with_highlighting( src: &str, - out: &mut Buffer, + out: &mut String, tooltip: Tooltip, playground_button: Option<&str>, extra_classes: &[String], @@ -59,61 +59,69 @@ pub(crate) fn render_example_with_highlighting( } fn write_header( - out: &mut Buffer, + out: &mut String, class: &str, - extra_content: Option, + extra_content: Option<&str>, tooltip: Tooltip, extra_classes: &[String], ) { - write!( + write_str( out, - "
", - match tooltip { - Tooltip::Ignore => " ignore", - Tooltip::CompileFail => " compile_fail", - Tooltip::ShouldPanic => " should_panic", - Tooltip::Edition(_) => " edition", - Tooltip::None => "", - }, + format_args!( + "
", + match tooltip { + Tooltip::Ignore => " ignore", + Tooltip::CompileFail => " compile_fail", + Tooltip::ShouldPanic => " should_panic", + Tooltip::Edition(_) => " edition", + Tooltip::None => "", + } + ), ); if tooltip != Tooltip::None { let edition_code; - write!( + write_str( out, - "", - match tooltip { - Tooltip::Ignore => "This example is not tested", - Tooltip::CompileFail => "This example deliberately fails to compile", - Tooltip::ShouldPanic => "This example panics", - Tooltip::Edition(edition) => { - edition_code = format!("This example runs with edition {edition}"); - &edition_code + format_args!( + "", + match tooltip { + Tooltip::Ignore => "This example is not tested", + Tooltip::CompileFail => "This example deliberately fails to compile", + Tooltip::ShouldPanic => "This example panics", + Tooltip::Edition(edition) => { + edition_code = format!("This example runs with edition {edition}"); + &edition_code + } + Tooltip::None => unreachable!(), } - Tooltip::None => unreachable!(), - }, + ), ); } if let Some(extra) = extra_content { - out.push_buffer(extra); + out.push_str(&extra); } if class.is_empty() { - write!( + write_str( out, - "
",
-            if extra_classes.is_empty() { "" } else { " " },
-            extra_classes.join(" "),
+            format_args!(
+                "
",
+                if extra_classes.is_empty() { "" } else { " " },
+                extra_classes.join(" ")
+            ),
         );
     } else {
-        write!(
+        write_str(
             out,
-            "
",
-            if extra_classes.is_empty() { "" } else { " " },
-            extra_classes.join(" "),
+            format_args!(
+                "
",
+                if extra_classes.is_empty() { "" } else { " " },
+                extra_classes.join(" ")
+            ),
         );
     }
-    write!(out, "");
+    write_str(out, format_args!(""));
 }
 
 /// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -398,8 +406,8 @@ pub(super) fn write_code(
     });
 }
 
-fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
-    writeln!(out, "
{}
", playground_button.unwrap_or_default()); +fn write_footer(out: &mut String, playground_button: Option<&str>) { + write_str(out, format_args_nl!("{}
", playground_button.unwrap_or_default())); } /// How a span of text is classified. Mostly corresponds to token kinds. diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 8f39130bb836e..2603e887bead5 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_span::create_default_session_globals_then; use super::{DecorationInfo, write_code}; -use crate::html::format::Buffer; const STYLE: &str = r#"