diff --git a/Cargo.lock b/Cargo.lock index 2ee2c52b32ad..d31ef9c4b17e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1997,7 +1997,7 @@ dependencies = [ "anyhow", "clap", "fs-err", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "rustdoc-json-types", "serde", "serde_json", @@ -3188,7 +3188,7 @@ dependencies = [ "proc-macro2", "quote", "rinja_parser", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "syn 2.0.96", ] @@ -3252,9 +3252,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-main" @@ -3317,7 +3317,6 @@ dependencies = [ "rand 0.8.5", "rand_xoshiro", "rustc_data_structures", - "rustc_feature", "rustc_index", "rustc_macros", "rustc_serialize", @@ -3379,6 +3378,7 @@ dependencies = [ "rustc_ast_pretty", "rustc_data_structures", "rustc_errors", + "rustc_feature", "rustc_fluent_macro", "rustc_hir", "rustc_index", @@ -3409,7 +3409,6 @@ dependencies = [ "rustc_parse", "rustc_session", "rustc_span", - "rustc_target", "thin-vec", ] @@ -3654,7 +3653,7 @@ dependencies = [ "memmap2", "parking_lot", "portable-atomic", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "rustc-rayon", "rustc-stable-hash", "rustc_arena", @@ -3683,6 +3682,7 @@ version = "0.0.0" dependencies = [ "ctrlc", "libc", + "rustc_abi", "rustc_ast", "rustc_ast_lowering", "rustc_ast_passes", @@ -4337,6 +4337,7 @@ version = "0.0.0" dependencies = [ "rustc_abi", "rustc_ast", + "rustc_ast_lowering", "rustc_ast_pretty", "rustc_attr_parsing", "rustc_data_structures", @@ -4360,7 +4361,7 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "rustc_abi", "rustc_apfloat", "rustc_arena", @@ -4421,6 +4422,7 @@ version = "0.0.0" dependencies = [ "parking_lot", "rustc-rayon-core", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4432,7 +4434,6 @@ dependencies = [ "rustc_serialize", "rustc_session", "rustc_span", - "rustc_target", "smallvec", "thin-vec", "tracing", @@ -4755,7 +4756,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "serde_json", ] @@ -5406,7 +5407,7 @@ dependencies = [ "ignore", "miropt-test-tools", "regex", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "semver", "serde", "similar", diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 3acd25e54611..1013f1d3958d 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -9,7 +9,6 @@ bitflags = "2.4.1" rand = { version = "0.8.4", default-features = false, optional = true } rand_xoshiro = { version = "0.6.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } -rustc_feature = { path = "../rustc_feature", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } @@ -24,7 +23,6 @@ default = ["nightly", "randomize"] # without depending on rustc_data_structures, rustc_macros and rustc_serialize nightly = [ "dep:rustc_data_structures", - "dep:rustc_feature", "dep:rustc_macros", "dep:rustc_serialize", "dep:rustc_span", diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index daa365bf6e1d..9fb70b80c9ef 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -1,6 +1,5 @@ #[cfg(feature = "nightly")] -use crate::{BackendRepr, FieldsShape, TyAbiInterface, TyAndLayout}; -use crate::{Primitive, Size, Variants}; +use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayout, Variants}; mod reg; diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 130834d560f7..c29db522511d 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -1,15 +1,19 @@ +use std::cmp::Ordering; use std::fmt; +use std::hash::{Hash, Hasher}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; -use rustc_span::{Span, Symbol, sym}; +#[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 @@ -69,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. @@ -93,255 +214,21 @@ impl Abi { } } -#[derive(Copy, Clone)] -pub struct AbiData { - abi: Abi, - - /// Name of this ABI as we like it called. - name: &'static str, -} - -#[allow(non_upper_case_globals)] -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 enum AbiUnsupported { - Unrecognized, - Reason { explain: &'static str }, -} - -/// 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(|| match name { - "riscv-interrupt" => AbiUnsupported::Reason { - explain: "please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively", - }, - "riscv-interrupt-u" => AbiUnsupported::Reason { - explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314", - }, - "wasm" => AbiUnsupported::Reason { - explain: "non-standard wasm ABI is no longer supported", - }, - - _ => AbiUnsupported::Unrecognized, - - }) -} - pub fn all_names() -> Vec<&'static str> { - AbiDatas.iter().map(|d| d.name).collect() + ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect() } -pub fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> { - AbiDatas - .iter() - .map(|d| d.name) - .filter(|name| is_enabled(features, span, name).is_ok()) - .collect() -} - -pub enum AbiDisabled { - Unstable { feature: Symbol, explain: &'static str }, - Unrecognized, -} - -pub fn is_enabled( - features: &rustc_feature::Features, - span: Span, - name: &str, -) -> Result<(), AbiDisabled> { - let s = is_stable(name); - if let Err(AbiDisabled::Unstable { feature, .. }) = s { - if features.enabled(feature) || span.allows_unstable(feature) { - return Ok(()); - } - } - s -} - -/// Returns whether the ABI is stable to use. -/// -/// Note that there is a separate check determining whether the ABI is even supported -/// on the current target; see `fn is_abi_supported` in `rustc_target::spec`. -pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { - match name { - // Stable - "Rust" | "C" | "C-unwind" | "cdecl" | "cdecl-unwind" | "stdcall" | "stdcall-unwind" - | "fastcall" | "fastcall-unwind" | "aapcs" | "aapcs-unwind" | "win64" | "win64-unwind" - | "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" | "thiscall" - | "thiscall-unwind" => Ok(()), - "rust-intrinsic" => Err(AbiDisabled::Unstable { - feature: sym::intrinsics, - explain: "intrinsics are subject to change", - }), - "vectorcall" => Err(AbiDisabled::Unstable { - feature: sym::abi_vectorcall, - explain: "vectorcall is experimental and subject to change", - }), - "vectorcall-unwind" => Err(AbiDisabled::Unstable { - feature: sym::abi_vectorcall, - explain: "vectorcall-unwind ABI is experimental and subject to change", - }), - "rust-call" => Err(AbiDisabled::Unstable { - feature: sym::unboxed_closures, - explain: "rust-call ABI is subject to change", - }), - "rust-cold" => Err(AbiDisabled::Unstable { - feature: sym::rust_cold_cc, - explain: "rust-cold is experimental and subject to change", - }), - "ptx-kernel" => Err(AbiDisabled::Unstable { - feature: sym::abi_ptx, - explain: "PTX ABIs are experimental and subject to change", - }), - "unadjusted" => Err(AbiDisabled::Unstable { - feature: sym::abi_unadjusted, - explain: "unadjusted ABI is an implementation detail and perma-unstable", - }), - "msp430-interrupt" => Err(AbiDisabled::Unstable { - feature: sym::abi_msp430_interrupt, - explain: "msp430-interrupt ABI is experimental and subject to change", - }), - "x86-interrupt" => Err(AbiDisabled::Unstable { - feature: sym::abi_x86_interrupt, - explain: "x86-interrupt ABI is experimental and subject to change", - }), - "gpu-kernel" => Err(AbiDisabled::Unstable { - feature: sym::abi_gpu_kernel, - explain: "gpu-kernel ABI is experimental and subject to change", - }), - "avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable { - feature: sym::abi_avr_interrupt, - explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change", - }), - "riscv-interrupt-m" | "riscv-interrupt-s" => Err(AbiDisabled::Unstable { - feature: sym::abi_riscv_interrupt, - explain: "riscv-interrupt ABIs are experimental and subject to change", - }), - "C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable { - feature: sym::abi_c_cmse_nonsecure_call, - explain: "C-cmse-nonsecure-call ABI is experimental and subject to change", - }), - "C-cmse-nonsecure-entry" => Err(AbiDisabled::Unstable { - feature: sym::cmse_nonsecure_entry, - explain: "C-cmse-nonsecure-entry ABI is experimental and subject to change", - }), - _ => Err(AbiDisabled::Unrecognized), - } -} - -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 4823058dd697..fc546a6570f0 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::Unrecognized)); + 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 fc34b2889330..da1c706d67cc 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -52,23 +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::{ - AbiDisabled, AbiUnsupported, ExternAbi, all_names, enabled_names, is_enabled, is_stable, 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/src/ast.rs b/compiler/rustc_ast/src/ast.rs index deee3a597aed..29c1d34a125a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2249,7 +2249,7 @@ pub enum TyKind { CVarArgs, /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero`, /// just as part of the type system. - Pat(P, P), + Pat(P, P), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. @@ -2277,6 +2277,27 @@ impl TyKind { } } +/// A pattern type pattern. +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct TyPat { + pub id: NodeId, + pub kind: TyPatKind, + pub span: Span, + pub tokens: Option, +} + +/// All the different flavors of pattern that Rust recognizes. +// +// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum TyPatKind { + /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). + Range(Option>, Option>, Spanned), + + /// Placeholder for a pattern that wasn't syntactically well formed in some way. + Err(ErrorGuaranteed), +} + /// Syntax used to declare a trait object. #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] #[repr(u8)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a9961cca5833..de9f049704a4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -210,6 +210,10 @@ pub trait MutVisitor: Sized { walk_ty(self, t); } + fn visit_ty_pat(&mut self, t: &mut P) { + walk_ty_pat(self, t); + } + fn visit_lifetime(&mut self, l: &mut Lifetime) { walk_lifetime(self, l); } @@ -570,7 +574,7 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Pat(ty, pat) => { vis.visit_ty(ty); - vis.visit_pat(pat); + vis.visit_ty_pat(pat); } TyKind::Path(qself, path) => { vis.visit_qself(qself); @@ -594,6 +598,20 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { vis.visit_span(span); } +pub fn walk_ty_pat(vis: &mut T, ty: &mut P) { + let TyPat { id, kind, span, tokens } = ty.deref_mut(); + vis.visit_id(id); + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt(start, |c| vis.visit_anon_const(c)); + visit_opt(end, |c| vis.visit_anon_const(c)); + } + TyPatKind::Err(_) => {} + } + visit_lazy_tts(vis, tokens); + vis.visit_span(span); +} + fn walk_foreign_mod(vis: &mut T, foreign_mod: &mut ForeignMod) { let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; visit_safety(vis, safety); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 714b074f930c..3242d4145959 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -179,6 +179,9 @@ pub trait Visitor<'ast>: Sized { fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result { walk_ty(self, t) } + fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result { + walk_ty_pat(self, t) + } fn visit_generic_param(&mut self, param: &'ast GenericParam) -> Self::Result { walk_generic_param(self, param) } @@ -534,7 +537,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { } TyKind::Pat(ty, pat) => { try_visit!(visitor.visit_ty(ty)); - try_visit!(visitor.visit_pat(pat)); + try_visit!(visitor.visit_ty_pat(pat)); } TyKind::Array(ty, length) => { try_visit!(visitor.visit_ty(ty)); @@ -555,6 +558,18 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { V::Result::output() } +pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Result { + let TyPat { id: _, kind, span: _, tokens: _ } = tp; + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt!(visitor, visit_anon_const, start); + visit_opt!(visitor, visit_anon_const, end); + } + TyPatKind::Err(_) => {} + } + V::Result::output() +} + fn walk_qself<'a, V: Visitor<'a>>(visitor: &mut V, qself: &'a Option>) -> V::Result { if let Some(qself) = qself { let QSelf { ty, path_span: _, position: _ } = &**qself; diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 754f3c1a6e9a..ce95f4dfa1b8 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -13,6 +13,7 @@ rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index f96c9fe8e327..1b91c33742d8 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -112,7 +112,8 @@ ast_lowering_invalid_register = invalid register `{$reg}`: {$error} ast_lowering_invalid_register_class = - invalid register class `{$reg_class}`: {$error} + invalid register class `{$reg_class}`: unknown register class + .note = the following register classes are supported on this target: {$supported_register_classes} ast_lowering_match_arm_with_no_body = `match` arm with no body diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 2f1f1269ece5..96c230ec243a 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -152,11 +152,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::RegClass(reg_class) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else( - |error| { + |supported_register_classes| { + let mut register_classes = + format!("`{}`", supported_register_classes[0]); + for m in &supported_register_classes[1..] { + let _ = write!(register_classes, ", `{m}`"); + } self.dcx().emit_err(InvalidRegisterClass { op_span: *op_sp, reg_class, - error, + supported_register_classes: register_classes, }); asm::InlineAsmRegClass::Err }, diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index f9fe4938ca8b..d8b7cb0c3225 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -41,13 +41,13 @@ use std::iter; use ast::visit::Visitor; use hir::def::{DefKind, PartialRes, Res}; use hir::{BodyId, HirId}; +use rustc_abi::ExternAbi; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, ResolverAstLowering}; use rustc_span::{Ident, Span}; -use rustc_target::spec::abi; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; @@ -398,7 +398,7 @@ impl<'hir> LoweringContext<'_, 'hir> { safety: hir::Safety::Safe.into(), constness: hir::Constness::NotConst, asyncness: hir::IsAsync::NotAsync, - abi: abi::Abi::Rust, + abi: ExternAbi::Rust, } } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index f727691bf479..f31e2db051d8 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,5 +1,5 @@ +use rustc_errors::DiagArgFromDisplay; use rustc_errors::codes::*; -use rustc_errors::{Diag, DiagArgFromDisplay, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -32,8 +32,6 @@ pub(crate) struct InvalidAbi { pub abi: Symbol, pub command: String, #[subdiagnostic] - pub explain: Option, - #[subdiagnostic] pub suggestion: Option, } @@ -45,19 +43,6 @@ pub(crate) struct TupleStructWithDefault { pub span: Span, } -pub(crate) struct InvalidAbiReason(pub &'static str); - -impl Subdiagnostic for InvalidAbiReason { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { - #[allow(rustc::untranslatable_diagnostic)] - diag.note(self.0); - } -} - #[derive(Subdiagnostic)] #[suggestion( ast_lowering_invalid_abi_suggestion, @@ -212,12 +197,13 @@ pub(crate) struct InvalidRegister<'a> { } #[derive(Diagnostic)] +#[note] #[diag(ast_lowering_invalid_register_class)] -pub(crate) struct InvalidRegisterClass<'a> { +pub(crate) struct InvalidRegisterClass { #[primary_span] pub op_span: Span, pub reg_class: Symbol, - pub error: &'a str, + pub supported_register_classes: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 923fd65dccaf..af53c7ec2157 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -379,16 +379,16 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } - /// Create an `ExprKind::Ret` that is preceded by a call to check contract ensures clause. + /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check + /// a contract ensures clause, if it exists. fn checked_return(&mut self, opt_expr: Option<&'hir hir::Expr<'hir>>) -> hir::ExprKind<'hir> { - let checked_ret = if let Some(Some((span, fresh_ident))) = - self.contract.as_ref().map(|c| c.ensures.as_ref().map(|e| (e.expr.span, e.fresh_ident))) - { - let expr = opt_expr.unwrap_or_else(|| self.expr_unit(span)); - Some(self.inject_ensures_check(expr, span, fresh_ident.0, fresh_ident.2)) - } else { - opt_expr - }; + let checked_ret = + if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures { + let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span)); + Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id)) + } else { + opt_expr + }; hir::ExprKind::Ret(checked_ret) } @@ -1090,7 +1090,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { None }; - let body_id = this.lower_fn_body(decl, |this| { + // FIXME(contracts): Support contracts on closures? + let body_id = this.lower_fn_body(decl, None, |this| { this.coroutine_kind = coroutine_kind; let e = this.lower_expr_mut(body); coroutine_kind = this.coroutine_kind; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7379a3d2cde6..bc2db4154698 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -17,9 +17,9 @@ use thin_vec::ThinVec; use tracing::instrument; use super::errors::{ - InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound, - TupleStructWithDefault, + InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault, }; +use super::stability::{enabled_names, gate_unstable_abi}; use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, @@ -211,36 +211,6 @@ impl<'hir> LoweringContext<'_, 'hir> { .. }) => { self.with_new_scopes(*fn_sig_span, |this| { - assert!(this.contract.is_none()); - if let Some(contract) = contract { - let requires = contract.requires.clone(); - let ensures = contract.ensures.clone(); - let ensures = ensures.map(|ens| { - // FIXME: this needs to be a fresh (or illegal) identifier to prevent - // accidental capture of a parameter or global variable. - let checker_ident: Ident = - Ident::from_str_and_span("__ensures_checker", ens.span); - let (checker_pat, checker_hir_id) = this.pat_ident_binding_mode_mut( - ens.span, - checker_ident, - hir::BindingMode::NONE, - ); - - crate::FnContractLoweringEnsures { - expr: ens, - fresh_ident: (checker_ident, checker_pat, checker_hir_id), - } - }); - - // Note: `with_new_scopes` will reinstall the outer - // item's contract (if any) after its callback finishes. - this.contract.replace(crate::FnContractLoweringInfo { - span, - requires, - ensures, - }); - } - // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body // only cares about the input argument patterns in the function @@ -254,6 +224,7 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind, body.as_deref(), attrs, + contract.as_deref(), ); let itctx = ImplTraitContext::Universal; @@ -803,6 +774,8 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { + // FIXME(contracts): Deny contract here since it won't apply to + // any impl method or callees. let names = self.lower_fn_params_to_names(&sig.decl); let (generics, sig) = self.lower_method_sig( generics, @@ -814,7 +787,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } - AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { + AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), contract, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -823,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_kind, Some(body), attrs, + contract.as_deref(), ); let (generics, sig) = self.lower_method_sig( generics, @@ -931,7 +905,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Const(ty, body) }, ), - AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { + AssocItemKind::Fn(box Fn { sig, generics, body, contract, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -940,6 +914,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_kind, body.as_deref(), attrs, + contract.as_deref(), ); let (generics, sig) = self.lower_method_sig( generics, @@ -1088,72 +1063,89 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_fn_body( &mut self, decl: &FnDecl, + contract: Option<&FnContract>, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::BodyId { self.lower_body(|this| { let params = this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))); - let result = body(this); - - let opt_contract = this.contract.take(); + // Optionally lower the fn contract, which turns: + // // { body } - // ==> - // { contract_requires(PRECOND); { body } } - let Some(contract) = opt_contract else { return (params, result) }; - let result_ref = this.arena.alloc(result); - let lit_unit = |this: &mut LoweringContext<'_, 'hir>| { - this.expr(contract.span, hir::ExprKind::Tup(&[])) - }; - - let precond: hir::Stmt<'hir> = if let Some(req) = contract.requires { - let lowered_req = this.lower_expr_mut(&req); - let precond = this.expr_call_lang_item_fn_mut( - req.span, - hir::LangItem::ContractCheckRequires, - &*arena_vec![this; lowered_req], - ); - this.stmt_expr(req.span, precond) - } else { - let u = lit_unit(this); - this.stmt_expr(contract.span, u) - }; - - let (postcond_checker, result) = if let Some(ens) = contract.ensures { - let crate::FnContractLoweringEnsures { expr: ens, fresh_ident } = ens; - let lowered_ens: hir::Expr<'hir> = this.lower_expr_mut(&ens); - let postcond_checker = this.expr_call_lang_item_fn( - ens.span, - hir::LangItem::ContractBuildCheckEnsures, - &*arena_vec![this; lowered_ens], - ); - let checker_binding_pat = fresh_ident.1; - ( - this.stmt_let_pat( + // + // into: + // + // { contract_requires(PRECOND); let __postcond = |ret_val| POSTCOND; postcond({ body }) } + if let Some(contract) = contract { + let precond = if let Some(req) = &contract.requires { + // Lower the precondition check intrinsic. + let lowered_req = this.lower_expr_mut(&req); + let precond = this.expr_call_lang_item_fn_mut( + req.span, + hir::LangItem::ContractCheckRequires, + &*arena_vec![this; lowered_req], + ); + Some(this.stmt_expr(req.span, precond)) + } else { + None + }; + let (postcond, body) = if let Some(ens) = &contract.ensures { + let ens_span = this.lower_span(ens.span); + // Set up the postcondition `let` statement. + let check_ident: Ident = + Ident::from_str_and_span("__ensures_checker", ens_span); + let (checker_pat, check_hir_id) = this.pat_ident_binding_mode_mut( + ens_span, + check_ident, + hir::BindingMode::NONE, + ); + let lowered_ens = this.lower_expr_mut(&ens); + let postcond_checker = this.expr_call_lang_item_fn( + ens_span, + hir::LangItem::ContractBuildCheckEnsures, + &*arena_vec![this; lowered_ens], + ); + let postcond = this.stmt_let_pat( None, - ens.span, + ens_span, Some(postcond_checker), - this.arena.alloc(checker_binding_pat), + this.arena.alloc(checker_pat), hir::LocalSource::Contract, - ), - this.inject_ensures_check(result_ref, ens.span, fresh_ident.0, fresh_ident.2), - ) - } else { - let u = lit_unit(this); - (this.stmt_expr(contract.span, u), &*result_ref) - }; + ); - let block = this.block_all( - contract.span, - arena_vec![this; precond, postcond_checker], - Some(result), - ); - (params, this.expr_block(block)) + // Install contract_ensures so we will intercept `return` statements, + // then lower the body. + this.contract_ensures = Some((ens_span, check_ident, check_hir_id)); + let body = this.arena.alloc(body(this)); + + // Finally, inject an ensures check on the implicit return of the body. + let body = this.inject_ensures_check(body, ens_span, check_ident, check_hir_id); + (Some(postcond), body) + } else { + let body = &*this.arena.alloc(body(this)); + (None, body) + }; + // Flatten the body into precond, then postcond, then wrapped body. + let wrapped_body = this.block_all( + body.span, + this.arena.alloc_from_iter([precond, postcond].into_iter().flatten()), + Some(body), + ); + (params, this.expr_block(wrapped_body)) + } else { + (params, body(this)) + } }) } - fn lower_fn_body_block(&mut self, decl: &FnDecl, body: &Block) -> hir::BodyId { - self.lower_fn_body(decl, |this| this.lower_block_expr(body)) + fn lower_fn_body_block( + &mut self, + decl: &FnDecl, + body: &Block, + contract: Option<&FnContract>, + ) -> hir::BodyId { + self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) } pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { @@ -1179,12 +1171,13 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind: Option, body: Option<&Block>, attrs: &'hir [hir::Attribute], + contract: Option<&FnContract>, ) -> hir::BodyId { let Some(body) = body else { // Functions without a body are an error, except if this is an intrinsic. For those we // create a fake body so that the entire rest of the compiler doesn't have to deal with // this as a special case. - return self.lower_fn_body(decl, |this| { + return self.lower_fn_body(decl, contract, |this| { if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) { let span = this.lower_span(span); let empty_block = hir::Block { @@ -1209,8 +1202,9 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let Some(coroutine_kind) = coroutine_kind else { // Typical case: not a coroutine. - return self.lower_fn_body_block(decl, body); + return self.lower_fn_body_block(decl, body, contract); }; + // FIXME(contracts): Support contracts on async fn. self.lower_body(|this| { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, @@ -1479,11 +1473,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - pub(super) fn lower_abi(&mut self, abi: StrLit) -> ExternAbi { - rustc_abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| { - self.error_on_invalid_abi(abi, err); + pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi { + let ast::StrLit { symbol_unescaped, span, .. } = abi_str; + let extern_abi = symbol_unescaped.as_str().parse().unwrap_or_else(|_| { + self.error_on_invalid_abi(abi_str); ExternAbi::Rust - }) + }); + let sess = self.tcx.sess; + let features = self.tcx.features(); + gate_unstable_abi(sess, features, span, extern_abi); + extern_abi } pub(super) fn lower_extern(&mut self, ext: Extern) -> ExternAbi { @@ -1494,8 +1493,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn error_on_invalid_abi(&self, abi: StrLit, err: rustc_abi::AbiUnsupported) { - let abi_names = rustc_abi::enabled_names(self.tcx.features(), abi.span) + fn error_on_invalid_abi(&self, abi: StrLit) { + let abi_names = enabled_names(self.tcx.features(), abi.span) .iter() .map(|s| Symbol::intern(s)) .collect::>(); @@ -1503,10 +1502,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(InvalidAbi { abi: abi.symbol_unescaped, span: abi.span, - explain: match err { - rustc_abi::AbiUnsupported::Reason { explain } => Some(InvalidAbiReason(explain)), - _ => None, - }, suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion { span: abi.span, suggestion: format!("\"{suggested_name}\""), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 127b7e3684e9..facc9414b20d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -84,22 +84,10 @@ mod index; mod item; mod pat; mod path; +pub mod stability; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -#[derive(Debug, Clone)] -struct FnContractLoweringInfo<'hir> { - pub span: Span, - pub requires: Option>, - pub ensures: Option>, -} - -#[derive(Debug, Clone)] -struct FnContractLoweringEnsures<'hir> { - expr: ast::ptr::P, - fresh_ident: (Ident, hir::Pat<'hir>, HirId), -} - struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering, @@ -114,7 +102,7 @@ struct LoweringContext<'a, 'hir> { /// Collect items that were created by lowering the current owner. children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>, - contract: Option>, + contract_ensures: Option<(Span, Ident, HirId)>, coroutine_kind: Option, @@ -164,7 +152,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bodies: Vec::new(), attrs: SortedMap::default(), children: Vec::default(), - contract: None, + contract_ensures: None, current_hir_id_owner: hir::CRATE_OWNER_ID, item_local_id_counter: hir::ItemLocalId::ZERO, ident_and_label_to_local_id: Default::default(), @@ -851,7 +839,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; - let old_contract = self.contract.take(); + let old_contract = self.contract_ensures.take(); let catch_scope = self.catch_scope.take(); let loop_scope = self.loop_scope.take(); @@ -859,7 +847,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.catch_scope = catch_scope; self.loop_scope = loop_scope; - self.contract = old_contract; + self.contract_ensures = old_contract; self.is_in_loop_condition = was_in_loop_condition; diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index bb9b2a13185b..e1f3afbcf590 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -4,10 +4,10 @@ use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::Res; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{Ident, Span, kw}; +use rustc_span::{Ident, Span}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -430,78 +430,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind }) } - pub(crate) fn lower_ty_pat(&mut self, pattern: &Pat) -> &'hir hir::TyPat<'hir> { + pub(crate) fn lower_ty_pat(&mut self, pattern: &TyPat) -> &'hir hir::TyPat<'hir> { self.arena.alloc(self.lower_ty_pat_mut(pattern)) } - fn lower_ty_pat_mut(&mut self, mut pattern: &Pat) -> hir::TyPat<'hir> { + fn lower_ty_pat_mut(&mut self, pattern: &TyPat) -> hir::TyPat<'hir> { // loop here to avoid recursion let pat_hir_id = self.lower_node_id(pattern.id); - let node = loop { - match &pattern.kind { - PatKind::Range(e1, e2, Spanned { node: end, .. }) => { - // FIXME(pattern_types): remove this closure and call `lower_const_arg` instead. - // That requires first modifying the AST to have const args here. - let mut lower_expr = |e: &Expr| -> &_ { - if let ExprKind::Path(None, path) = &e.kind - && let Some(res) = self - .resolver - .get_partial_res(e.id) - .and_then(|partial_res| partial_res.full_res()) - { - self.lower_const_path_to_const_arg(path, res, e.id, e.span) - } else { - let node_id = self.next_node_id(); - let def_id = self.create_def( - self.current_hir_id_owner.def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - e.span, - ); - let hir_id = self.lower_node_id(node_id); - let ac = self.arena.alloc(hir::AnonConst { - def_id, - hir_id, - body: self.lower_const_body(pattern.span, Some(e)), - span: self.lower_span(pattern.span), - }); - self.arena.alloc(hir::ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Anon(ac), - }) - } - }; - break hir::TyPatKind::Range( - e1.as_deref().map(|e| lower_expr(e)), - e2.as_deref().map(|e| lower_expr(e)), - self.lower_range_end(end, e2.is_some()), - ); - } - // return inner to be processed in next loop - PatKind::Paren(inner) => pattern = inner, - PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), - PatKind::Err(guar) => break hir::TyPatKind::Err(*guar), - PatKind::Deref(..) - | PatKind::Box(..) - | PatKind::Or(..) - | PatKind::Struct(..) - | PatKind::TupleStruct(..) - | PatKind::Tuple(..) - | PatKind::Ref(..) - | PatKind::Expr(..) - | PatKind::Guard(..) - | PatKind::Slice(_) - | PatKind::Ident(..) - | PatKind::Path(..) - | PatKind::Wild - | PatKind::Never - | PatKind::Rest => { - break hir::TyPatKind::Err( - self.dcx().span_err(pattern.span, "pattern not supported in pattern types"), - ); - } - } + let node = match &pattern.kind { + TyPatKind::Range(e1, e2, Spanned { node: end, .. }) => hir::TyPatKind::Range( + e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)), + e2.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)), + self.lower_range_end(end, e2.is_some()), + ), + TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar), }; hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) } diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs new file mode 100644 index 000000000000..a2004bbb39f0 --- /dev/null +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -0,0 +1,142 @@ +use std::fmt; + +use rustc_abi::ExternAbi; +use rustc_feature::Features; +use rustc_session::Session; +use rustc_session::parse::feature_err; +use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; + +pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> { + ExternAbi::ALL_VARIANTS + .into_iter() + .filter(|abi| extern_abi_enabled(features, span, **abi).is_ok()) + .map(|abi| abi.as_str()) + .collect() +} + +pub(crate) fn extern_abi_enabled( + features: &rustc_feature::Features, + span: Span, + abi: ExternAbi, +) -> Result<(), UnstableAbi> { + extern_abi_stability(abi).or_else(|unstable @ UnstableAbi { feature, .. }| { + if features.enabled(feature) || span.allows_unstable(feature) { + Ok(()) + } else { + Err(unstable) + } + }) +} + +#[allow(rustc::untranslatable_diagnostic)] +pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) { + match extern_abi_enabled(features, span, abi) { + Ok(_) => (), + Err(unstable_abi) => { + let explain = unstable_abi.to_string(); + feature_err(sess, unstable_abi.feature, span, explain).emit(); + } + } +} + +pub struct UnstableAbi { + abi: ExternAbi, + feature: Symbol, + explain: GateReason, +} + +enum GateReason { + Experimental, + ImplDetail, +} + +impl fmt::Display for UnstableAbi { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { abi, .. } = self; + match self.explain { + GateReason::Experimental => { + write!(f, "the extern {abi} ABI is experimental and subject to change") + } + GateReason::ImplDetail => { + write!(f, "the extern {abi} ABI is an implementation detail and perma-unstable") + } + } + } +} + +pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { + match abi { + // stable ABIs + ExternAbi::Rust + | ExternAbi::C { .. } + | ExternAbi::Cdecl { .. } + | ExternAbi::Stdcall { .. } + | ExternAbi::Fastcall { .. } + | ExternAbi::Thiscall { .. } + | ExternAbi::Aapcs { .. } + | ExternAbi::Win64 { .. } + | ExternAbi::SysV64 { .. } + | ExternAbi::System { .. } + | ExternAbi::EfiApi => Ok(()), + // implementation details + ExternAbi::RustIntrinsic => { + Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail }) + } + ExternAbi::Unadjusted => { + Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail }) + } + // experimental + ExternAbi::Vectorcall { .. } => Err(UnstableAbi { + abi, + feature: sym::abi_vectorcall, + explain: GateReason::Experimental, + }), + ExternAbi::RustCall => Err(UnstableAbi { + abi, + feature: sym::unboxed_closures, + explain: GateReason::Experimental, + }), + ExternAbi::RustCold => { + Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental }) + } + ExternAbi::GpuKernel => Err(UnstableAbi { + abi, + feature: sym::abi_gpu_kernel, + explain: GateReason::Experimental, + }), + ExternAbi::PtxKernel => { + Err(UnstableAbi { abi, feature: sym::abi_ptx, explain: GateReason::Experimental }) + } + ExternAbi::Msp430Interrupt => Err(UnstableAbi { + abi, + feature: sym::abi_msp430_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::X86Interrupt => Err(UnstableAbi { + abi, + feature: sym::abi_x86_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::AvrInterrupt | ExternAbi::AvrNonBlockingInterrupt => Err(UnstableAbi { + abi, + feature: sym::abi_avr_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS => Err(UnstableAbi { + abi, + feature: sym::abi_riscv_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::CCmseNonSecureCall => Err(UnstableAbi { + abi, + feature: sym::abi_c_cmse_nonsecure_call, + explain: GateReason::Experimental, + }), + ExternAbi::CCmseNonSecureEntry => Err(UnstableAbi { + abi, + feature: sym::cmse_nonsecure_entry, + explain: GateReason::Experimental, + }), + } +} diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 19c379c8599a..e4c227532085 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_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0049c5b4823c..f9f4035cb22f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -20,6 +20,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use itertools::{Either, Itertools}; +use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list}; use rustc_ast::*; @@ -35,7 +36,6 @@ use rustc_session::lint::builtin::{ }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::{Ident, Span, kw, sym}; -use rustc_target::spec::abi; use thin_vec::thin_vec; use crate::errors::{self, TildeConstReason}; @@ -723,7 +723,7 @@ impl<'a> AstValidator<'a> { MISSING_ABI, id, span, - BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK), + BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK), ) } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 13294efdaf6f..e5d8013058f6 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,9 +1,9 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{NodeId, PatKind, attr, token}; -use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features, GateIssue}; +use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features}; use rustc_session::Session; -use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; +use rustc_session::parse::{feature_err, feature_warn}; use rustc_span::source_map::Spanned; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; @@ -72,35 +72,6 @@ struct PostExpansionVisitor<'a> { } impl<'a> PostExpansionVisitor<'a> { - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn check_abi(&self, abi: ast::StrLit) { - let ast::StrLit { symbol_unescaped, span, .. } = abi; - - match rustc_abi::is_enabled(self.features, span, symbol_unescaped.as_str()) { - Ok(()) => (), - Err(rustc_abi::AbiDisabled::Unstable { feature, explain }) => { - feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit(); - } - Err(rustc_abi::AbiDisabled::Unrecognized) => { - if self.sess.opts.pretty.is_none_or(|ppm| ppm.needs_hir()) { - self.sess.dcx().span_delayed_bug( - span, - format!( - "unrecognized ABI not caught in lowering: {}", - symbol_unescaped.as_str() - ), - ); - } - } - } - } - - fn check_extern(&self, ext: ast::Extern) { - if let ast::Extern::Explicit(abi, _) = ext { - self.check_abi(abi); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) { struct ImplTraitVisitor<'a> { @@ -223,12 +194,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_item(&mut self, i: &'a ast::Item) { match &i.kind { - ast::ItemKind::ForeignMod(foreign_module) => { - if let Some(abi) = foreign_module.abi { - self.check_abi(abi); - } + ast::ItemKind::ForeignMod(_foreign_module) => { + // handled during lowering } - ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => { for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { @@ -315,7 +283,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match &ty.kind { ast::TyKind::BareFn(bare_fn_ty) => { // Function pointers cannot be `const` - self.check_extern(bare_fn_ty.ext); self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); } ast::TyKind::Never => { @@ -418,9 +385,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { - if let Some(header) = fn_kind.header() { + if let Some(_header) = fn_kind.header() { // Stability of const fn methods are covered in `visit_assoc_item` below. - self.check_extern(header.ext); } if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index eeec24e5ea4e..0bf5de3ef898 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1148,6 +1148,28 @@ impl<'a> State<'a> { } } + pub fn print_ty_pat(&mut self, pat: &ast::TyPat) { + match &pat.kind { + rustc_ast::TyPatKind::Range(start, end, include_end) => { + if let Some(start) = start { + self.print_expr_anon_const(start, &[]); + } + self.word(".."); + if let Some(end) = end { + if let RangeEnd::Included(_) = include_end.node { + self.word("="); + } + self.print_expr_anon_const(end, &[]); + } + } + rustc_ast::TyPatKind::Err(_) => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose(); + } + } + } + pub fn print_type(&mut self, ty: &ast::Ty) { self.maybe_print_comment(ty.span.lo()); self.ibox(0); @@ -1252,7 +1274,7 @@ impl<'a> State<'a> { ast::TyKind::Pat(ty, pat) => { self.print_type(ty); self.word(" is "); - self.print_pat(pat); + self.print_ty_pat(pat); } } self.end(); diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 30b0a3585802..aa968a1e40f3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -9,8 +9,8 @@ use rustc_infer::infer::{ }; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::query::{ - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpDeeplyNormalizeGoal, + CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ @@ -109,6 +109,14 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable> + 'tcx> ToUnivers } } +impl<'tcx, T: Copy + fmt::Display + TypeFoldable> + 'tcx> ToUniverseInfo<'tcx> + for CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T> +{ + fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + UniverseInfo::TypeOp(Rc::new(DeeplyNormalizeQuery { canonical_query: self, base_universe })) + } +} + impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpAscribeUserTypeGoal<'tcx> { fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { UniverseInfo::TypeOp(Rc::new(AscribeUserTypeQuery { canonical_query: self, base_universe })) @@ -285,6 +293,53 @@ where } } +struct DeeplyNormalizeQuery<'tcx, T> { + canonical_query: CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>, + base_universe: ty::UniverseIndex, +} + +impl<'tcx, T> TypeOpInfo<'tcx> for DeeplyNormalizeQuery<'tcx, T> +where + T: Copy + fmt::Display + TypeFoldable> + 'tcx, +{ + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> { + tcx.dcx().create_err(HigherRankedLifetimeError { + cause: Some(HigherRankedErrorCause::CouldNotNormalize { + value: self.canonical_query.canonical.value.value.value.to_string(), + }), + span, + }) + } + + fn base_universe(&self) -> ty::UniverseIndex { + self.base_universe + } + + fn nice_error<'infcx>( + &self, + mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>, + cause: ObligationCause<'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, + ) -> Option> { + let (infcx, key, _) = + mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); + let ocx = ObligationCtxt::new(&infcx); + + let (param_env, value) = key.into_parts(); + let _ = ocx.deeply_normalize(&cause, param_env, value.value); + + let diag = try_extract_error_from_fulfill_cx( + &ocx, + mbcx.mir_def_id(), + placeholder_region, + error_region, + )? + .with_dcx(mbcx.dcx()); + Some(diag) + } +} + struct AscribeUserTypeQuery<'tcx> { canonical_query: CanonicalTypeOpAscribeUserTypeGoal<'tcx>, base_universe: ty::UniverseIndex, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 860c7c267ea9..df83ac985c65 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -570,7 +570,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // If we didn't find an overloaded deref or index, then assume it's a // built in deref and check the type of the base. let base_ty = deref_base.ty(self.body, tcx).ty; - if base_ty.is_unsafe_ptr() { + if base_ty.is_raw_ptr() { BorrowedContentSource::DerefRawPointer } else if base_ty.is_mutable_ptr() { BorrowedContentSource::DerefMutableRef diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index bffd9f383343..b3fa786a5177 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -149,6 +149,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.normalize_with_category(value, location, ConstraintCategory::Boring) } + pub(super) fn deeply_normalize(&mut self, value: T, location: impl NormalizeLocation) -> T + where + T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, + { + let result: Result<_, ErrorGuaranteed> = self.fully_perform_op( + location.to_locations(), + ConstraintCategory::Boring, + self.infcx.param_env.and(type_op::normalize::DeeplyNormalize { value }), + ); + result.unwrap_or(value) + } + #[instrument(skip(self), level = "debug")] pub(super) fn normalize_with_category( &mut self, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 4b7f53213886..3b48ca305c45 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -4,15 +4,12 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; +use rustc_infer::traits::query::type_op::DeeplyNormalize; use rustc_middle::bug; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; -use rustc_middle::traits::ObligationCause; -use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::Span; -use rustc_trait_selection::traits::ScrubbedTraitError; -use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument}; @@ -270,20 +267,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ConstraintCategory<'tcx>, )>, ) -> Ty<'tcx> { - let result = CustomTypeOp::new( - |ocx| { - ocx.deeply_normalize( - &ObligationCause::dummy_with_span(self.span), - self.param_env, - ty, - ) - .map_err(|_: Vec>| NoSolution) - }, - "normalize type outlives obligation", - ) - .fully_perform(self.infcx, self.span); - - match result { + match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span) + { Ok(TypeOpOutput { output: ty, constraints, .. }) => { if let Some(QueryRegionConstraints { outlives }) = constraints { next_outlives_predicates.extend(outlives.iter().copied()); diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index edf612f4e97a..efbae1e15353 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -5,14 +5,11 @@ use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::{InferCtxt, outlives}; -use rustc_infer::traits::ScrubbedTraitError; +use rustc_infer::traits::query::type_op::DeeplyNormalize; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::solve::NoSolution; -use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use tracing::{debug, instrument}; use type_op::TypeOpOutput; @@ -267,7 +264,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = param_env - .and(type_op::normalize::Normalize { value: ty }) + .and(DeeplyNormalize { value: ty }) .fully_perform(self.infcx, span) .unwrap_or_else(|guar| TypeOpOutput { output: Ty::new_error(self.infcx.tcx, guar), @@ -303,9 +300,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // Add implied bounds from impl header. if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) { for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) { - let result: Result<_, ErrorGuaranteed> = param_env - .and(type_op::normalize::Normalize { value: ty }) - .fully_perform(self.infcx, span); + let result: Result<_, ErrorGuaranteed> = + param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, span); let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else { continue; }; @@ -360,18 +356,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { output: normalized_outlives, constraints: constraints_normalize, error_info: _, - }) = CustomTypeOp::new( - |ocx| { - ocx.deeply_normalize( - &ObligationCause::dummy_with_span(span), - self.param_env, - outlives, - ) - .map_err(|_: Vec>| NoSolution) - }, - "normalize type outlives obligation", - ) - .fully_perform(self.infcx, span) + }) = self + .param_env + .and(DeeplyNormalize { value: outlives }) + .fully_perform(self.infcx, span) else { self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}")); return; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 26a5d438edb9..93081919ec79 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1116,7 +1116,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring, ); - let sig = self.normalize(unnormalized_sig, term_location); + let sig = self.deeply_normalize(unnormalized_sig, term_location); // HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))` // with built-in `Fn` implementations, since the impl may not be // well-formed itself. diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs index 85a30f7bdc9b..6a24af361fe7 100644 --- a/compiler/rustc_builtin_macros/src/contracts.rs +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -1,11 +1,9 @@ -#![allow(unused_imports, unused_variables)] - use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_errors::ErrorGuaranteed; use rustc_expand::base::{AttrProcMacro, ExtCtxt}; use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::symbol::{Ident, Symbol, kw}; pub(crate) struct ExpandRequires; @@ -121,23 +119,19 @@ fn expand_contract_clause( } } - // Record the span as a contract attribute expansion. - // This is used later to stop users from using the extended syntax directly - // which is gated via `contracts_internals`. - ecx.psess().contract_attribute_spans.push(attr_span); - Ok(new_tts) } fn expand_requires_tts( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_contract_clause(_ecx, attr_span, annotated, |new_tts| { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractRequires, attr_span)), + token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Token( @@ -155,14 +149,15 @@ fn expand_requires_tts( } fn expand_ensures_tts( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_contract_clause(_ecx, attr_span, annotated, |new_tts| { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, attr_span)), + token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Delimited( diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 82417a86dd9e..5aed9f76f144 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -3,11 +3,11 @@ use ast::ptr::P; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::visit::BoundKind; use rustc_ast::{ - self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem, + self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem, TraitBoundModifiers, VariantData, WherePredicate, }; -use rustc_attr_parsing as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; +use rustc_errors::E0802; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; @@ -32,15 +32,6 @@ pub(crate) fn expand_deriving_coerce_pointee( let (name_ident, generics) = if let Annotatable::Item(aitem) = item && let ItemKind::Struct(struct_data, g) = &aitem.kind { - let is_transparent = aitem.attrs.iter().any(|attr| { - attr::find_repr_attrs(cx.sess, attr) - .into_iter() - .any(|r| matches!(r, attr::ReprTransparent)) - }); - if !is_transparent { - cx.dcx().emit_err(RequireTransparent { span }); - return; - } if !matches!( struct_data, VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) @@ -88,8 +79,7 @@ pub(crate) fn expand_deriving_coerce_pointee( } else { let mut pointees = type_params .iter() - .filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span))) - .fuse(); + .filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span))); match (pointees.next(), pointees.next()) { (Some((idx, _span)), None) => idx, (None, _) => { @@ -110,6 +100,52 @@ pub(crate) fn expand_deriving_coerce_pointee( // Declare helper function that adds implementation blocks. // FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),]; + // # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`. + { + let trait_path = + cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]); + let trait_ref = cx.trait_ref(trait_path); + push(Annotatable::Item( + cx.item( + span, + Ident::empty(), + attrs.clone(), + ast::ItemKind::Impl(Box::new(ast::Impl { + safety: ast::Safety::Default, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Final, + constness: ast::Const::No, + generics: Generics { + params: generics + .params + .iter() + .map(|p| match &p.kind { + GenericParamKind::Lifetime => { + cx.lifetime_param(p.span(), p.ident, p.bounds.clone()) + } + GenericParamKind::Type { default: _ } => { + cx.typaram(p.span(), p.ident, p.bounds.clone(), None) + } + GenericParamKind::Const { ty, kw_span: _, default: _ } => cx + .const_param( + p.span(), + p.ident, + p.bounds.clone(), + ty.clone(), + None, + ), + }) + .collect(), + where_clause: generics.where_clause.clone(), + span: generics.span, + }, + of_trait: Some(trait_ref), + self_ty: self_type.clone(), + items: ThinVec::new(), + })), + ), + )); + } let mut add_impl_block = |generics, trait_symbol, trait_args| { let mut parts = path!(span, core::ops); parts.push(Ident::new(trait_symbol, span)); @@ -430,35 +466,35 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_transparent)] +#[diag(builtin_macros_coerce_pointee_requires_transparent, code = E0802)] struct RequireTransparent { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_field)] +#[diag(builtin_macros_coerce_pointee_requires_one_field, code = E0802)] struct RequireOneField { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_generic)] +#[diag(builtin_macros_coerce_pointee_requires_one_generic, code = E0802)] struct RequireOneGeneric { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_pointee)] +#[diag(builtin_macros_coerce_pointee_requires_one_pointee, code = E0802)] struct RequireOnePointee { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_too_many_pointees)] +#[diag(builtin_macros_coerce_pointee_too_many_pointees, code = E0802)] struct TooManyPointees { #[primary_span] one: Span, @@ -467,7 +503,7 @@ struct TooManyPointees { } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_maybe_sized)] +#[diag(builtin_macros_coerce_pointee_requires_maybe_sized, code = E0802)] struct RequiresMaybeSized { #[primary_span] span: Span, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index a600a9f316a7..a55c7e962d09 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{Pat, Ty, ast}; +use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_parse::exp; @@ -21,12 +21,24 @@ pub(crate) fn expand<'cx>( ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat)))) } -fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P, P)> { +fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P, P)> { let mut parser = cx.new_parser_from_tts(stream); let ty = parser.parse_ty()?; parser.expect_keyword(exp!(Is))?; - let pat = parser.parse_pat_no_top_alt(None, None)?; + let pat = parser.parse_pat_no_top_alt(None, None)?.into_inner(); + + let kind = match pat.kind { + ast::PatKind::Range(start, end, include_end) => TyPatKind::Range( + start.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), + end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), + include_end, + ), + ast::PatKind::Err(guar) => TyPatKind::Err(guar), + _ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")), + }; + + let pat = P(TyPat { id: pat.id, kind, span: pat.span, tokens: pat.tokens }); Ok((ty, pat)) } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index a0a381638c06..79820232496a 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -57,6 +57,9 @@ impl LegacyReceiver for Box {} #[lang = "copy"] pub trait Copy {} +#[lang = "bikeshed_guaranteed_no_drop"] +pub trait BikeshedGuaranteedNoDrop {} + impl Copy for bool {} impl Copy for u8 {} impl Copy for u16 {} diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a2b9e5712e50..125a9201831c 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -900,8 +900,8 @@ fn codegen_stmt<'tcx>( }; let data = codegen_operand(fx, data); let meta = codegen_operand(fx, meta); - assert!(data.layout().ty.is_unsafe_ptr()); - assert!(layout.ty.is_unsafe_ptr()); + assert!(data.layout().ty.is_raw_ptr()); + assert!(layout.ty.is_raw_ptr()); let ptr_val = if meta.layout().is_zst() { data.cast_pointer_to(layout) } else { diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index a460023b59cb..9d9e0462a9b7 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -48,7 +48,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( ) -> (Pointer, Value) { let (ptr, vtable) = 'block: { if let BackendRepr::Scalar(_) = arg.layout().backend_repr { - while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { + while !arg.layout().ty.is_raw_ptr() && !arg.layout().ty.is_ref() { let (idx, _) = arg .layout() .non_1zst_field(fx) diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 5a4ee0a198ce..2ff1d757fd4e 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -54,6 +54,9 @@ impl LegacyReceiver for Box {} #[lang = "copy"] pub trait Copy {} +#[lang = "bikeshed_guaranteed_no_drop"] +pub trait BikeshedGuaranteedNoDrop {} + impl Copy for bool {} impl Copy for u8 {} impl Copy for u16 {} diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 4a1db8d662a9..f3552d9b12fc 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -400,7 +400,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { conv: Conv::C, can_unwind: false, }; - fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }).unwrap(); + fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }); let ret_indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 685b2f37c9c3..13846c8ab4b9 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -664,7 +664,7 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } impl llvm::CallConv { - pub fn from_conv(conv: Conv, arch: &str) -> Self { + pub(crate) fn from_conv(conv: Conv, arch: &str) -> Self { match conv { Conv::C | Conv::Rust diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 149ded28356b..66723cbf8820 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -81,13 +81,13 @@ pub(crate) unsafe fn codegen( llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); - llvm::LLVMSetInitializer(ll_g, llval); + llvm::set_initializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); - llvm::LLVMSetInitializer(ll_g, llval); + llvm::set_initializer(ll_g, llval); } if tcx.sess.opts.debuginfo != DebugInfo::None { diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 33a956e552fb..93553f3f3648 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -11,7 +11,7 @@ use rustc_codegen_ssa::back::archive::{ use rustc_session::Session; use crate::llvm::archive_ro::{ArchiveRO, Child}; -use crate::llvm::{self, ArchiveKind}; +use crate::llvm::{self, ArchiveKind, last_error}; /// Helper for adding many files to an archive. #[must_use = "must call build() to finish building the archive"] @@ -169,6 +169,8 @@ impl<'a> LlvmArchiveBuilder<'a> { .unwrap_or_else(|kind| self.sess.dcx().emit_fatal(UnknownArchiveKind { kind })); let mut additions = mem::take(&mut self.additions); + // Values in the `members` list below will contain pointers to the strings allocated here. + // So they need to get dropped after all elements of `members` get freed. let mut strings = Vec::new(); let mut members = Vec::new(); @@ -229,12 +231,7 @@ impl<'a> LlvmArchiveBuilder<'a> { self.sess.target.arch == "arm64ec", ); let ret = if r.into_result().is_err() { - let err = llvm::LLVMRustGetLastError(); - let msg = if err.is_null() { - "failed to write archive".into() - } else { - String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()) - }; + let msg = last_error().unwrap_or_else(|| "failed to write archive".into()); Err(io::Error::new(io::ErrorKind::Other, msg)) } else { Ok(!members.is_empty()) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 8bad437eeb71..7262fce49119 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -642,7 +642,7 @@ unsafe impl Send for ModuleBuffer {} unsafe impl Sync for ModuleBuffer {} impl ModuleBuffer { - pub fn new(m: &llvm::Module) -> ModuleBuffer { + pub(crate) fn new(m: &llvm::Module) -> ModuleBuffer { ModuleBuffer(unsafe { llvm::LLVMRustModuleBufferCreate(m) }) } } @@ -684,7 +684,7 @@ unsafe impl Send for ThinBuffer {} unsafe impl Sync for ThinBuffer {} impl ThinBuffer { - pub fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer { + pub(crate) fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer { unsafe { let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary); ThinBuffer(buffer) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 4cbd49aa44d4..f075f332462f 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -17,7 +17,7 @@ pub struct OwnedTargetMachine { } impl OwnedTargetMachine { - pub fn new( + pub(crate) fn new( triple: &CStr, cpu: &CStr, features: &CStr, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index ae4c4d5876e2..58933a77e53d 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -40,7 +40,7 @@ use crate::errors::{ WithLlvmError, WriteBytecode, }; use crate::llvm::diagnostic::OptimizationDiagnosticKind::*; -use crate::llvm::{self, DiagnosticInfo, PassManager}; +use crate::llvm::{self, DiagnosticInfo}; use crate::type_::Type; use crate::{LlvmCodegenBackend, ModuleLlvm, base, common, llvm_util}; @@ -54,7 +54,7 @@ pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> Fatal fn write_output_file<'ll>( dcx: DiagCtxtHandle<'_>, target: &'ll llvm::TargetMachine, - pm: &llvm::PassManager<'ll>, + no_builtins: bool, m: &'ll llvm::Module, output: &Path, dwo_output: Option<&Path>, @@ -63,16 +63,19 @@ fn write_output_file<'ll>( verify_llvm_ir: bool, ) -> Result<(), FatalError> { debug!("write_output_file output={:?} dwo_output={:?}", output, dwo_output); - unsafe { - let output_c = path_to_c_string(output); - let dwo_output_c; - let dwo_output_ptr = if let Some(dwo_output) = dwo_output { - dwo_output_c = path_to_c_string(dwo_output); - dwo_output_c.as_ptr() - } else { - std::ptr::null() - }; - let result = llvm::LLVMRustWriteOutputFile( + let output_c = path_to_c_string(output); + let dwo_output_c; + let dwo_output_ptr = if let Some(dwo_output) = dwo_output { + dwo_output_c = path_to_c_string(dwo_output); + dwo_output_c.as_ptr() + } else { + std::ptr::null() + }; + let result = unsafe { + let pm = llvm::LLVMCreatePassManager(); + llvm::LLVMAddAnalysisPasses(target, pm); + llvm::LLVMRustAddLibraryInfo(pm, m, no_builtins); + llvm::LLVMRustWriteOutputFile( target, pm, m, @@ -80,22 +83,22 @@ fn write_output_file<'ll>( dwo_output_ptr, file_type, verify_llvm_ir, - ); + ) + }; - // Record artifact sizes for self-profiling - if result == llvm::LLVMRustResult::Success { - let artifact_kind = match file_type { - llvm::FileType::ObjectFile => "object_file", - llvm::FileType::AssemblyFile => "assembly_file", - }; - record_artifact_size(self_profiler_ref, artifact_kind, output); - if let Some(dwo_file) = dwo_output { - record_artifact_size(self_profiler_ref, "dwo_file", dwo_file); - } + // Record artifact sizes for self-profiling + if result == llvm::LLVMRustResult::Success { + let artifact_kind = match file_type { + llvm::FileType::ObjectFile => "object_file", + llvm::FileType::AssemblyFile => "assembly_file", + }; + record_artifact_size(self_profiler_ref, artifact_kind, output); + if let Some(dwo_file) = dwo_output { + record_artifact_size(self_profiler_ref, "dwo_file", dwo_file); } - - result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } + + result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } pub(crate) fn create_informational_target_machine( @@ -325,13 +328,17 @@ pub(crate) fn save_temp_bitcode( if !cgcx.save_temps { return; } + let ext = format!("{name}.bc"); + let cgu = Some(&module.name[..]); + let path = cgcx.output_filenames.temp_path_ext(&ext, cgu); + write_bitcode_to_file(module, &path) +} + +fn write_bitcode_to_file(module: &ModuleCodegen, path: &Path) { unsafe { - let ext = format!("{name}.bc"); - let cgu = Some(&module.name[..]); - let path = cgcx.output_filenames.temp_path_ext(&ext, cgu); - let cstr = path_to_c_string(&path); + let path = path_to_c_string(&path); let llmod = module.module_llvm.llmod(); - llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); + llvm::LLVMWriteBitcodeToFile(llmod, path.as_ptr()); } } @@ -676,7 +683,6 @@ pub(crate) unsafe fn optimize( ) -> Result<(), FatalError> { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name); - let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, module, CodegenDiagnosticsStage::Opt); @@ -685,8 +691,7 @@ pub(crate) unsafe fn optimize( if config.emit_no_opt_bc { let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); - let out = path_to_c_string(&out); - unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) }; + write_bitcode_to_file(module, &out) } // FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts @@ -755,31 +760,6 @@ pub(crate) unsafe fn codegen( create_msvc_imps(cgcx, llcx, llmod); } - // A codegen-specific pass manager is used to generate object - // files for an LLVM module. - // - // Apparently each of these pass managers is a one-shot kind of - // thing, so we create a new one for each type of output. The - // pass manager passed to the closure should be ensured to not - // escape the closure itself, and the manager should only be - // used once. - unsafe fn with_codegen<'ll, F, R>( - tm: &'ll llvm::TargetMachine, - llmod: &'ll llvm::Module, - no_builtins: bool, - f: F, - ) -> R - where - F: FnOnce(&'ll mut PassManager<'ll>) -> R, - { - unsafe { - let cpm = llvm::LLVMCreatePassManager(); - llvm::LLVMAddAnalysisPasses(tm, cpm); - llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); - f(cpm) - } - } - // Note that if object files are just LLVM bitcode we write bitcode, // copy it to the .o file, and delete the bitcode if it wasn't // otherwise requested. @@ -898,21 +878,17 @@ pub(crate) unsafe fn codegen( } else { llmod }; - unsafe { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &path, - None, - llvm::FileType::AssemblyFile, - &cgcx.prof, - config.verify_llvm_ir, - ) - })?; - } + write_output_file( + dcx, + tm, + config.no_builtins, + llmod, + &path, + None, + llvm::FileType::AssemblyFile, + &cgcx.prof, + config.verify_llvm_ir, + )?; } match config.emit_obj { @@ -936,21 +912,17 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - unsafe { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &obj_out, - dwo_out, - llvm::FileType::ObjectFile, - &cgcx.prof, - config.verify_llvm_ir, - ) - })?; - } + write_output_file( + dcx, + tm, + config.no_builtins, + llmod, + &obj_out, + dwo_out, + llvm::FileType::ObjectFile, + &cgcx.prof, + config.verify_llvm_ir, + )?; } EmitObj::Bitcode => { @@ -1077,24 +1049,18 @@ unsafe fn embed_bitcode( { // We don't need custom section flags, create LLVM globals. let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.module".as_ptr(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); + let llglobal = + llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); + llvm::set_initializer(llglobal, llconst); llvm::set_section(llglobal, bitcode_section_name(cgcx)); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.cmdline".as_ptr(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); + let llglobal = + llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); + llvm::set_initializer(llglobal, llconst); let section = if cgcx.target_is_like_osx { c"__LLVM,__cmdline" } else if cgcx.target_is_like_aix { @@ -1134,31 +1100,29 @@ fn create_msvc_imps( // underscores added in front). let prefix = if cgcx.target_arch == "x86" { "\x01__imp__" } else { "\x01__imp_" }; - unsafe { - let ptr_ty = Type::ptr_llcx(llcx); - let globals = base::iter_globals(llmod) - .filter(|&val| { - llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage - && llvm::LLVMIsDeclaration(val) == 0 - }) - .filter_map(|val| { - // Exclude some symbols that we know are not Rust symbols. - let name = llvm::get_value_name(val); - if ignored(name) { None } else { Some((val, name)) } - }) - .map(move |(val, name)| { - let mut imp_name = prefix.as_bytes().to_vec(); - imp_name.extend(name); - let imp_name = CString::new(imp_name).unwrap(); - (imp_name, val) - }) - .collect::>(); + let ptr_ty = Type::ptr_llcx(llcx); + let globals = base::iter_globals(llmod) + .filter(|&val| { + llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage && !llvm::is_declaration(val) + }) + .filter_map(|val| { + // Exclude some symbols that we know are not Rust symbols. + let name = llvm::get_value_name(val); + if ignored(name) { None } else { Some((val, name)) } + }) + .map(move |(val, name)| { + let mut imp_name = prefix.as_bytes().to_vec(); + imp_name.extend(name); + let imp_name = CString::new(imp_name).unwrap(); + (imp_name, val) + }) + .collect::>(); - for (imp_name, val) in globals { - let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr()); - llvm::LLVMSetInitializer(imp, val); - llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage); - } + for (imp_name, val) in globals { + let imp = llvm::add_global(llmod, ptr_ty, &imp_name); + + llvm::set_initializer(imp, val); + llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage); } // Use this function to exclude certain symbols from `__imp` generation. diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 8c94a46ebf30..78b3a7f85417 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -219,8 +219,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| { bug!("symbol `{}` is already defined", sym); }); + llvm::set_initializer(g, sc); unsafe { - llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index c6855dd42e53..4a5491ec7a18 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -191,7 +191,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( }) }); llvm::set_linkage(g2, llvm::Linkage::InternalLinkage); - unsafe { llvm::LLVMSetInitializer(g2, g1) }; + llvm::set_initializer(g2, g1); g2 } else if cx.tcx.sess.target.arch == "x86" && common::is_mingw_gnu_toolchain(&cx.tcx.sess.target) @@ -235,7 +235,7 @@ impl<'ll> CodegenCx<'ll, '_> { } _ => self.define_private_global(self.val_ty(cv)), }; - unsafe { llvm::LLVMSetInitializer(gv, cv) }; + llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); gv @@ -458,7 +458,7 @@ impl<'ll> CodegenCx<'ll, '_> { new_g }; set_global_alignment(self, g, alloc.align); - llvm::LLVMSetInitializer(g, v); + llvm::set_initializer(g, v); if self.should_assume_dso_local(g, true) { llvm::LLVMRustSetDSOLocal(g, true); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ba4fd75fb941..7fe527a4c07d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -616,12 +616,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) { let array = self.const_array(self.type_ptr(), values); - unsafe { - let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); - llvm::LLVMSetInitializer(g, array); - llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); - llvm::set_section(g, c"llvm.metadata"); - } + let g = llvm::add_global(self.llmod, self.val_ty(array), name); + llvm::set_initializer(g, array); + llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); + llvm::set_section(g, c"llvm.metadata"); } } impl<'ll> SimpleCx<'ll> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 2c9f1cda13a8..54c5d445f66b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -73,7 +73,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( .define_global(section_var_name, llvm_type) .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); llvm::set_section(section_var, c".debug_gdb_scripts"); - llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); + llvm::set_initializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index bdc83267cca9..cebceef1b93f 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -235,7 +235,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// name. pub(crate) fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { self.get_declared_value(name).and_then(|val| { - let declaration = unsafe { llvm::LLVMIsDeclaration(val) != 0 }; + let declaration = llvm::is_declaration(val); if !declaration { Some(val) } else { None } }) } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 3200c94d9770..8b9768859045 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -824,7 +824,7 @@ fn codegen_msvc_try<'ll>( if bx.cx.tcx.sess.target.supports_comdat() { llvm::SetUniqueComdat(bx.llmod, tydesc); } - unsafe { llvm::LLVMSetInitializer(tydesc, type_info) }; + llvm::set_initializer(tydesc, type_info); // The flag value of 8 indicates that we are catching the exception by // reference instead of by value. We can't use catch by value because diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index f0d04b2b6447..bcb1cc72b560 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -30,7 +30,7 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; -pub use llvm_util::target_features_cfg; +pub(crate) use llvm_util::target_features_cfg; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4d6a76b23ea1..441d144ce50d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2359,7 +2359,7 @@ unsafe extern "C" { ); pub fn LLVMRustWriteOutputFile<'a>( T: &'a TargetMachine, - PM: &PassManager<'a>, + PM: *mut PassManager<'a>, M: &'a Module, Output: *const c_char, DwoOutput: *const c_char, diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 707aeba22ccf..7becba4ccd4c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -241,6 +241,10 @@ pub fn set_linkage(llglobal: &Value, linkage: Linkage) { } } +pub fn is_declaration(llglobal: &Value) -> bool { + unsafe { LLVMIsDeclaration(llglobal) == ffi::True } +} + pub fn get_visibility(llglobal: &Value) -> Visibility { unsafe { LLVMGetVisibility(llglobal) }.to_rust() } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53611c746a72..b4b5d6a5b194 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -271,6 +271,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("fullfp16")), // Filter out features that are not supported by the current LLVM version ("aarch64", "fpmr") if get_version().0 != 18 => None, + ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single // feature called `fast-unaligned-access`. In LLVM 19, it was split back out. ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => { @@ -303,7 +304,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Vec { +pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec { let mut features: FxHashSet = Default::default(); // Add base features for the target. diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 34cede54aaf1..d61ce4175627 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -237,11 +237,11 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl Type { /// Creates an integer type with the given number of bits, e.g., i24 - pub fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type { + pub(crate) fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type { unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) } } - pub fn ptr_llcx(llcx: &llvm::Context) -> &Type { + pub(crate) fn ptr_llcx(llcx: &llvm::Context) -> &Type { unsafe { llvm::LLVMPointerTypeInContext(llcx, AddressSpace::DATA.0) } } } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 2c38fb5658f2..1d8f61806f56 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,5 +1,6 @@ use std::str::FromStr; +use rustc_abi::ExternAbi; use rustc_ast::attr::list_contains_name; use rustc_ast::expand::autodiff_attrs::{ AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, @@ -23,7 +24,7 @@ use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_session::{Session, lint}; use rustc_span::{Ident, Span, sym}; -use rustc_target::spec::{SanitizerSet, abi}; +use rustc_target::spec::SanitizerSet; use tracing::debug; use crate::errors; @@ -219,7 +220,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if !is_closure && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().abi() != abi::Abi::Rust + && fn_sig.skip_binder().abi() != ExternAbi::Rust { struct_span_code_err!( tcx.dcx(), diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 051753715913..53953b089c61 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -367,9 +367,7 @@ fn push_debuginfo_type_name<'tcx>( output.push_str(sig.safety.prefix_str()); if sig.abi != rustc_abi::ExternAbi::Rust { - output.push_str("extern \""); - output.push_str(sig.abi.name()); - output.push_str("\" "); + let _ = write!(output, "extern {} ", sig.abi); } output.push_str("fn("); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 45003c83edc2..616d748a2995 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1036,7 +1036,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // This is also relevant for `Pin<&mut Self>`, where we need to peel the // `Pin`. - while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() { + while !op.layout.ty.is_raw_ptr() && !op.layout.ty.is_ref() { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); @@ -1068,7 +1068,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } Immediate(_) => { // See comment above explaining why we peel these newtypes - while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() { + while !op.layout.ty.is_raw_ptr() && !op.layout.ty.is_ref() { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 6e7fbe62c8df..b34e966ba6ce 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.sess().dcx().emit_fatal(errors::AtomicCompareExchange); }; let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { let weak = instruction == "cxchgweak"; let dst = args[0].immediate(); let cmp = args[1].immediate(); @@ -395,7 +395,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "load" => { let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { let layout = bx.layout_of(ty); let size = layout.size; let source = args[0].immediate(); @@ -413,7 +413,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "store" => { let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { let size = bx.layout_of(ty).size; let val = args[1].immediate(); let ptr = args[0].immediate(); @@ -458,7 +458,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { let ptr = args[0].immediate(); let val = args[1].immediate(); bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 27cb7883b9a6..3b7fefee80a3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -689,7 +689,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (OperandValue::Immediate(llval), operand.layout) } mir::UnOp::PtrMetadata => { - assert!(operand.layout.ty.is_unsafe_ptr() || operand.layout.ty.is_ref(),); + assert!(operand.layout.ty.is_raw_ptr() || operand.layout.ty.is_ref(),); let (_, meta) = operand.val.pointer_parts(); assert_eq!(operand.layout.fields.count() > 1, meta.is_some()); if let Some(meta) = meta { diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index d0ce027ec2b7..90002d3f1090 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -710,7 +710,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if is_int_bool_float_or_char(lhs_ty) && is_int_bool_float_or_char(rhs_ty) { // Int, bool, float, and char operations are fine. - } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { + } else if lhs_ty.is_fn_ptr() || lhs_ty.is_raw_ptr() { assert_matches!( op, BinOp::Eq diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 8df9877cabca..c08495c012f8 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -16,7 +16,6 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::ty::{self, Mutability, Ty}; use rustc_span::{Span, Symbol}; -use rustc_target::callconv::AdjustForForeignAbiError; use crate::interpret::InternKind; @@ -936,9 +935,6 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { InvalidProgramInfo::TooGeneric => const_eval_too_generic, InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported, InvalidProgramInfo::Layout(e) => e.diagnostic_message(), - InvalidProgramInfo::FnAbiAdjustForForeignAbi(_) => { - rustc_middle::error::middle_adjust_for_foreign_abi_error - } } } fn add_args(self, diag: &mut Diag<'_, G>) { @@ -953,12 +949,6 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { } dummy_diag.cancel(); } - InvalidProgramInfo::FnAbiAdjustForForeignAbi( - AdjustForForeignAbiError::Unsupported { arch, abi }, - ) => { - diag.arg("arch", arch); - diag.arg("abi", abi.name()); - } } } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index e110c155da08..b53c1505f6b1 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -203,7 +203,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { cast_to: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_any_ptr()); - assert!(cast_to.ty.is_unsafe_ptr()); + assert!(cast_to.ty.is_raw_ptr()); // Handle casting any ptr to raw ptr (might be a wide ptr). if cast_to.size == src.layout.size { // Thin or wide pointer that just has the ptr kind of target type changed. @@ -212,7 +212,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Casting the metadata away from a wide ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); assert_eq!(cast_to.size, self.pointer_size()); - assert!(src.layout.ty.is_unsafe_ptr()); + assert!(src.layout.ty.is_raw_ptr()); return match **src { Immediate::ScalarPair(data, _) => interp_ok(ImmTy::from_scalar(data, cast_to)), Immediate::Scalar(..) => span_bug!( diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 95a72d3cbc1d..66a75113652f 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -106,9 +106,6 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { ) -> InterpErrorKind<'tcx> { match err { FnAbiError::Layout(err) => err_inval!(Layout(err)), - FnAbiError::AdjustForForeignAbi(err) => { - err_inval!(FnAbiAdjustForForeignAbi(err)) - } } } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index abe73c43d8a9..6a17da61c8b7 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -241,7 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Figure out whether this is an addr_of of an already raw place. let place_base_raw = if place.is_indirect_first_projection() { let ty = self.frame().body.local_decls[place.local].ty; - ty.is_unsafe_ptr() + ty.is_raw_ptr() } else { // Not a deref, and thus not raw. false diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index eb98e3b53805..ba579e25f036 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,12 +1,8 @@ -use std::ops::ControlFlow; - use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, -}; +use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt}; use tracing::debug; use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval}; @@ -20,44 +16,10 @@ where T: TypeVisitable>, { debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.has_param() { - return interp_ok(()); - } - - struct FoundParam; - struct UsedParamsNeedInstantiationVisitor {} - - impl<'tcx> TypeVisitor> for UsedParamsNeedInstantiationVisitor { - type Result = ControlFlow; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - if !ty.has_param() { - return ControlFlow::Continue(()); - } - - match *ty.kind() { - ty::Param(_) => ControlFlow::Break(FoundParam), - ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::FnDef(..) => { - ControlFlow::Continue(()) - } - _ => ty.super_visit_with(self), - } - } - - fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { - match c.kind() { - ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), - _ => c.super_visit_with(self), - } - } - } - - let mut vis = UsedParamsNeedInstantiationVisitor {}; - if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { + if ty.has_param() { throw_inval!(TooGeneric); - } else { - interp_ok(()) } + interp_ok(()) } impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> { diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 07b88e59723d..0b45e5786e83 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_passes = { path = "../rustc_ast_passes" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4c47ce93dd56..2bcc33241dfa 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_target::spec::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_error_codes/src/error_codes/E0802.md b/compiler/rustc_error_codes/src/error_codes/E0802.md new file mode 100644 index 000000000000..59061ff04359 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0802.md @@ -0,0 +1,94 @@ +The target of `derive(CoercePointee)` macro has inadmissible specification for +a meaningful use. + +Erroneous code examples: + +The target data is not a `struct`. + +```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; +#[derive(CoercePointee)] +enum NotStruct<'a, T: ?Sized> { + Variant(&'a T), +} +``` + +The target data has a layout that is not transparent, or `repr(transparent)` +in other words. + +```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; +#[derive(CoercePointee)] +struct NotTransparent<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} +``` + +The target data has no data field. + +```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; +#[derive(CoercePointee)] +#[repr(transparent)] +struct NoField<'a, #[pointee] T: ?Sized> {} +``` + +The target data is not generic over any data, or has no generic type parameter. + +```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; +#[derive(CoercePointee)] +#[repr(transparent)] +struct NoGeneric<'a>(&'a u8); +``` + +The target data has multiple generic type parameters, but none is designated as +a pointee for coercion. + +```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; +#[derive(CoercePointee)] +#[repr(transparent)] +struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> { + a: (&'a T1, &'a T2), +} +``` + +The target data has multiple generic type parameters that are designated as +pointees for coercion. + +```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; +#[derive(CoercePointee)] +#[repr(transparent)] +struct TooManyPointees< + 'a, + #[pointee] A: ?Sized, + #[pointee] B: ?Sized> +((&'a A, &'a B)); +``` + +The type parameter that is designated as a pointee is not marked `?Sized`. + +```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; +#[derive(CoercePointee)] +#[repr(transparent)] +struct NoMaybeSized<'a, #[pointee] T> { + ptr: &'a T, +} +``` + +In summary, the `CoercePointee` macro demands the type to be a `struct` that is +generic over at least one type or over more types, one of which is marked with +`#[pointee]`, and has at least one data field and adopts a `repr(transparent)` +layout. +The only generic type or the type marked with `#[pointee]` has to be also +marked as `?Sized`. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 0a30bdb48a09..e970b16f6106 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -545,6 +545,7 @@ E0798: 0798, E0799: 0799, E0800: 0800, E0801: 0801, +E0802: 0802, ); ) } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index d179396398f0..7f383946c146 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -93,6 +93,7 @@ into_diag_arg_using_display!( SplitDebuginfo, ExitStatus, ErrCode, + rustc_abi::ExternAbi, ); impl IntoDiagArg for rustc_type_ir::TraitRef { @@ -108,13 +109,13 @@ impl IntoDiagArg for rustc_type_ir::ExistentialTrait } impl IntoDiagArg for rustc_type_ir::UnevaluatedConst { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self) -> DiagArgValue { format!("{self:?}").into_diag_arg() } } impl IntoDiagArg for rustc_type_ir::FnSig { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self) -> DiagArgValue { format!("{self:?}").into_diag_arg() } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 15cf285e7ffc..4824dc098ada 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1982,7 +1982,7 @@ impl HumanEmitter { { debug!(?complete, ?parts, ?highlights); - let has_deletion = parts.iter().any(|p| p.is_deletion(sm)); + let has_deletion = parts.iter().any(|p| p.is_deletion(sm) || p.is_replacement(sm)); let is_multiline = complete.lines().count() > 1; if i == 0 { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 046213b5a6a6..ee7f68cc2f01 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -1,7 +1,8 @@ use rustc_ast::ptr::P; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, attr, token, + self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, + attr, token, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -138,6 +139,42 @@ impl<'a> ExtCtxt<'a> { } } + pub fn lifetime_param( + &self, + span: Span, + ident: Ident, + bounds: ast::GenericBounds, + ) -> ast::GenericParam { + ast::GenericParam { + id: ast::DUMMY_NODE_ID, + ident: ident.with_span_pos(span), + attrs: AttrVec::new(), + bounds, + is_placeholder: false, + kind: ast::GenericParamKind::Lifetime, + colon_span: None, + } + } + + pub fn const_param( + &self, + span: Span, + ident: Ident, + bounds: ast::GenericBounds, + ty: P, + default: Option, + ) -> ast::GenericParam { + ast::GenericParam { + id: ast::DUMMY_NODE_ID, + ident: ident.with_span_pos(span), + attrs: AttrVec::new(), + bounds, + is_placeholder: false, + kind: ast::GenericParamKind::Const { ty, kw_span: DUMMY_SP, default }, + colon_span: None, + } + } + pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef { ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID } } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 822cf4982b56..76ca0d618d55 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -197,9 +197,6 @@ declare_features! ( (accepted, expr_fragment_specifier_2024, "1.83.0", Some(123742)), /// Allows arbitrary expressions in key-value attributes at parse time. (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), - /// Allows using `efiapi`, `aapcs`, `sysv64` and `win64` as calling - /// convention for functions with varargs. - (accepted, extended_varargs_abi_support, "1.85.0", Some(100189)), /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660)), /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a4c5e4800eb4..ee22d8990fa4 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -487,6 +487,9 @@ declare_features! ( (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), + /// Allows using `efiapi`, `sysv64` and `win64` as calling convention + /// for functions with varargs. + (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), /// Allows defining `extern type`s. (unstable, extern_types, "1.23.0", Some(43467)), /// Allow using 128-bit (quad precision) floating point numbers. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b6689c95c4bb..34c0837b25a5 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -351,6 +351,7 @@ language_item_table! { PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1); ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct, GenericRequirement::None; + BikeshedGuaranteedNoDrop, sym::bikeshed_guaranteed_no_drop, bikeshed_guaranteed_no_drop, Target::Trait, GenericRequirement::Exact(0); MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None; @@ -370,6 +371,8 @@ language_item_table! { PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0); + CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait, GenericRequirement::Exact(0); + ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); @@ -429,9 +432,13 @@ language_item_table! { ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None; } +/// The requirement imposed on the generics of a lang item pub enum GenericRequirement { + /// No restriction on the generics None, + /// A minimum number of generics that is demanded on a lang item Minimum(usize), + /// The number of generics must match precisely as stipulated Exact(usize), } diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index db0d0fcf3b91..d7c8a3d5c0a5 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_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index c28c1afcfe66..7344ea01fb21 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -72,19 +72,29 @@ hir_analysis_cmse_entry_generic = functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type hir_analysis_cmse_inputs_stack_spill = - arguments for `"{$abi_name}"` function too large to pass via registers + arguments for `{$abi}` function too large to pass via registers .label = {$plural -> [false] this argument doesn't *[true] these arguments don't } fit in the available registers - .note = functions with the `"{$abi_name}"` ABI must pass all their arguments via the 4 32-bit available argument registers + .note = functions with the `{$abi}` ABI must pass all their arguments via the 4 32-bit available argument registers hir_analysis_cmse_output_stack_spill = - return value of `"{$abi_name}"` function too large to pass via registers + return value of `{$abi}` function too large to pass via registers .label = this type doesn't fit in the available registers - .note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers + .note1 = functions with the `{$abi}` ABI must pass their result via the available return registers .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size +hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field + +hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden + +hir_analysis_coerce_pointee_not_concrete_ty = `derive(CoercePointee)` is only applicable to `struct` + +hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applicable to `struct`, instead of `{$kind}` + +hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout + hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions @@ -592,7 +602,7 @@ hir_analysis_value_of_associated_struct_already_specified = .label = re-bound here .previous_bound_label = `{$item_name}` bound here first -hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi` +hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} .label = C-variadic function must have a compatible calling convention hir_analysis_variances_of = {$variances} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 9ed56d7bde51..71a10ad3a0c1 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; use rustc_hir::def::{CtorKind, DefKind}; -use rustc_hir::{Node, intravisit}; +use rustc_hir::{LangItem, Node, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ @@ -27,6 +27,7 @@ use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_type_ir::fold::TypeFoldable; use tracing::{debug, instrument}; use ty::TypingMode; @@ -87,89 +88,76 @@ fn allowed_union_or_unsafe_field<'tcx>( typing_env: ty::TypingEnv<'tcx>, span: Span, ) -> bool { - // We don't just accept all !needs_drop fields, due to semver concerns. - let allowed = match ty.kind() { - ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) - ty::Tuple(tys) => { - // allow tuples of allowed types - tys.iter().all(|ty| allowed_union_or_unsafe_field(tcx, ty, typing_env, span)) - } - ty::Array(elem, _len) => { - // Like `Copy`, we do *not* special-case length 0. - allowed_union_or_unsafe_field(tcx, *elem, typing_env, span) - } - _ => { - // Fallback case: allow `ManuallyDrop` and things that are `Copy`, - // also no need to report an error if the type is unresolved. - ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) - || tcx.type_is_copy_modulo_regions(typing_env, ty) - || ty.references_error() - } - }; - if allowed && ty.needs_drop(tcx, typing_env) { - // This should never happen. But we can get here e.g. in case of name resolution errors. - tcx.dcx() - .span_delayed_bug(span, "we should never accept maybe-dropping union or unsafe fields"); + // HACK (not that bad of a hack don't worry): Some codegen tests don't even define proper + // impls for `Copy`. Let's short-circuit here for this validity check, since a lot of them + // use unions. We should eventually fix all the tests to define that lang item or use + // minicore stubs. + if ty.is_trivially_pure_clone_copy() { + return true; } - allowed + // If `BikeshedGuaranteedNoDrop` is not defined in a `#[no_core]` test, fall back to `Copy`. + // This is an underapproximation of `BikeshedGuaranteedNoDrop`, + let def_id = tcx + .lang_items() + .get(LangItem::BikeshedGuaranteedNoDrop) + .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, Some(span))); + let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else { + tcx.dcx().span_delayed_bug(span, "could not normalize field type"); + return true; + }; + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + infcx.predicate_must_hold_modulo_regions(&Obligation::new( + tcx, + ObligationCause::dummy_with_span(span), + param_env, + ty::TraitRef::new(tcx, def_id, [ty]), + )) } /// Check that the fields of the `union` do not need dropping. fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { - let item_type = tcx.type_of(item_def_id).instantiate_identity(); - if let ty::Adt(def, args) = item_type.kind() { - assert!(def.is_union()); + let def = tcx.adt_def(item_def_id); + assert!(def.is_union()); - let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); - for field in &def.non_enum_variant().fields { - let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) - else { - tcx.dcx().span_delayed_bug(span, "could not normalize field type"); - continue; + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); + let args = ty::GenericArgs::identity_for_item(tcx, item_def_id); + + for field in &def.non_enum_variant().fields { + if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) { + let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { + // We are currently checking the type this field came from, so it must be local. + Some(Node::Field(field)) => (field.span, field.ty.span), + _ => unreachable!("mir field has to correspond to hir field"), }; - - if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) { - let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { - // We are currently checking the type this field came from, so it must be local. - Some(Node::Field(field)) => (field.span, field.ty.span), - _ => unreachable!("mir field has to correspond to hir field"), - }; - tcx.dcx().emit_err(errors::InvalidUnionField { - field_span, - sugg: errors::InvalidUnionFieldSuggestion { - lo: ty_span.shrink_to_lo(), - hi: ty_span.shrink_to_hi(), - }, - note: (), - }); - return false; - } + tcx.dcx().emit_err(errors::InvalidUnionField { + field_span, + sugg: errors::InvalidUnionFieldSuggestion { + lo: ty_span.shrink_to_lo(), + hi: ty_span.shrink_to_hi(), + }, + note: (), + }); + return false; } - } else { - span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind()); } + true } /// Check that the unsafe fields do not need dropping. fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) { let span = tcx.def_span(item_def_id); - let item_type = tcx.type_of(item_def_id).instantiate_identity(); - let ty::Adt(def, args) = item_type.kind() else { - span_bug!(span, "structs/enums must be ty::Adt, but got {:?}", item_type.kind()); - }; + let def = tcx.adt_def(item_def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); + let args = ty::GenericArgs::identity_for_item(tcx, item_def_id); + for field in def.all_fields() { if !field.safety.is_unsafe() { continue; } - let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) - else { - tcx.dcx().span_delayed_bug(span, "could not normalize field type"); - continue; - }; - if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) { + if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) { let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.expect_local()) else { unreachable!("field has to correspond to hir field") }; diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 66082f4c282b..9da57c330c5e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -48,6 +48,10 @@ pub(super) fn check_trait<'tcx>( checker .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?; + checker.check( + lang_items.coerce_pointee_validated_trait(), + visit_implementation_of_coerce_pointee_validity, + )?; Ok(()) } @@ -783,3 +787,32 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err .with_note(why_disqualified) .emit()) } + +fn visit_implementation_of_coerce_pointee_validity( + checker: &Checker<'_>, +) -> Result<(), ErrorGuaranteed> { + let tcx = checker.tcx; + let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); + let span = tcx.def_span(checker.impl_def_id); + if !tcx.is_builtin_derived(checker.impl_def_id.into()) { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span })); + } + let ty::Adt(def, _args) = self_ty.kind() else { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span })); + }; + let did = def.did(); + // Now get a more precise span of the `struct`. + let span = tcx.def_span(did); + if !def.is_struct() { + return Err(tcx + .dcx() + .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() })); + } + if !def.repr().transparent() { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span })); + } + if def.all_fields().next().is_none() { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span })); + } + Ok(()) +} diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ce7319f65619..126237799562 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -614,9 +614,10 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { if !infer_replacements.is_empty() { diag.multipart_suggestion( format!( - "try replacing `_` with the type{} in the corresponding trait method signature", - rustc_errors::pluralize!(infer_replacements.len()), - ), + "try replacing `_` with the type{} in the corresponding trait method \ + signature", + rustc_errors::pluralize!(infer_replacements.len()), + ), infer_replacements, Applicability::MachineApplicable, ); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9769be302264..1574506de603 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1,5 +1,6 @@ //! Errors emitted by `rustc_hir_analysis`. +use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, @@ -646,10 +647,11 @@ pub(crate) struct MainFunctionGenericParameters { #[derive(Diagnostic)] #[diag(hir_analysis_variadic_function_compatible_convention, code = E0045)] -pub(crate) struct VariadicFunctionCompatibleConvention { +pub(crate) struct VariadicFunctionCompatibleConvention<'a> { #[primary_span] #[label] pub span: Span, + pub conventions: &'a str, } #[derive(Diagnostic)] @@ -1180,6 +1182,42 @@ pub(crate) struct DispatchFromDynRepr { pub span: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_not_struct, code = E0802)] +pub(crate) struct CoercePointeeNotStruct { + #[primary_span] + pub span: Span, + pub kind: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_not_concrete_ty, code = E0802)] +pub(crate) struct CoercePointeeNotConcreteType { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_no_user_validity_assertion, code = E0802)] +pub(crate) struct CoercePointeeNoUserValidityAssertion { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_not_transparent, code = E0802)] +pub(crate) struct CoercePointeeNotTransparent { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_no_field, code = E0802)] +pub(crate) struct CoercePointeeNoField { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)] #[help] @@ -1653,7 +1691,7 @@ pub(crate) struct CmseInputsStackSpill { #[label] pub span: Span, pub plural: bool, - pub abi_name: &'static str, + pub abi: ExternAbi, } #[derive(Diagnostic)] @@ -1664,7 +1702,7 @@ pub(crate) struct CmseOutputStackSpill { #[primary_span] #[label] pub span: Span, - pub abi_name: &'static str, + pub abi: ExternAbi, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 4c8f2735b979..5fed2e352879 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -17,8 +17,6 @@ pub(crate) fn validate_cmse_abi<'tcx>( abi: ExternAbi, fn_sig: ty::PolyFnSig<'tcx>, ) { - let abi_name = abi.name(); - match abi { ExternAbi::CCmseNonSecureCall => { let hir_node = tcx.hir_node(hir_id); @@ -56,7 +54,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( .to(bare_fn_ty.decl.inputs[index].span) .to(bare_fn_ty.decl.inputs.last().unwrap().span); let plural = bare_fn_ty.param_names.len() - index != 1; - dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi_name }); + dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi }); } Err(layout_err) => { if should_emit_generic_error(abi, layout_err) { @@ -69,7 +67,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( Ok(true) => {} Ok(false) => { let span = bare_fn_ty.decl.output.span(); - dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name }); + dcx.emit_err(errors::CmseOutputStackSpill { span, abi }); } Err(layout_err) => { if should_emit_generic_error(abi, layout_err) { @@ -92,7 +90,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( // ^^^^^^ let span = decl.inputs[index].span.to(decl.inputs.last().unwrap().span); let plural = decl.inputs.len() - index != 1; - dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi_name }); + dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi }); } Err(layout_err) => { if should_emit_generic_error(abi, layout_err) { @@ -105,7 +103,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( Ok(true) => {} Ok(false) => { let span = decl.output.span(); - dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name }); + dcx.emit_err(errors::CmseOutputStackSpill { span, abi }); } Err(layout_err) => { if should_emit_generic_error(abi, layout_err) { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 79aa2f4b8ccd..7eb982a31798 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{ Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err, }; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; @@ -1027,7 +1027,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, segments: impl Iterator> + Clone, args_visitors: impl Iterator> + Clone, - err_extend: GenericsArgsErrExtend<'_>, + err_extend: GenericsArgsErrExtend<'a>, ) -> ErrorGuaranteed { #[derive(PartialEq, Eq, Hash)] enum ProhibitGenericsArg { @@ -1047,23 +1047,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; }); + let segments: Vec<_> = segments.collect(); let types_and_spans: Vec<_> = segments - .clone() + .iter() .flat_map(|segment| { if segment.args().args.is_empty() { None } else { Some(( match segment.res { - hir::def::Res::PrimTy(ty) => { + Res::PrimTy(ty) => { format!("{} `{}`", segment.res.descr(), ty.name()) } - hir::def::Res::Def(_, def_id) + Res::Def(_, def_id) if let Some(name) = self.tcx().opt_item_name(def_id) => { format!("{} `{name}`", segment.res.descr()) } - hir::def::Res::Err => "this type".to_string(), + Res::Err => "this type".to_string(), _ => segment.res.descr().to_string(), }, segment.ident.span, @@ -1074,11 +1075,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let this_type = listify(&types_and_spans, |(t, _)| t.to_string()) .expect("expected one segment to deny"); - let arg_spans: Vec = segments - .clone() - .flat_map(|segment| segment.args().args) - .map(|arg| arg.span()) - .collect(); + let arg_spans: Vec = + segments.iter().flat_map(|segment| segment.args().args).map(|arg| arg.span()).collect(); let mut kinds = Vec::with_capacity(4); prohibit_args.iter().for_each(|arg| match arg { @@ -1103,7 +1101,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for (what, span) in types_and_spans { err.span_label(span, format!("not allowed on {what}")); } - generics_args_err_extend(self.tcx(), segments, &mut err, err_extend); + generics_args_err_extend(self.tcx(), segments.into_iter(), &mut err, err_extend); err.emit() } @@ -1400,7 +1398,7 @@ pub enum GenericsArgsErrExtend<'tcx> { }, SelfTyParam(Span), Param(DefId), - DefVariant, + DefVariant(&'tcx [hir::PathSegment<'tcx>]), None, } @@ -1408,7 +1406,7 @@ fn generics_args_err_extend<'a>( tcx: TyCtxt<'_>, segments: impl Iterator> + Clone, err: &mut Diag<'_>, - err_extend: GenericsArgsErrExtend<'_>, + err_extend: GenericsArgsErrExtend<'a>, ) { match err_extend { GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => { @@ -1496,6 +1494,32 @@ fn generics_args_err_extend<'a>( ]; err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect); } + GenericsArgsErrExtend::DefVariant(segments) => { + let args: Vec = segments + .iter() + .filter_map(|segment| match segment.res { + Res::Def( + DefKind::Ctor(CtorOf::Variant, _) | DefKind::Variant | DefKind::Enum, + _, + ) => segment.args().span_ext().map(|s| s.with_lo(segment.ident.span.hi())), + _ => None, + }) + .collect(); + if args.len() > 1 + && let Some(span) = args.into_iter().last() + { + err.note( + "generic arguments are not allowed on both an enum and its variant's path \ + segments simultaneously; they are only valid in one place or the other", + ); + err.span_suggestion_verbose( + span, + "remove the generics arguments from one of the path segments", + String::new(), + Applicability::MaybeIncorrect, + ); + } + } GenericsArgsErrExtend::PrimTy(prim_ty) => { let name = prim_ty.name_str(); for segment in segments { @@ -1512,9 +1536,6 @@ fn generics_args_err_extend<'a>( GenericsArgsErrExtend::OpaqueTy => { err.note("`impl Trait` types can't have type parameters"); } - GenericsArgsErrExtend::DefVariant => { - err.note("enum variants can't have type parameters"); - } GenericsArgsErrExtend::Param(def_id) => { let span = tcx.def_ident_span(def_id).unwrap(); let kind = tcx.def_descr(def_id); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ffddf6f73aaf..c6e47a804dc8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1694,7 +1694,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn prohibit_generic_args<'a>( &self, segments: impl Iterator> + Clone, - err_extend: GenericsArgsErrExtend<'_>, + err_extend: GenericsArgsErrExtend<'a>, ) -> Result<(), ErrorGuaranteed> { let args_visitors = segments.clone().flat_map(|segment| segment.args().args); let mut result = Ok(()); @@ -1911,7 +1911,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { path.segments.iter().enumerate().filter_map(|(index, seg)| { if !indices.contains(&index) { Some(seg) } else { None } }), - GenericsArgsErrExtend::DefVariant, + GenericsArgsErrExtend::DefVariant(&path.segments), ); let GenericPathSegment(def_id, index) = generic_segments.last().unwrap(); @@ -2154,11 +2154,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") } // FIXME(const_generics): create real const to allow fn items as const paths - Res::Def(DefKind::Fn | DefKind::AssocFn, _) => ty::Const::new_error_with_message( - tcx, - span, - "fn items cannot be used as const args", - ), + Res::Def(DefKind::Fn | DefKind::AssocFn, did) => { + self.dcx().span_delayed_bug(span, "function items cannot be used as const args"); + let args = self.lower_generic_args_of_path_segment( + span, + did, + path.segments.last().unwrap(), + ); + ty::Const::new_value(tcx, ty::ValTree::zst(), Ty::new_fn_def(tcx, did, args)) + } // Exhaustive match to be clear about what exactly we're considering to be // an invalid Res for a const path. @@ -2557,27 +2561,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // reject function types that violate cmse ABI requirements cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, bare_fn_ty); - // Find any late-bound regions declared in return type that do - // not appear in the arguments. These are not well-formed. - // - // Example: - // for<'a> fn() -> &'a str <-- 'a is bad - // for<'a> fn(&'a String) -> &'a str <-- 'a is ok - let inputs = bare_fn_ty.inputs(); - let late_bound_in_args = - tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned())); - let output = bare_fn_ty.output(); - let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output); + if !bare_fn_ty.references_error() { + // Find any late-bound regions declared in return type that do + // not appear in the arguments. These are not well-formed. + // + // Example: + // for<'a> fn() -> &'a str <-- 'a is bad + // for<'a> fn(&'a String) -> &'a str <-- 'a is ok + let inputs = bare_fn_ty.inputs(); + let late_bound_in_args = + tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned())); + let output = bare_fn_ty.output(); + let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output); - self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { - struct_span_code_err!( - self.dcx(), - decl.output.span(), - E0581, - "return type references {}, which is not constrained by the fn input types", - br_name - ) - }); + self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { + struct_span_code_err!( + self.dcx(), + decl.output.span(), + E0581, + "return type references {}, which is not constrained by the fn input types", + br_name + ) + }); + } bare_fn_ty } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3af4318544e9..323b912ca18a 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -100,6 +100,8 @@ use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_session::parse::feature_err; +use rustc_span::symbol::sym; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; @@ -114,9 +116,34 @@ fn require_c_abi_if_c_variadic( abi: ExternAbi, span: Span, ) { - if decl.c_variadic && !abi.supports_varargs() { - tcx.dcx().emit_err(errors::VariadicFunctionCompatibleConvention { span }); + const CONVENTIONS_UNSTABLE: &str = + "`C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`"; + const CONVENTIONS_STABLE: &str = "`C` or `cdecl`"; + const UNSTABLE_EXPLAIN: &str = + "using calling conventions other than `C` or `cdecl` for varargs functions is unstable"; + + if !decl.c_variadic || matches!(abi, ExternAbi::C { .. } | ExternAbi::Cdecl { .. }) { + return; } + + let extended_abi_support = tcx.features().extended_varargs_abi_support(); + let conventions = match (extended_abi_support, abi.supports_varargs()) { + // User enabled additional ABI support for varargs and function ABI matches those ones. + (true, true) => return, + + // Using this ABI would be ok, if the feature for additional ABI support was enabled. + // Return CONVENTIONS_STABLE, because we want the other error to look the same. + (false, true) => { + feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, UNSTABLE_EXPLAIN) + .emit(); + CONVENTIONS_STABLE + } + + (false, false) => CONVENTIONS_STABLE, + (true, false) => CONVENTIONS_UNSTABLE, + }; + + tcx.dcx().emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions }); } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index d8015bcc9142..f5f6ada12c3c 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -690,7 +690,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else { match self.try_coercion_cast(fcx) { Ok(()) => { - if self.expr_ty.is_unsafe_ptr() && self.cast_ty.is_unsafe_ptr() { + if self.expr_ty.is_raw_ptr() && self.cast_ty.is_raw_ptr() { // When casting a raw pointer to another raw pointer, we cannot convert the cast into // a coercion because the pointee types might only differ in regions, which HIR typeck // cannot distinguish. This would cause us to erroneously discard a cast which will diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 14dd0f32d820..ad378367e305 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -219,7 +219,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // or pin-ergonomics. match *b.kind() { ty::RawPtr(_, b_mutbl) => { - return self.coerce_unsafe_ptr(a, b, b_mutbl); + return self.coerce_raw_ptr(a, b, b_mutbl); } ty::Ref(r_b, _, mutbl_b) => { return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); @@ -1017,13 +1017,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } - fn coerce_unsafe_ptr( + fn coerce_raw_ptr( &self, a: Ty<'tcx>, b: Ty<'tcx>, mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { - debug!("coerce_unsafe_ptr(a={:?}, b={:?})", a, b); + debug!("coerce_raw_ptr(a={:?}, b={:?})", a, b); let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), @@ -1033,21 +1033,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { coerce_mutbls(mt_a.mutbl, mutbl_b)?; // Check that the types which they point at are compatible. - let a_unsafe = Ty::new_ptr(self.tcx, mt_a.ty, mutbl_b); - // Although references and unsafe ptrs have the same + let a_raw = Ty::new_ptr(self.tcx, mt_a.ty, mutbl_b); + // Although references and raw ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. if is_ref { - self.unify_and(a_unsafe, b, |target| { + self.unify_and(a_raw, b, |target| { vec![ Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }, Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target }, ] }) } else if mt_a.mutbl != mutbl_b { - self.unify_and(a_unsafe, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer))) + self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer))) } else { - self.unify_and(a_unsafe, b, identity) + self.unify_and(a_raw, b, identity) } } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9dd965a4dcbb..9ccd67460874 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3556,7 +3556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if base_t.is_unsafe_ptr() && idx_t.is_integral() { + if base_t.is_raw_ptr() && idx_t.is_integral() { err.multipart_suggestion( "consider using `wrapping_add` or `add` for indexing into raw pointer", vec![ diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 6bb8cf5f3315..e74ffeff343a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1043,12 +1043,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut user_self_ty = None; let mut is_alias_variant_ctor = false; + let mut err_extend = GenericsArgsErrExtend::None; match res { Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) if let Some(self_ty) = self_ty => { let adt_def = self_ty.normalized.ty_adt_def().unwrap(); user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw }); is_alias_variant_ctor = true; + err_extend = GenericsArgsErrExtend::DefVariant(segments); + } + Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { + err_extend = GenericsArgsErrExtend::DefVariant(segments); } Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { let assoc_item = tcx.associated_item(def_id); @@ -1095,7 +1100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segments.iter().enumerate().filter_map(|(index, seg)| { if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None } }), - GenericsArgsErrExtend::None, + err_extend, ); if let Res::Local(hid) = res { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 3e48e8d15c3c..36cc9b40d008 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -681,17 +681,23 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id); // must be exactly one trait ref or we'd get an ambig error etc - let [upcast_trait_ref] = upcast_trait_refs.as_slice() else { - span_bug!( + if let &[upcast_trait_ref] = upcast_trait_refs.as_slice() { + upcast_trait_ref + } else { + self.dcx().span_delayed_bug( self.span, - "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`", - source_trait_ref, - target_trait_def_id, - upcast_trait_refs - ) - }; + format!( + "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`", + source_trait_ref, target_trait_def_id, upcast_trait_refs + ), + ); - *upcast_trait_ref + ty::Binder::dummy(ty::TraitRef::new_from_args( + self.tcx, + target_trait_def_id, + ty::GenericArgs::extend_with_error(self.tcx, target_trait_def_id, &[]), + )) + } } fn instantiate_binder_with_fresh_vars(&self, value: ty::Binder<'tcx, T>) -> T diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b9d1f93bfb8e..9394fcafd767 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -598,7 +598,7 @@ fn method_autoderef_steps<'tcx>( unsize: false, reachable_via_deref, }; - if ty.is_unsafe_ptr() { + if ty.is_raw_ptr() { // all the subsequent steps will be from_unsafe_deref reached_raw_pointer = true; } @@ -618,7 +618,7 @@ fn method_autoderef_steps<'tcx>( unsize: false, reachable_via_deref: true, }; - if ty.is_unsafe_ptr() { + if ty.is_raw_ptr() { // all the subsequent steps will be from_unsafe_deref reached_raw_pointer = true; } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index fc07c9858494..1750c2af1c7f 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -645,7 +645,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // pointer + {integer} or pointer - pointer. if op.span.can_be_used_for_suggestions() { match op.node { - hir::BinOpKind::Add if lhs_ty.is_unsafe_ptr() && rhs_ty.is_integral() => { + hir::BinOpKind::Add if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() => { err.multipart_suggestion( "consider using `wrapping_add` or `add` for pointer + {integer}", vec![ @@ -659,7 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } hir::BinOpKind::Sub => { - if lhs_ty.is_unsafe_ptr() && rhs_ty.is_integral() { + if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() { err.multipart_suggestion( "consider using `wrapping_sub` or `sub` for \ pointer - {integer}", @@ -674,7 +674,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if lhs_ty.is_unsafe_ptr() && rhs_ty.is_unsafe_ptr() { + if lhs_ty.is_raw_ptr() && rhs_ty.is_raw_ptr() { err.multipart_suggestion( "consider using `offset_from` for pointer - pointer if the \ pointers point to the same allocation", diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index c986429c1b24..dacbadbcd005 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -2042,7 +2042,7 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { restrict_repr_packed_field_ref_capture(place_with_id.place.clone(), capture_kind); // Raw pointers don't inherit mutability - if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) { + if place_with_id.place.deref_tys().any(Ty::is_raw_ptr) { capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::Immutable); } @@ -2093,7 +2093,7 @@ fn restrict_precision_for_unsafe( mut place: Place<'_>, mut curr_mode: ty::UpvarCapture, ) -> (Place<'_>, ty::UpvarCapture) { - if place.base_ty.is_unsafe_ptr() { + if place.base_ty.is_raw_ptr() { truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0); } @@ -2102,8 +2102,8 @@ fn restrict_precision_for_unsafe( } for (i, proj) in place.projections.iter().enumerate() { - if proj.ty.is_unsafe_ptr() { - // Don't apply any projections on top of an unsafe ptr. + if proj.ty.is_raw_ptr() { + // Don't apply any projections on top of a raw ptr. truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i + 1); break; } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 55c6a122d35d..480d97e377a4 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -390,9 +390,6 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` lint_improper_ctypes_opaque = opaque types have no C equivalent -lint_improper_ctypes_pat_help = consider using the base type instead - -lint_improper_ctypes_pat_reason = pattern types have no C equivalent lint_improper_ctypes_slice_help = consider using a raw pointer instead lint_improper_ctypes_slice_reason = slices have no C equivalent diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5e6b854ff52e..ecd40a52e75f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -576,7 +576,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { // and recommending Copy might be a bad idea. for field in def.all_fields() { let did = field.did; - if cx.tcx.type_of(did).instantiate_identity().is_unsafe_ptr() { + if cx.tcx.type_of(did).instantiate_identity().is_raw_ptr() { return; } } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 92dbc76a7b5e..aeb5a03a4f7e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -160,8 +160,7 @@ pub(super) fn decorate_lint( .decorate_lint(diag); } BuiltinLintDiag::MissingAbi(label_span, default_abi) => { - lints::MissingAbi { span: label_span, default_abi: default_abi.name() } - .decorate_lint(diag); + lints::MissingAbi { span: label_span, default_abi }.decorate_lint(diag); } BuiltinLintDiag::LegacyDeriveHelpers(label_span) => { lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag); diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 45b188205d22..636779fe9b4c 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -241,10 +241,7 @@ fn structurally_same_type_impl<'tcx>( if let ty::Adt(def, args) = *ty.kind() { let is_transparent = def.repr().transparent(); let is_non_null = types::nonnull_optimization_guaranteed(tcx, def); - debug!( - "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", - ty, is_transparent, is_non_null - ); + debug!(?ty, is_transparent, is_non_null); if is_transparent && !is_non_null { debug_assert_eq!(def.variants().len(), 1); let v = &def.variant(FIRST_VARIANT); @@ -378,14 +375,14 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. - (Adt(..), _) if is_primitive_or_pointer(b) => { + (Adt(..) | Pat(..), _) if is_primitive_or_pointer(b) => { if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { a_inner == b } else { false } } - (_, Adt(..)) if is_primitive_or_pointer(a) => { + (_, Adt(..) | Pat(..)) if is_primitive_or_pointer(a) => { if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { b_inner == a } else { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d89e615e14ad..c8de5e877531 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -33,6 +33,7 @@ #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 09b0e1ed8bdb..368d36bfdd0b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,6 +2,7 @@ #![allow(rustc::untranslatable_diagnostic)] use std::num::NonZero; +use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, @@ -2833,9 +2834,9 @@ pub(crate) struct PatternsInFnsWithoutBodySub { #[derive(LintDiagnostic)] #[diag(lint_extern_without_abi)] pub(crate) struct MissingAbi { - #[suggestion(code = "extern \"{default_abi}\"", applicability = "machine-applicable")] + #[suggestion(code = "extern {default_abi}", applicability = "machine-applicable")] pub span: Span, - pub default_abi: &'static str, + pub default_abi: ExternAbi, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 601d2fbfb67f..68b1f435a4cf 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -877,6 +877,37 @@ fn ty_is_known_nonnull<'tcx>( .filter_map(|variant| transparent_newtype_field(tcx, variant)) .any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args), mode)) } + ty::Pat(base, pat) => { + ty_is_known_nonnull(tcx, typing_env, *base, mode) + || Option::unwrap_or_default( + try { + match **pat { + ty::PatternKind::Range { start, end, include_end } => { + match (start, end) { + (Some(start), None) => { + start.try_to_value()?.try_to_bits(tcx, typing_env)? > 0 + } + (Some(start), Some(end)) => { + let start = + start.try_to_value()?.try_to_bits(tcx, typing_env)?; + let end = + end.try_to_value()?.try_to_bits(tcx, typing_env)?; + + if include_end { + // This also works for negative numbers, as we just need + // to ensure we aren't wrapping over zero. + start > 0 && end >= start + } else { + start > 0 && end > start + } + } + _ => false, + } + } + } + }, + ) + } _ => false, } } @@ -907,9 +938,8 @@ fn get_nullable_type<'tcx>( }; return get_nullable_type(tcx, typing_env, inner_field_ty); } - ty::Int(ty) => Ty::new_int(tcx, ty), - ty::Uint(ty) => Ty::new_uint(tcx, ty), - ty::RawPtr(ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), + ty::Pat(base, ..) => return get_nullable_type(tcx, typing_env, base), + ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => ty, // As these types are always non-null, the nullable equivalent of // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), @@ -965,63 +995,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>( ckind: CItemKind, ) -> Option> { debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty); - if let ty::Adt(ty_def, args) = ty.kind() { - let field_ty = match &ty_def.variants().raw[..] { - [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { - ([], [field]) | ([field], []) => field.ty(tcx, args), - ([field1], [field2]) => { - let ty1 = field1.ty(tcx, args); - let ty2 = field2.ty(tcx, args); + match ty.kind() { + ty::Adt(ty_def, args) => { + let field_ty = match &ty_def.variants().raw[..] { + [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { + ([], [field]) | ([field], []) => field.ty(tcx, args), + ([field1], [field2]) => { + let ty1 = field1.ty(tcx, args); + let ty2 = field2.ty(tcx, args); - if is_niche_optimization_candidate(tcx, typing_env, ty1) { - ty2 - } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { - ty1 - } else { - return None; + if is_niche_optimization_candidate(tcx, typing_env, ty1) { + ty2 + } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { + ty1 + } else { + return None; + } } - } + _ => return None, + }, _ => return None, - }, - _ => return None, - }; - - if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { - return None; - } - - // At this point, the field's type is known to be nonnull and the parent enum is Option-like. - // If the computed size for the field and the enum are different, the nonnull optimization isn't - // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); - if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { - bug!("improper_ctypes: Option nonnull optimization not applied?"); - } - - // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); - if field_ty_layout.is_err() && !field_ty.has_non_region_param() { - bug!("should be able to compute the layout of non-polymorphic type"); - } - - let field_ty_abi = &field_ty_layout.ok()?.backend_repr; - if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { - match field_ty_scalar.valid_range(&tcx) { - WrappingRange { start: 0, end } - if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => - { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start, end } => { - unreachable!("Unhandled start and end range: ({}, {})", start, end) - } }; + + if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { + return None; + } + + // At this point, the field's type is known to be nonnull and the parent enum is Option-like. + // If the computed size for the field and the enum are different, the nonnull optimization isn't + // being applied (and we've got a problem somewhere). + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); + if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { + bug!("improper_ctypes: Option nonnull optimization not applied?"); + } + + // Return the nullable type this Option-like enum can be safely represented with. + let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); + if field_ty_layout.is_err() && !field_ty.has_non_region_param() { + bug!("should be able to compute the layout of non-polymorphic type"); + } + + let field_ty_abi = &field_ty_layout.ok()?.backend_repr; + if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { + match field_ty_scalar.valid_range(&tcx) { + WrappingRange { start: 0, end } + if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => + { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start: 1, .. } => { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start, end } => { + unreachable!("Unhandled start and end range: ({}, {})", start, end) + } + }; + } + None } + ty::Pat(base, pat) => match **pat { + ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, *base), + }, + _ => None, } - None } impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { @@ -1256,11 +1292,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { help: Some(fluent::lint_improper_ctypes_char_help), }, - ty::Pat(..) => FfiUnsafe { - ty, - reason: fluent::lint_improper_ctypes_pat_reason, - help: Some(fluent::lint_improper_ctypes_pat_help), - }, + // It's just extra invariants on the type that you need to uphold, + // but only the base type is relevant for being representable in FFI. + ty::Pat(base, ..) => self.check_type_for_ffi(acc, base), ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index ded1c5805727..09c16222be19 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 b30d3a950c6a..91b18295b43b 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_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 4df4624971df..83c7bb0f52f4 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -10,11 +10,10 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::Visitor; use rustc_hir::*; use rustc_hir_pretty as pprust_hir; -use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spans}; -use crate::hir::ModuleItems; +use crate::hir::{ModuleItems, nested_filter}; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; use crate::ty::TyCtxt; diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 77a7da2c74bc..93bbf6d7fa4f 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -13,7 +13,6 @@ use rustc_feature::GateIssue; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::{self as hir, HirId}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; -use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer}; @@ -23,6 +22,7 @@ use tracing::debug; pub use self::StabilityLevel::*; use crate::ty::TyCtxt; +use crate::ty::print::with_no_trimmed_paths; #[derive(PartialEq, Clone, Copy, Debug)] pub enum StabilityLevel { diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index a52ec58a1ee6..3fd73712b096 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -1,5 +1,6 @@ use gsgdt::{Edge, Graph, Node, NodeStyle}; -use rustc_middle::mir::*; + +use crate::mir::*; /// Convert an MIR function into a gsgdt Graph pub(crate) fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph { diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs index e1c3d8156d83..bce7beb521da 100644 --- a/compiler/rustc_middle/src/mir/generic_graphviz.rs +++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs @@ -2,7 +2,8 @@ use std::io::{self, Write}; use rustc_data_structures::graph::{self, iterate}; use rustc_graphviz as dot; -use rustc_middle::ty::TyCtxt; + +use crate::ty::TyCtxt; pub struct GraphvizWriter< 'a, diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index 7bb41193d5c9..a64b122fbc9e 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -2,10 +2,10 @@ use std::io::{self, Write}; use gsgdt::GraphvizSettings; use rustc_graphviz as dot; -use rustc_middle::mir::*; use super::generic_graph::mir_fn_to_generic_graph; use super::pretty::dump_mir_def_ids; +use crate::mir::*; /// Write a graphviz DOT graph of a list of MIRs. pub fn write_mir_graphviz(tcx: TyCtxt<'_>, single: Option, w: &mut W) -> io::Result<()> diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 1222ba052cce..8861e31b0991 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -216,10 +216,6 @@ pub enum InvalidProgramInfo<'tcx> { AlreadyReported(ReportedErrorInfo), /// An error occurred during layout computation. Layout(layout::LayoutError<'tcx>), - /// An error occurred during FnAbi computation: the passed --target lacks FFI support - /// (which unfortunately typeck does not reject). - /// Not using `FnAbiError` as that contains a nested `LayoutError`. - FnAbiAdjustForForeignAbi(rustc_target::callconv::AdjustForForeignAbiError), } /// Details of why a pointer had to be in-bounds. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 45c862e0d34b..c48cfffa05cc 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -20,7 +20,6 @@ use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; use tracing::{debug, trace}; // Also make the error macros available from this module. @@ -46,6 +45,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; +use crate::ty::print::with_no_trimmed_paths; use crate::ty::{self, Instance, Ty, TyCtxt}; /// Uniquely identifies one of the following: diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index 18c48d99b81c..748797fbb8d5 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -1,6 +1,7 @@ -use rustc_middle::mir::*; use tracing::debug; +use crate::mir::*; + /// This struct represents a patch to MIR, which can add /// new statements and basic blocks and patch over block /// terminators. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 11ebbbe807db..b0df6c71014a 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -5,17 +5,16 @@ use std::{fs, io}; use rustc_abi::Size; use rustc_ast::InlineAsmTemplatePiece; -use rustc_middle::mir::interpret::{ - AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range, - read_target_uint, -}; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::*; use tracing::trace; use ty::print::PrettyPrinter; use super::graphviz::write_mir_fn_graphviz; -use crate::mir::interpret::ConstAllocation; +use crate::mir::interpret::{ + AllocBytes, AllocId, Allocation, ConstAllocation, GlobalAlloc, Pointer, Provenance, + alloc_range, read_target_uint, +}; +use crate::mir::visit::Visitor; +use crate::mir::*; const INDENT: &str = " "; /// Alignment for lining up comments following MIR statements diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 14f871cbbdcb..cbd60920bc57 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -101,9 +101,9 @@ impl EraseType for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> { type Result = [u8; size_of::>>()]; } -impl EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> { +impl EraseType for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> { type Result = [u8; size_of::< - Result<(&'static (), rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed>, + Result<(&'static (), crate::thir::ExprId), rustc_errors::ErrorGuaranteed>, >()]; } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 3247bdbf1050..d9035efaf56d 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -11,12 +11,6 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, Stab use rustc_hir::definitions::DefPathHash; use rustc_index::{Idx, IndexVec}; use rustc_macros::{Decodable, Encodable}; -use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; -use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::mir::{self, interpret}; -use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; -use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::query::QuerySideEffects; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -30,6 +24,13 @@ use rustc_span::{ SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, }; +use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use crate::mir::mono::MonoItem; +use crate::mir::{self, interpret}; +use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; +use crate::ty::{self, Ty, TyCtxt}; + const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; // A normal span encoded with both location information and a `SyntaxContext` @@ -563,7 +564,7 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> { } } -rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); // This ensures that the `Decodable::decode` specialization for `Vec` is used // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 4dc8f2795535..2ab8750f727c 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -20,20 +20,21 @@ use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; use rustc_index::{IndexVec, newtype_index}; use rustc_macros::{HashStable, TypeVisitable}; -use rustc_middle::middle::region; -use rustc_middle::mir::interpret::AllocId; -use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp}; -use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{ - self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty, - TyCtxt, UpvarArgs, -}; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_target::asm::InlineAsmRegOrRegClass; use tracing::instrument; +use crate::middle::region; +use crate::mir::interpret::AllocId; +use crate::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp}; +use crate::ty::adjustment::PointerCoercion; +use crate::ty::layout::IntegerExt; +use crate::ty::{ + self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty, + TyCtxt, UpvarArgs, +}; + pub mod visit; macro_rules! thir_with_elements { diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 8cd04a6f5e40..4203c8fd8614 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -41,11 +41,18 @@ pub mod type_op { pub predicate: Predicate<'tcx>, } + /// Normalizes, but not in the new solver. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct Normalize { pub value: T, } + /// Normalizes, and deeply normalizes in the new solver. + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] + pub struct DeeplyNormalize { + pub value: T, + } + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct ImpliedOutlivesBounds<'tcx> { pub ty: Ty<'tcx>, @@ -80,6 +87,9 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>>; +pub type CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T> = + CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::DeeplyNormalize>>; + pub type CanonicalImpliedOutlivesBoundsGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::ImpliedOutlivesBounds<'tcx>>>; diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index b7cd545d02db..811bd8fb4588 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -168,6 +168,8 @@ pub enum SelectionCandidate<'tcx> { BuiltinObjectCandidate, BuiltinUnsizeCandidate, + + BikeshedGuaranteedNoDropCandidate, } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index e28fcc555dcd..b529d17540a8 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -217,6 +217,10 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { self.is_phantom_data() } + fn is_manually_drop(self) -> bool { + self.is_manually_drop() + } + fn all_field_tys( self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index b1316ceef5ac..10f7d5896362 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -2,8 +2,8 @@ // typeck and codegen. use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_middle::mir; +use crate::mir; use crate::ty::{self, Ty}; /// Types that are represented as ints. diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 94bf1aa4f035..6b6e0ffc6564 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -13,8 +13,6 @@ use std::marker::DiscriminantKind; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::ty::TyCtxt; use rustc_serialize::{Decodable, Encodable}; use rustc_span::Span; use rustc_span::source_map::Spanned; @@ -23,9 +21,10 @@ pub use rustc_type_ir::{TyDecoder, TyEncoder}; use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance}; +use crate::mir::mono::MonoItem; use crate::mir::{self}; use crate::traits; -use crate::ty::{self, AdtDef, GenericArgsRef, Ty}; +use crate::ty::{self, AdtDef, GenericArgsRef, Ty, TyCtxt}; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a9b4593c13da..9c07981a0275 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -690,6 +690,7 @@ bidirectional_lang_item_map! { AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, + BikeshedGuaranteedNoDrop, CallOnceFuture, CallRefFuture, Clone, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b7a648aae3f1..e9c19331e4a0 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -10,13 +10,13 @@ use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::FiniteBitSet; use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable}; -use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, Symbol}; use tracing::{debug, instrument}; use crate::error; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::print::{FmtPrinter, Printer, shrunk_instance_name}; use crate::ty::{ self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index e5015ea3c3d1..e5a4e38c8750 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -24,7 +24,6 @@ use rustc_target::spec::{ use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; -use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; @@ -369,7 +368,7 @@ impl<'tcx> SizeSkeleton<'tcx> { match *ty.kind() { ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { - let non_zero = !ty.is_unsafe_ptr(); + let non_zero = !ty.is_raw_ptr(); let tail = tcx.struct_tail_raw( pointee, @@ -841,7 +840,7 @@ where // as the `Abi` or `FieldsShape` is checked by users. if i == 0 { let nil = tcx.types.unit; - let unit_ptr_ty = if this.ty.is_unsafe_ptr() { + let unit_ptr_ty = if this.ty.is_raw_ptr() { Ty::new_mut_ptr(tcx, nil) } else { Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil) @@ -1275,18 +1274,12 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) pub enum FnAbiError<'tcx> { /// Error produced by a `layout_of` call, while computing `FnAbi` initially. Layout(LayoutError<'tcx>), - - /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI. - AdjustForForeignAbi(rustc_target::callconv::AdjustForForeignAbiError), } impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { match self { Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level), - Self::AdjustForForeignAbi( - rustc_target::callconv::AdjustForForeignAbiError::Unsupported { arch, abi }, - ) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diag(dcx, level), } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index feae8ea312ea..2c1adc2bcadd 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1512,7 +1512,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ExprKind::Binop(op) => { let (_, _, c1, c2) = expr.binop_args(); - let precedence = |binop: rustc_middle::mir::BinOp| { + let precedence = |binop: crate::mir::BinOp| { use rustc_ast::util::parser::AssocOp; AssocOp::from_ast_binop(binop.to_hir_binop()).precedence() }; @@ -1558,7 +1558,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ExprKind::UnOp(op) => { let (_, ct) = expr.unop_args(); - use rustc_middle::mir::UnOp; + use crate::mir::UnOp; let formatted_op = match op { UnOp::Not => "!", UnOp::Neg => "-", @@ -1800,7 +1800,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } let u8_type = self.tcx().types.u8; - match (cv.valtree, cv.ty.kind()) { + match (cv.valtree, *cv.ty.kind()) { (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() { ty::Slice(t) if *t == u8_type => { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { @@ -1820,13 +1820,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(()); } _ => { - let cv = ty::Value { valtree: cv.valtree, ty: *inner_ty }; + let cv = ty::Value { valtree: cv.valtree, ty: inner_ty }; p!("&"); p!(pretty_print_const_valtree(cv, print_ty)); return Ok(()); } }, - (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => { + (ty::ValTree::Branch(_), ty::Array(t, _)) if t == u8_type => { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!("expected to convert valtree to raw bytes for type {:?}", t) }); @@ -1893,11 +1893,16 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { p!(write("&")); - return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty); + return self.pretty_print_const_scalar_int(leaf, inner_ty, print_ty); } (ty::ValTree::Leaf(leaf), _) => { return self.pretty_print_const_scalar_int(leaf, cv.ty, print_ty); } + (_, ty::FnDef(def_id, args)) => { + // Never allowed today, but we still encounter them in invalid const args. + p!(print_value_path(def_id, args)); + return Ok(()); + } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading // their fields instead of just dumping the memory. _ => {} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a9a47c87a388..8a31b2960188 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1199,7 +1199,7 @@ impl<'tcx> Ty<'tcx> { } #[inline] - pub fn is_unsafe_ptr(self) -> bool { + pub fn is_raw_ptr(self) -> bool { matches!(self.kind(), RawPtr(_, _)) } @@ -1207,7 +1207,7 @@ impl<'tcx> Ty<'tcx> { /// `Box` is *not* considered a pointer here! #[inline] pub fn is_any_ptr(self) -> bool { - self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr() + self.is_ref() || self.is_raw_ptr() || self.is_fn_ptr() } #[inline] @@ -1394,7 +1394,7 @@ impl<'tcx> Ty<'tcx> { /// Returns the type and mutability of `*ty`. /// /// The parameter `explicit` indicates if this is an *explicit* dereference. - /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. + /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(self, explicit: bool) -> Option> { match *self.kind() { _ if let Some(boxed) = self.boxed_ty() => Some(boxed), diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 49bdb5e9dc31..1b5b791bb24a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -14,13 +14,13 @@ use rustc_hir::{ }; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; use super::RvalueScopes; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::Canonical; +use crate::mir::FakeReadCause; use crate::traits::ObligationCause; use crate::ty::{ self, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs, diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs index 8c875007b7fb..85519fb0a7d2 100644 --- a/compiler/rustc_middle/src/util/mod.rs +++ b/compiler/rustc_middle/src/util/mod.rs @@ -2,9 +2,9 @@ pub mod bug; #[derive(Default, Copy, Clone)] pub struct Providers { - pub queries: rustc_middle::query::Providers, - pub extern_queries: rustc_middle::query::ExternProviders, - pub hooks: rustc_middle::hooks::Providers, + pub queries: crate::query::Providers, + pub extern_queries: crate::query::ExternProviders, + pub hooks: crate::hooks::Providers, } /// Backwards compatibility hack to keep the diff small. This @@ -17,7 +17,7 @@ impl std::ops::DerefMut for Providers { } impl std::ops::Deref for Providers { - type Target = rustc_middle::query::Providers; + type Target = crate::query::Providers; fn deref(&self) -> &Self::Target { &self.queries diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 867f8f639698..433f7542bd70 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -7,7 +7,6 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; use rustc_query_system::Value; use rustc_query_system::query::{CycleError, report_cycle}; use rustc_span::def_id::LocalDefId; @@ -15,6 +14,7 @@ use rustc_span::{ErrorGuaranteed, Span}; use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; +use crate::ty::{self, Representability, Ty, TyCtxt}; impl<'tcx> Value> for Ty<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 2b9b948763f9..1bd33475e607 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -554,7 +554,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { _ => self.requires_unsafe(expr.span, UseOfExternStatic), } } - } else if self.thir[arg].ty.is_unsafe_ptr() { + } else if self.thir[arg].ty.is_raw_ptr() { self.requires_unsafe(expr.span, DerefOfRawPointer); } } diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index ccaa83fd9e27..d693f739180f 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -190,7 +190,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { let pointer_ty = self.local_decls[place.local].ty; // We only want to check places based on raw pointers - if !pointer_ty.is_unsafe_ptr() { + if !pointer_ty.is_raw_ptr() { trace!("Indirect, but not based on an raw ptr, not checking {:?}", place); return; } diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs index 8ba14a1158ef..ed3b1ae4f42f 100644 --- a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs +++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs @@ -47,7 +47,7 @@ impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> { { let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); if let [input] = fn_sig.inputs() { - return input.is_unsafe_ptr() && fn_sig.output().is_integral(); + return input.is_raw_ptr() && fn_sig.output().is_integral(); } } false diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs deleted file mode 100644 index 63257df66fb9..000000000000 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ /dev/null @@ -1,195 +0,0 @@ -//! This pass finds basic blocks that are completely equal, -//! and replaces all uses with just one of them. - -use std::collections::hash_map::Entry; -use std::hash::{Hash, Hasher}; -use std::iter; - -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use tracing::debug; - -use super::simplify::simplify_cfg; - -pub(super) struct DeduplicateBlocks; - -impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks { - fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 4 - } - - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("Running DeduplicateBlocks on `{:?}`", body.source); - let duplicates = find_duplicates(body); - let has_opts_to_apply = !duplicates.is_empty(); - - if has_opts_to_apply { - let mut opt_applier = OptApplier { tcx, duplicates }; - opt_applier.visit_body(body); - simplify_cfg(body); - } - } - - fn is_required(&self) -> bool { - false - } -} - -struct OptApplier<'tcx> { - tcx: TyCtxt<'tcx>, - duplicates: FxHashMap, -} - -impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - for target in terminator.successors_mut() { - if let Some(replacement) = self.duplicates.get(target) { - debug!("SUCCESS: Replacing: `{:?}` with `{:?}`", target, replacement); - *target = *replacement; - } - } - - self.super_terminator(terminator, location); - } -} - -fn find_duplicates(body: &Body<'_>) -> FxHashMap { - let mut duplicates = FxHashMap::default(); - - let bbs_to_go_through = - body.basic_blocks.iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count(); - - let mut same_hashes = - FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default()); - - // Go through the basic blocks backwards. This means that in case of duplicates, - // we can use the basic block with the highest index as the replacement for all lower ones. - // For example, if bb1, bb2 and bb3 are duplicates, we will first insert bb3 in same_hashes. - // Then we will see that bb2 is a duplicate of bb3, - // and insert bb2 with the replacement bb3 in the duplicates list. - // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the - // duplicates list with replacement bb3. - // When the duplicates are removed, we will end up with only bb3. - for (bb, bbd) in body.basic_blocks.iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) { - // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks - // that are unlikely to have duplicates, we stop early. The early bail number has been - // found experimentally by eprintln while compiling the crates in the rustc-perf suite. - if bbd.statements.len() > 10 { - continue; - } - - let to_hash = BasicBlockHashable { basic_block_data: bbd }; - let entry = same_hashes.entry(to_hash); - match entry { - Entry::Occupied(occupied) => { - // The basic block was already in the hashmap, which means we have a duplicate - let value = *occupied.get(); - debug!("Inserting {:?} -> {:?}", bb, value); - duplicates.try_insert(bb, value).expect("key was already inserted"); - } - Entry::Vacant(vacant) => { - vacant.insert(bb); - } - } - } - - duplicates -} - -struct BasicBlockHashable<'a, 'tcx> { - basic_block_data: &'a BasicBlockData<'tcx>, -} - -impl Hash for BasicBlockHashable<'_, '_> { - fn hash(&self, state: &mut H) { - hash_statements(state, self.basic_block_data.statements.iter()); - // Note that since we only hash the kind, we lose span information if we deduplicate the - // blocks. - self.basic_block_data.terminator().kind.hash(state); - } -} - -impl Eq for BasicBlockHashable<'_, '_> {} - -impl PartialEq for BasicBlockHashable<'_, '_> { - fn eq(&self, other: &Self) -> bool { - self.basic_block_data.statements.len() == other.basic_block_data.statements.len() - && &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind - && iter::zip(&self.basic_block_data.statements, &other.basic_block_data.statements) - .all(|(x, y)| statement_eq(&x.kind, &y.kind)) - } -} - -fn hash_statements<'a, 'tcx, H: Hasher>( - hasher: &mut H, - iter: impl Iterator>, -) where - 'tcx: 'a, -{ - for stmt in iter { - statement_hash(hasher, &stmt.kind); - } -} - -fn statement_hash(hasher: &mut H, stmt: &StatementKind<'_>) { - match stmt { - StatementKind::Assign(box (place, rvalue)) => { - place.hash(hasher); - rvalue_hash(hasher, rvalue) - } - x => x.hash(hasher), - }; -} - -fn rvalue_hash(hasher: &mut H, rvalue: &Rvalue<'_>) { - match rvalue { - Rvalue::Use(op) => operand_hash(hasher, op), - x => x.hash(hasher), - }; -} - -fn operand_hash(hasher: &mut H, operand: &Operand<'_>) { - match operand { - Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }) => const_.hash(hasher), - x => x.hash(hasher), - }; -} - -fn statement_eq<'tcx>(lhs: &StatementKind<'tcx>, rhs: &StatementKind<'tcx>) -> bool { - let res = match (lhs, rhs) { - ( - StatementKind::Assign(box (place, rvalue)), - StatementKind::Assign(box (place2, rvalue2)), - ) => place == place2 && rvalue_eq(rvalue, rvalue2), - (x, y) => x == y, - }; - debug!("statement_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); - res -} - -fn rvalue_eq<'tcx>(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool { - let res = match (lhs, rhs) { - (Rvalue::Use(op1), Rvalue::Use(op2)) => operand_eq(op1, op2), - (x, y) => x == y, - }; - debug!("rvalue_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); - res -} - -fn operand_eq<'tcx>(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool { - let res = match (lhs, rhs) { - ( - Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }), - Operand::Constant(box ConstOperand { user_ty: _, const_: const2, span: _ }), - ) => const_ == const2, - (x, y) => x == y, - }; - debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); - res -} diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 7e88925b2e1b..73e47bb79f0b 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -161,12 +161,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { let unsafety = fn_sig.safety().prefix_str(); let abi = match fn_sig.abi() { ExternAbi::Rust => String::from(""), - other_abi => { - let mut s = String::from("extern \""); - s.push_str(other_abi.name()); - s.push_str("\" "); - s - } + other_abi => format!("extern {other_abi} "), }; let ident = self.tcx.item_ident(fn_id); let ty_params = fn_args.types().map(|ty| format!("{ty}")); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 1a2120ecd710..77a3854ebdef 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1397,8 +1397,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // or `*mut [i32]` <=> `*const [u64]`), including the common special // case of `*const T` <=> `*mut T`. if let Transmute = kind - && from.is_unsafe_ptr() - && to.is_unsafe_ptr() + && from.is_raw_ptr() + && to.is_raw_ptr() && self.pointers_have_same_metadata(from, to) { kind = PtrToPtr; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b572f6ca0b36..397d21a857f0 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -135,7 +135,6 @@ declare_passes! { Initial, Final }; - mod deduplicate_blocks : DeduplicateBlocks; mod deref_separator : Derefer; mod dest_prop : DestinationPropagation; pub mod dump_mir : Marker; @@ -700,7 +699,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &nrvo::RenameReturnPlace, &simplify::SimplifyLocals::Final, &multiple_return_terminators::MultipleReturnTerminators, - &deduplicate_blocks::DeduplicateBlocks, &large_enums::EnumSizeOpt { discrepancy: 128 }, // Some cleanup necessary at least for LLVM and potentially other codegen backends. &add_call_guards::CriticalCallEdges, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index d0b01b14d635..a3274fb40115 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -267,6 +267,11 @@ where goal: Goal, ) -> Result, NoSolution>; + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution>; + /// Consider (possibly several) candidates to upcast or unsize a type to another /// type, excluding the coercion of a sized type into a `dyn Trait`. /// @@ -478,6 +483,9 @@ where Some(TraitSolverLangItem::TransmuteTrait) => { G::consider_builtin_transmute_candidate(self, goal) } + Some(TraitSolverLangItem::BikeshedGuaranteedNoDrop) => { + G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal) + } _ => Err(NoSolution), } }; diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index fb53e778e603..eb398e8724d4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -374,6 +374,13 @@ where unreachable!("TransmuteFrom is not const") } + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("BikeshedGuaranteedNoDrop is not const"); + } + fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c8ea0b119ffb..1d0ec7b45ca1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -942,6 +942,13 @@ where ) -> Result, NoSolution> { panic!("`TransmuteFrom` does not have an associated type: {:?}", goal) } + + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + _ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution> { + unreachable!("`BikeshedGuaranteedNoDrop` does not have an associated type: {:?}", goal) + } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 46fae5c6fa46..dabfa5cc04c8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -625,6 +625,101 @@ where }) } + /// NOTE: This is implemented as a built-in goal and not a set of impls like: + /// + /// ```rust,ignore (illustrative) + /// impl BikeshedGuaranteedNoDrop for T where T: Copy {} + /// impl BikeshedGuaranteedNoDrop for ManuallyDrop {} + /// ``` + /// + /// because these impls overlap, and I'd rather not build a coherence hack for + /// this harmless overlap. + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution> { + if goal.predicate.polarity != ty::PredicatePolarity::Positive { + return Err(NoSolution); + } + + let cx = ecx.cx(); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let ty = goal.predicate.self_ty(); + match ty.kind() { + // `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`. + ty::Ref(..) => {} + // `ManuallyDrop` always implements `BikeshedGuaranteedNoDrop`. + ty::Adt(def, _) if def.is_manually_drop() => {} + // Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if + // their constituent types implement `BikeshedGuaranteedNoDrop`. + ty::Tuple(tys) => { + ecx.add_goals( + GoalSource::ImplWhereBound, + tys.iter().map(|elem_ty| { + goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])) + }), + ); + } + ty::Array(elem_ty, _) => { + ecx.add_goal( + GoalSource::ImplWhereBound, + goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])), + ); + } + + // All other types implement `BikeshedGuaranteedNoDrop` only if + // they implement `Copy`. We could be smart here and short-circuit + // some trivially `Copy`/`!Copy` types, but there's no benefit. + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Adt(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) => { + ecx.add_goal( + GoalSource::ImplWhereBound, + goal.with( + cx, + ty::TraitRef::new( + cx, + cx.require_lang_item(TraitSolverLangItem::Copy), + [ty], + ), + ), + ); + } + + ty::Bound(..) + | ty::Infer( + ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), + ) => { + panic!("unexpected type `{ty:?}`") + } + } + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + /// ```ignore (builtin impl example) /// trait Trait { /// fn foo(&self); diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 86816819be27..11f0e579de5a 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -302,26 +302,16 @@ impl<'a> Parser<'a> { pub(super) fn parse_contract( &mut self, ) -> PResult<'a, Option>> { - let gate = |span| { - if self.psess.contract_attribute_spans.contains(span) { - // span was generated via a builtin contracts attribute, so gate as end-user visible - self.psess.gated_spans.gate(sym::contracts, span); - } else { - // span was not generated via a builtin contracts attribute, so gate as internal machinery - self.psess.gated_spans.gate(sym::contracts_internals, span); - } - }; - let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { + self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let precond = self.parse_expr()?; - gate(precond.span); Some(precond) } else { None }; let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) { + self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let postcond = self.parse_expr()?; - gate(postcond.span); Some(postcond) } else { None diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 2b8a3b9ce235..f592a12ab75c 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } +rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 4601bb87b76f..671b7d7ad76c 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -46,15 +46,6 @@ fn unwrap_fn_abi<'tcx>( span: tcx.def_span(item_def_id), }); } - Err(FnAbiError::AdjustForForeignAbi(e)) => { - // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if - // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE - // isn't the worst thing. Also this matches what codegen does. - span_bug!( - tcx.def_span(item_def_id), - "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", - ) - } } } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 1e165b22e51c..875b6edb58cb 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,5 +1,6 @@ //! Checks validity of naked functions. +use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; @@ -11,7 +12,6 @@ use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_span::{Span, sym}; -use rustc_target::spec::abi::Abi; use crate::errors::{ NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, @@ -61,8 +61,8 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { } /// Checks that function uses non-Rust ABI. -fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) { - if abi == Abi::Rust { +fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: ExternAbi) { + if abi == ExternAbi::Rust { let hir_id = tcx.local_def_id_to_hir_id(def_id); let span = tcx.def_span(def_id); tcx.emit_node_span_lint( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 34f1ca55c787..fd30d0d4867f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -4,6 +4,7 @@ use std::mem::replace; use std::num::NonZero; +use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_parsing::{ self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, @@ -1027,8 +1028,8 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { if let TyKind::Never = t.kind { self.fully_stable = false; } - if let TyKind::BareFn(f) = t.kind { - if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() { + if let TyKind::BareFn(function) = t.kind { + if extern_abi_stability(function.abi).is_err() { self.fully_stable = false; } } diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 96b210accdb3..a42329b4614f 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 480fd4977283..7d508b8201bd 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_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8d42b478647d..5db6f83f3ee5 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1127,7 +1127,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); // Make sure error reporting is deterministic. - suggestions.sort_by(|a, b| a.candidate.as_str().partial_cmp(b.candidate.as_str()).unwrap()); + suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str())); match find_best_match_for_name( &suggestions.iter().map(|suggestion| suggestion.candidate).collect::>(), @@ -2256,14 +2256,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { - match (path.get(0), path.get(1)) { + match path[..] { // `{{root}}::ident::...` on both editions. // On 2015 `{{root}}` is usually added implicitly. - (Some(fst), Some(snd)) - if fst.ident.name == kw::PathRoot && !snd.ident.is_path_segment_keyword() => {} + [first, second, ..] + if first.ident.name == kw::PathRoot && !second.ident.is_path_segment_keyword() => {} // `ident::...` on 2018. - (Some(fst), _) - if fst.ident.span.at_least_rust_2018() && !fst.ident.is_path_segment_keyword() => + [first, ..] + if first.ident.span.at_least_rust_2018() + && !first.ident.is_path_segment_keyword() => { // Insert a placeholder that's later replaced by `self`/`super`/etc. path.insert(0, Segment::from_ident(Ident::empty())); @@ -2374,7 +2375,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 2) `std` suggestions before `core` suggestions. let mut extern_crate_names = self.extern_prelude.keys().map(|ident| ident.name).collect::>(); - extern_crate_names.sort_by(|a, b| b.as_str().partial_cmp(a.as_str()).unwrap()); + extern_crate_names.sort_by(|a, b| b.as_str().cmp(a.as_str())); for name in extern_crate_names.into_iter() { // Replace first ident with a crate name and check if that is valid. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 508bd831ccbe..03aeb8720ca6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -923,6 +923,21 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.diag_metadata.current_trait_object = prev; self.diag_metadata.current_type_path = prev_ty; } + + fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result { + match &t.kind { + TyPatKind::Range(start, end, _) => { + if let Some(start) = start { + self.resolve_anon_const(start, AnonConstKind::ConstArg(IsRepeatExpr::No)); + } + if let Some(end) = end { + self.resolve_anon_const(end, AnonConstKind::ConstArg(IsRepeatExpr::No)); + } + } + TyPatKind::Err(_) => {} + } + } + fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef) { let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo()); self.with_generic_param_rib( diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 4762281c329a..aa9ebdd9cead 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -9,7 +9,7 @@ //! //! ## Adding a new cfg //! -//! Adding a new feature requires two new symbols one for the cfg it-self +//! Adding a new feature requires two new symbols one for the cfg itself //! and the second one for the unstable feature gate, those are defined in //! `rustc_span::symbol`. //! diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index d4db05ce139f..e0405a71f65a 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -208,10 +208,6 @@ pub struct ParseSess { pub config: Cfg, pub check_config: CheckCfg, pub edition: Edition, - /// Places where contract attributes were expanded into unstable AST forms. - /// This is used to allowlist those spans (so that we only check them against the feature - /// gate for the externally visible interface, and not internal implmentation machinery). - pub contract_attribute_spans: AppendOnlyVec, /// Places where raw identifiers were used. This is used to avoid complaining about idents /// clashing with keywords in new editions. pub raw_identifier_spans: AppendOnlyVec, @@ -260,7 +256,6 @@ impl ParseSess { config: Cfg::default(), check_config: CheckCfg::default(), edition: ExpnId::root().expn_data().edition, - contract_attribute_spans: Default::default(), raw_identifier_spans: Default::default(), bad_unicode_identifiers: Lock::new(Default::default()), source_map, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6eb2cdc4e11f..e93a722ccc09 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -193,6 +193,7 @@ symbols! { Cleanup, Clone, CoercePointee, + CoercePointeeValidated, CoerceUnsized, Command, ConstParamTy, @@ -514,6 +515,7 @@ symbols! { bang, begin_panic, bench, + bikeshed_guaranteed_no_drop, bin, binaryheap_iter, bind_by_move_pattern_guards, @@ -619,6 +621,7 @@ symbols! { cmp_partialord_lt, cmpxchg16b_target_feature, cmse_nonsecure_entry, + coerce_pointee_validated, coerce_unsized, cold, cold_path, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0ac6f17b97bd..4fafd1ac3509 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/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 0a4ffb152195..9f791603c723 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -39,12 +39,12 @@ macro_rules! def_reg_class { } } - pub fn parse(name: rustc_span::Symbol) -> Result { + pub fn parse(name: rustc_span::Symbol) -> Result { match name { $( rustc_span::sym::$class => Ok(Self::$class), )* - _ => Err("unknown register class"), + _ => Err(&[$(rustc_span::sym::$class),*]), } } } @@ -635,7 +635,7 @@ impl InlineAsmRegClass { } } - pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result { + pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result { Ok(match arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 => { Self::X86(X86InlineAsmRegClass::parse(name)?) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 50ac6c8fcde1..b49dd2588692 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -6,7 +6,6 @@ use rustc_abi::{ Size, TyAbiInterface, TyAndLayout, }; use rustc_macros::HashStable_Generic; -use rustc_span::Symbol; use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; @@ -623,19 +622,8 @@ impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> { } } -/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI. -#[derive(Copy, Clone, Debug, HashStable_Generic)] -pub enum AdjustForForeignAbiError { - /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs. - Unsupported { arch: Symbol, abi: ExternAbi }, -} - impl<'a, Ty> FnAbi<'a, Ty> { - pub fn adjust_for_foreign_abi( - &mut self, - cx: &C, - abi: ExternAbi, - ) -> Result<(), AdjustForForeignAbiError> + pub fn adjust_for_foreign_abi(&mut self, cx: &C, abi: ExternAbi) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt, @@ -644,7 +632,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { if let Some(arg) = self.args.first_mut() { arg.pass_by_stack_offset(None); } - return Ok(()); + return; } let spec = cx.target_spec(); @@ -719,15 +707,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { } "wasm64" => wasm::compute_c_abi_info(cx, self), "bpf" => bpf::compute_abi_info(self), - arch => { - return Err(AdjustForForeignAbiError::Unsupported { - arch: Symbol::intern(arch), - abi, - }); - } + arch => panic!("no lowering implemented for {arch}"), } - - Ok(()) } pub fn adjust_for_rust_abi(&mut self, cx: &C, abi: ExternAbi) diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index bde4af643fa6..7ebe96960ed0 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_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index df1862ec27ee..7e84127c93a6 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -57,13 +57,6 @@ use crate::spec::crt_objects::CrtObjects; pub mod crt_objects; -pub mod abi { - pub use rustc_abi::{ - AbiDisabled, AbiUnsupported, ExternAbi as Abi, all_names, enabled_names, is_enabled, - is_stable, lookup, - }; -} - mod base; mod json; @@ -1797,7 +1790,7 @@ supported_targets! { ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), ("aarch64-unknown-redox", aarch64_unknown_redox), - ("i686-unknown-redox", i686_unknown_redox), + ("i586-unknown-redox", i586_unknown_redox), ("x86_64-unknown-redox", x86_64_unknown_redox), ("i386-apple-ios", i386_apple_ios), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs similarity index 94% rename from compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs rename to compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs index bfe52a330d30..29ef8b883a11 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs @@ -10,7 +10,7 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Call; Target { - llvm_target: "i686-unknown-redox".into(), + llvm_target: "i586-unknown-redox".into(), metadata: crate::spec::TargetMetadata { description: None, tier: None, diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs index dcf9b6b4460f..1b8f4c1be2df 100644 --- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { base.max_atomic_width = Some(64); // https://developer.android.com/ndk/guides/abis.html#x86 - base.cpu = "pentiumpro".into(); + base.cpu = "pentium4".into(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".into(); base.stack_probes = StackProbeType::Inline; diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index ea7c15a35953..1ba8defedae1 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -145,6 +145,7 @@ static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("dotprod", Unstable(sym::arm_target_feature), &["neon"]), ("dsp", Unstable(sym::arm_target_feature), &[]), ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]), + ("fp16", Unstable(sym::arm_target_feature), &["neon"]), ("fpregs", Unstable(sym::arm_target_feature), &[]), ("i8mm", Unstable(sym::arm_target_feature), &["neon"]), ("mclass", Unstable(sym::arm_target_feature), &[]), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 99b70c87ccd1..9e7e96dddd7c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -18,6 +18,8 @@ use rustc_middle::ty::{ TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, }; use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym}; +use rustc_type_ir::inherent::*; +use rustc_type_ir::visit::TypeVisitableExt; use tracing::{debug, instrument, warn}; use super::nice_region_error::placeholder_error::Highlighted; @@ -155,27 +157,92 @@ impl UnderspecifiedArgKind { } } -struct ClosureEraser<'tcx> { - tcx: TyCtxt<'tcx>, +struct ClosureEraser<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, } -impl<'tcx> TypeFolder> for ClosureEraser<'tcx> { +impl<'a, 'tcx> ClosureEraser<'a, 'tcx> { + fn new_infer(&mut self) -> Ty<'tcx> { + self.infcx.next_ty_var(DUMMY_SP) + } +} + +impl<'a, 'tcx> TypeFolder> for ClosureEraser<'a, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.tcx + self.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { match ty.kind() { ty::Closure(_, args) => { + // For a closure type, we turn it into a function pointer so that it gets rendered + // as `fn(args) -> Ret`. let closure_sig = args.as_closure().sig(); Ty::new_fn_ptr( - self.tcx, - self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe), + self.cx(), + self.cx().signature_unclosure(closure_sig, hir::Safety::Safe), ) } - _ => ty.super_fold_with(self), + ty::Adt(_, args) if !args.iter().any(|a| a.has_infer()) => { + // We have a type that doesn't have any inference variables, so we replace + // the whole thing with `_`. The type system already knows about this type in + // its entirety and it is redundant to specify it for the user. The user only + // needs to specify the type parameters that we *couldn't* figure out. + self.new_infer() + } + ty::Adt(def, args) => { + let generics = self.cx().generics_of(def.did()); + let generics: Vec = generics + .own_params + .iter() + .map(|param| param.default_value(self.cx()).is_some()) + .collect(); + let ty = Ty::new_adt( + self.cx(), + *def, + self.cx().mk_args_from_iter(generics.into_iter().zip(args.iter()).map( + |(has_default, arg)| { + if arg.has_infer() { + // This param has an unsubstituted type variable, meaning that this + // type has a (potentially deeply nested) type parameter from the + // corresponding type's definition. We have explicitly asked this + // type to not be hidden. In either case, we keep the type and don't + // substitute with `_` just yet. + arg.fold_with(self) + } else if has_default { + // We have a type param that has a default type, like the allocator + // in Vec. We decided to show `Vec` itself, because it hasn't yet + // been replaced by an `_` `Infer`, but we want to ensure that the + // type parameter with default types does *not* get replaced with + // `_` because then we'd end up with `Vec<_, _>`, instead of + // `Vec<_>`. + arg + } else if let GenericArgKind::Type(_) = arg.kind() { + // We don't replace lifetime or const params, only type params. + self.new_infer().into() + } else { + arg.fold_with(self) + } + }, + )), + ); + ty + } + _ if ty.has_infer() => { + // This type has a (potentially nested) type parameter that we couldn't figure out. + // We will print this depth of type, so at least the type name and at least one of + // its type parameters. + ty.super_fold_with(self) + } + // We don't have an unknown type parameter anywhere, replace with `_`. + _ => self.new_infer(), } } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + // Avoid accidentally erasing the type of the const. + c + } } fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> { @@ -219,9 +286,9 @@ fn ty_to_string<'tcx>( ) -> String { let mut printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); - // We use `fn` ptr syntax for closures, but this only works when the closure - // does not capture anything. - let ty = ty.fold_with(&mut ClosureEraser { tcx: infcx.tcx }); + // We use `fn` ptr syntax for closures, but this only works when the closure does not capture + // anything. We also remove all type parameters that are fully known to the type system. + let ty = ty.fold_with(&mut ClosureEraser { infcx }); match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index e8c2528aa6ee..2f6bbd7f4cf4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -2,7 +2,7 @@ use std::fmt; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -pub use rustc_middle::traits::query::type_op::Normalize; +pub use rustc_middle::traits::query::type_op::{DeeplyNormalize, Normalize}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -27,13 +27,54 @@ where T::type_op_method(tcx, canonicalized) } + fn perform_locally_with_next_solver( + _ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + _span: Span, + ) -> Result { + Ok(key.value.value) + } +} + +impl<'tcx, T> super::QueryTypeOp<'tcx> for DeeplyNormalize +where + T: Normalizable<'tcx> + 'tcx, +{ + type QueryResponse = T; + + fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option { + if !key.value.value.has_aliases() { Some(key.value.value) } else { None } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Result, NoSolution> { + T::type_op_method( + tcx, + CanonicalQueryInput { + typing_mode: canonicalized.typing_mode, + canonical: canonicalized.canonical.unchecked_map( + |ty::ParamEnvAnd { param_env, value }| ty::ParamEnvAnd { + param_env, + value: Normalize { value: value.value }, + }, + ), + }, + ) + } + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, span: Span, ) -> Result { - // FIXME(-Znext-solver): shouldn't be using old normalizer - Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value)) + ocx.deeply_normalize( + &ObligationCause::dummy_with_span(span), + key.param_env, + key.value.value, + ) + .map_err(|_| NoSolution) } } @@ -81,3 +122,14 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> { tcx.type_op_normalize_fn_sig(canonicalized) } } + +/// This impl is not needed, since we never normalize type outlives predicates +/// in the old solver, but is required by trait bounds to be happy. +impl<'tcx> Normalizable<'tcx> for ty::PolyTypeOutlivesPredicate<'tcx> { + fn type_op_method( + _tcx: TyCtxt<'tcx>, + _canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Result, NoSolution> { + unreachable!("we never normalize PolyTypeOutlivesPredicate") + } +} 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 e495bdbf7825..5b362b2356e8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -102,6 +102,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidate_for_tuple(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); + } else if tcx.is_lang_item(def_id, LangItem::BikeshedGuaranteedNoDrop) { + self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + obligation, + &mut candidates, + ); } else { if tcx.is_lang_item(def_id, LangItem::Clone) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -920,11 +925,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"); @@ -1183,4 +1189,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match obligation.predicate.self_ty().skip_binder().kind() { + ty::Ref(..) + | ty::Adt(..) + | ty::Tuple(_) + | ty::Array(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) + | ty::Bound(..) => { + candidates.vec.push(BikeshedGuaranteedNoDropCandidate); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + candidates.ambiguous = true; + } + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index eb4adde716a0..32cbb97e314d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_type_ir::elaborate; +use thin_vec::thin_vec; use tracing::{debug, instrument}; use super::SelectionCandidate::{self, *}; @@ -130,6 +131,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitUpcastingUnsizeCandidate(idx) => { self.confirm_trait_upcasting_unsize_candidate(obligation, idx)? } + + BikeshedGuaranteedNoDropCandidate => { + self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation) + } }; // The obligations returned by confirmation are recursively evaluated @@ -1346,6 +1351,93 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("source: {source}, target: {target}"), }) } + + fn confirm_bikeshed_guaranteed_no_drop_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> ImplSource<'tcx, PredicateObligation<'tcx>> { + let mut obligations = thin_vec![]; + + let tcx = self.tcx(); + let self_ty = obligation.predicate.self_ty(); + match *self_ty.skip_binder().kind() { + // `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`. + ty::Ref(..) => {} + // `ManuallyDrop` always implements `BikeshedGuaranteedNoDrop`. + ty::Adt(def, _) if def.is_manually_drop() => {} + // Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if + // their constituent types implement `BikeshedGuaranteedNoDrop`. + ty::Tuple(tys) => { + obligations.extend(tys.iter().map(|elem_ty| { + obligation.with( + tcx, + self_ty.rebind(ty::TraitRef::new( + tcx, + obligation.predicate.def_id(), + [elem_ty], + )), + ) + })); + } + ty::Array(elem_ty, _) => { + obligations.push(obligation.with( + tcx, + self_ty.rebind(ty::TraitRef::new( + tcx, + obligation.predicate.def_id(), + [elem_ty], + )), + )); + } + + // All other types implement `BikeshedGuaranteedNoDrop` only if + // they implement `Copy`. We could be smart here and short-circuit + // some trivially `Copy`/`!Copy` types, but there's no benefit. + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Adt(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) + | ty::Bound(..) => { + obligations.push(obligation.with( + tcx, + self_ty.map_bound(|ty| { + ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)), + [ty], + ) + }), + )); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } + + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) + } } /// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6b1e1774f035..436ce3dddd9f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1949,7 +1949,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitAliasCandidate | TraitUpcastingUnsizeCandidate(_) | BuiltinObjectCandidate - | BuiltinUnsizeCandidate => false, + | BuiltinUnsizeCandidate + | BikeshedGuaranteedNoDropCandidate => false, // Non-global param candidates have already been handled, global // where-bounds get ignored. ParamCandidate(_) | ImplCandidate(_) => true, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index c27bd269b0d9..2f72b44f6b62 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -881,7 +881,10 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty.map_bound(|ty| { ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Copy, Some(self.span)), + self.tcx().require_lang_item( + LangItem::BikeshedGuaranteedNoDrop, + Some(self.span), + ), [ty], ) }), diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 169f3a78c26a..df30872c4374 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -650,7 +650,7 @@ fn fn_abi_new_uncached<'tcx>( conv, can_unwind: fn_can_unwind(cx.tcx(), fn_def_id, sig.abi), }; - fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?; + fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id); debug!("fn_abi_new_uncached = {:?}", fn_abi); fn_abi_sanity_check(cx, &fn_abi, sig.abi); Ok(tcx.arena.alloc(fn_abi)) @@ -662,7 +662,7 @@ fn fn_abi_adjust_for_abi<'tcx>( fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, abi: ExternAbi, fn_def_id: Option, -) -> Result<(), &'tcx FnAbiError<'tcx>> { +) { if abi == ExternAbi::Unadjusted { // The "unadjusted" ABI passes aggregates in "direct" mode. That's fragile but needed for // some LLVM intrinsics. @@ -682,7 +682,7 @@ fn fn_abi_adjust_for_abi<'tcx>( for arg in fn_abi.args.iter_mut() { unadjust(arg); } - return Ok(()); + return; } let tcx = cx.tcx(); @@ -723,12 +723,8 @@ fn fn_abi_adjust_for_abi<'tcx>( } } } else { - fn_abi - .adjust_for_foreign_abi(cx, abi) - .map_err(|err| &*tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?; + fn_abi.adjust_for_foreign_abi(cx, abi); } - - Ok(()) } #[tracing::instrument(level = "debug", skip(cx))] @@ -753,7 +749,7 @@ fn make_thin_self_ptr<'tcx>( // To get the type `*mut RcInner`, we just keep unwrapping newtypes until we // get a built-in pointer type let mut wide_pointer_layout = layout; - while !wide_pointer_layout.ty.is_unsafe_ptr() && !wide_pointer_layout.ty.is_ref() { + while !wide_pointer_layout.ty.is_raw_ptr() && !wide_pointer_layout.ty.is_ref() { wide_pointer_layout = wide_pointer_layout .non_1zst_field(cx) .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type") diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index ce8dc3a2515d..ee271048fc17 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -269,7 +269,7 @@ fn layout_of_uncached<'tcx>( // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA)); - if !ty.is_unsafe_ptr() { + if !ty.is_raw_ptr() { data_ptr.valid_range_mut().start = 1; } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 4e6d645e6fae..6924216bd26e 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -540,6 +540,8 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { fn is_phantom_data(self) -> bool; + fn is_manually_drop(self) -> bool; + // FIXME: perhaps use `all_fields` and expose `FieldDef`. fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index eeb80bc3ab42..65f7cdf8f922 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -10,6 +10,7 @@ pub enum TraitSolverLangItem { AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, + BikeshedGuaranteedNoDrop, CallOnceFuture, CallRefFuture, Clone, diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index dc2312b2da3a..e42639c68075 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -1,10 +1,10 @@ -pub use rustc_type_ir::relate::*; -use rustc_type_ir::solve::Goal; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; use tracing::{debug, instrument}; use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combine_tys}; use crate::data_structures::DelayedSet; +pub use crate::relate::*; +use crate::solve::Goal; +use crate::{self as ty, InferCtxtLike, Interner}; pub trait RelateExt: InferCtxtLike { fn relate>( diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 3434597e7b05..9ef80edb82a6 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -489,7 +489,7 @@ impl TyKind { /// Returns the type and mutability of `*ty` for builtin types. /// /// The parameter `explicit` indicates if this is an *explicit* dereference. - /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. + /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(&self, explicit: bool) -> Option { match self.rigid()? { RigidTy::Adt(def, args) if def.is_box() => { diff --git a/config.example.toml b/config.example.toml index 7f6bbf279928..1a8f42428ab8 100644 --- a/config.example.toml +++ b/config.example.toml @@ -323,7 +323,7 @@ #full-bootstrap = false # Set the bootstrap/download cache path. It is useful when building rust -# repeatedly in a CI invironment. +# repeatedly in a CI environment. #bootstrap-cache-path = /path/to/shared/cache # Enable a build of the extended Rust tool set which is not only the compiler diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index dcab6136ae8a..9805cee1c331 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -94,7 +94,7 @@ impl fmt::Display for AllocError { /// - the memory block is deallocated, or /// - the allocator is dropped. /// -/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it +/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it. /// A copied or cloned allocator must behave like the original allocator. /// /// A memory block which is [*currently allocated*] may be passed to diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 17d945559278..f90de1f5ced4 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -610,6 +610,101 @@ impl dyn Any + Send + Sync { /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware /// of relying on them inside of your code! +/// +/// # Danger of Improper Variance +/// +/// You might think that subtyping is impossible between two static types, +/// but this is false; there exists a static type with a static subtype. +/// To wit, `fn(&str)`, which is short for `for<'any> fn(&'any str)`, and +/// `fn(&'static str)`, are two distinct, static types, and yet, +/// `fn(&str)` is a subtype of `fn(&'static str)`, since any value of type +/// `fn(&str)` can be used where a value of type `fn(&'static str)` is needed. +/// +/// This means that abstractions around `TypeId`, despite its +/// `'static` bound on arguments, still need to worry about unnecessary +/// and improper variance: it is advisable to strive for invariance +/// first. The usability impact will be negligible, while the reduction +/// in the risk of unsoundness will be most welcome. +/// +/// ## Examples +/// +/// Suppose `SubType` is a subtype of `SuperType`, that is, +/// a value of type `SubType` can be used wherever +/// a value of type `SuperType` is expected. +/// Suppose also that `CoVar` is a generic type, which is covariant over `T` +/// (like many other types, including `PhantomData` and `Vec`). +/// +/// Then, by covariance, `CoVar` is a subtype of `CoVar`, +/// that is, a value of type `CoVar` can be used wherever +/// a value of type `CoVar` is expected. +/// +/// Then if `CoVar` relies on `TypeId::of::()` to uphold any invariants, +/// those invariants may be broken because a value of type `CoVar` can be created +/// without going through any of its methods, like so: +/// ``` +/// type SubType = fn(&()); +/// type SuperType = fn(&'static ()); +/// type CoVar = Vec; // imagine something more complicated +/// +/// let sub: CoVar = CoVar::new(); +/// // we have a `CoVar` instance without +/// // *ever* having called `CoVar::::new()`! +/// let fake_super: CoVar = sub; +/// ``` +/// +/// The following is an example program that tries to use `TypeId::of` to +/// implement a generic type `Unique` that guarantees unique instances for each `Unique`, +/// that is, and for each type `T` there can be at most one value of type `Unique` at any time. +/// +/// ``` +/// mod unique { +/// use std::any::TypeId; +/// use std::collections::BTreeSet; +/// use std::marker::PhantomData; +/// use std::sync::Mutex; +/// +/// static ID_SET: Mutex> = Mutex::new(BTreeSet::new()); +/// +/// // TypeId has only covariant uses, which makes Unique covariant over TypeAsId 🚨 +/// #[derive(Debug, PartialEq)] +/// pub struct Unique( +/// // private field prevents creation without `new` outside this module +/// PhantomData, +/// ); +/// +/// impl Unique { +/// pub fn new() -> Option { +/// let mut set = ID_SET.lock().unwrap(); +/// (set.insert(TypeId::of::())).then(|| Self(PhantomData)) +/// } +/// } +/// +/// impl Drop for Unique { +/// fn drop(&mut self) { +/// let mut set = ID_SET.lock().unwrap(); +/// (!set.remove(&TypeId::of::())).then(|| panic!("duplicity detected")); +/// } +/// } +/// } +/// +/// use unique::Unique; +/// +/// // `OtherRing` is a subtype of `TheOneRing`. Both are 'static, and thus have a TypeId. +/// type TheOneRing = fn(&'static ()); +/// type OtherRing = fn(&()); +/// +/// fn main() { +/// let the_one_ring: Unique = Unique::new().unwrap(); +/// assert_eq!(Unique::::new(), None); +/// +/// let other_ring: Unique = Unique::new().unwrap(); +/// // Use that `Unique` is a subtype of `Unique` 🚨 +/// let fake_one_ring: Unique = other_ring; +/// assert_eq!(fake_one_ring, the_one_ring); +/// +/// std::mem::forget(fake_one_ring); +/// } +/// ``` #[derive(Clone, Copy, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { @@ -627,8 +722,7 @@ impl PartialEq for TypeId { } impl TypeId { - /// Returns the `TypeId` of the type this generic function has been - /// instantiated with. + /// Returns the `TypeId` of the generic type parameter. /// /// # Examples /// diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index e5c1a64c12ee..520b9941ae45 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -646,7 +646,7 @@ pub const fn must_use(value: T) -> T { /// ``` /// /// -#[unstable(feature = "likely_unlikely", issue = "26179")] +#[unstable(feature = "likely_unlikely", issue = "136873")] #[inline(always)] pub const fn likely(b: bool) -> bool { crate::intrinsics::likely(b) @@ -696,7 +696,7 @@ pub const fn likely(b: bool) -> bool { /// } /// } /// ``` -#[unstable(feature = "likely_unlikely", issue = "26179")] +#[unstable(feature = "likely_unlikely", issue = "136873")] #[inline(always)] pub const fn unlikely(b: bool) -> bool { crate::intrinsics::unlikely(b) @@ -729,7 +729,7 @@ pub const fn unlikely(b: bool) -> bool { /// } /// } /// ``` -#[unstable(feature = "cold_path", issue = "26179")] +#[unstable(feature = "cold_path", issue = "136873")] #[inline(always)] pub const fn cold_path() { crate::intrinsics::cold_path() diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1a8ef20dd7b9..042ee419d57e 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -453,6 +453,23 @@ impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] impl Copy for &T {} +/// Marker trait for the types that are allowed in union fields, unsafe fields, +/// and unsafe binder types. +/// +/// Implemented for: +/// * `&T`, `&mut T` for all `T`, +/// * `ManuallyDrop` for all `T`, +/// * tuples and arrays whose elements implement `BikeshedGuaranteedNoDrop`, +/// * or otherwise, all types that are `Copy`. +/// +/// Notably, this doesn't include all trivially-destructible types for semver +/// reasons. +/// +/// Bikeshed name for now. +#[unstable(feature = "bikeshed_guaranteed_no_drop", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "bikeshed_guaranteed_no_drop")] +pub trait BikeshedGuaranteedNoDrop {} + /// Types for which it is safe to share references between threads. /// /// This trait is automatically implemented when the compiler determines @@ -1284,8 +1301,22 @@ pub trait FnPtr: Copy + Clone { /// } /// ``` #[rustc_builtin_macro(CoercePointee, attributes(pointee))] -#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] +#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize, coerce_pointee_validated)] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] pub macro CoercePointee($item:item) { /* compiler built-in */ } + +/// A trait that is implemented for ADTs with `derive(CoercePointee)` so that +/// the compiler can enforce the derive impls are valid post-expansion, since +/// the derive has stricter requirements than if the impls were written by hand. +/// +/// This trait is not intended to be implemented by users or used other than +/// validation, so it should never be stabilized. +#[cfg(not(bootstrap))] +#[lang = "coerce_pointee_validated"] +#[unstable(feature = "coerce_pointee_validated", issue = "none")] +#[doc(hidden)] +pub trait CoercePointeeValidated { + /* compiler built-in */ +} diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index a115acf42b12..21bad6705ab8 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -612,8 +612,6 @@ macro_rules! nonzero_integer { /// Basic usage: /// /// ``` - /// #![feature(non_zero_count_ones)] - /// /// # use std::num::NonZero; /// # /// # fn main() { test().unwrap(); } @@ -627,7 +625,8 @@ macro_rules! nonzero_integer { /// # } /// ``` /// - #[unstable(feature = "non_zero_count_ones", issue = "120287")] + #[stable(feature = "non_zero_count_ones", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_zero_count_ones", since = "CURRENT_RUSTC_VERSION")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index e1348552b65c..eb99be817a2c 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/library/std/src/f128.rs b/library/std/src/f128.rs index 89612fa74755..cff0bf4ccf4c 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -1,4 +1,4 @@ -//! Constants for the `f128` double-precision floating point type. +//! Constants for the `f128` quadruple-precision floating point type. //! //! *[See also the `f128` primitive type](primitive@f128).* //! diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index cc523c93b4de..f6a553b1d0fa 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -1,4 +1,4 @@ -//! Constants for the `f16` double-precision floating point type. +//! Constants for the `f16` half-precision floating point type. //! //! *[See also the `f16` primitive type](primitive@f16).* //! diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0871a9e22d38..83b009c86dc0 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -664,7 +664,7 @@ impl File { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; + /// let f = File::create("foo.txt")?; /// f.lock()?; /// Ok(()) /// } @@ -767,7 +767,7 @@ impl File { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; + /// let f = File::create("foo.txt")?; /// f.try_lock()?; /// Ok(()) /// } diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 1d26bf37f4d2..825a89fc7f2c 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -651,16 +651,24 @@ mod if_keyword {} #[doc(keyword = "impl")] // -/// Implement some functionality for a type. +/// Implementations of functionality for a type, or a type implementing some functionality. +/// +/// There are two uses of the keyword `impl`: +/// * An `impl` block is an item that is used to implement some functionality for a type. +/// * An `impl Trait` in a type-position can be used to designate a type that implements a trait called `Trait`. +/// +/// # Implementing Functionality for a Type /// /// The `impl` keyword is primarily used to define implementations on types. Inherent /// implementations are standalone, while trait implementations are used to implement traits for /// types, or other traits. /// -/// Functions and consts can both be defined in an implementation. A function defined in an -/// `impl` block can be standalone, meaning it would be called like `Foo::bar()`. If the function +/// An implementation consists of definitions of functions and consts. A function defined in an +/// `impl` block can be standalone, meaning it would be called like `Vec::new()`. If the function /// takes `self`, `&self`, or `&mut self` as its first argument, it can also be called using -/// method-call syntax, a familiar feature to any object oriented programmer, like `foo.bar()`. +/// method-call syntax, a familiar feature to any object-oriented programmer, like `vec.len()`. +/// +/// ## Inherent Implementations /// /// ```rust /// struct Example { @@ -680,6 +688,17 @@ mod if_keyword {} /// self.number /// } /// } +/// ``` +/// +/// It matters little where an inherent implementation is defined; +/// its functionality is in scope wherever its implementing type is. +/// +/// ## Trait Implementations +/// +/// ```rust +/// struct Example { +/// number: i32, +/// } /// /// trait Thingy { /// fn do_thingy(&self); @@ -692,11 +711,19 @@ mod if_keyword {} /// } /// ``` /// +/// It matters little where a trait implementation is defined; +/// its functionality can be brought into scope by importing the trait it implements. +/// /// For more information on implementations, see the [Rust book][book1] or the [Reference]. /// -/// The other use of the `impl` keyword is in `impl Trait` syntax, which can be seen as a shorthand -/// for "a concrete type that implements this trait". Its primary use is working with closures, -/// which have type definitions generated at compile time that can't be simply typed out. +/// # Designating a Type that Implements Some Functionality +/// +/// The other use of the `impl` keyword is in `impl Trait` syntax, which can be understood to mean +/// "any (or some) concrete type that implements Trait". +/// It can be used as the type of a variable declaration, +/// in [argument position](https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html) +/// or in [return position](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). +/// One pertinent use case is in working with closures, which have unnameable types. /// /// ```rust /// fn thing_returning_closure() -> impl Fn(i32) -> bool { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 954a4182fbd6..aea81b4bddee 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -272,6 +272,9 @@ // // Language features: // tidy-alphabetical-start + +// stabilization was reverted after it hit beta +#![cfg_attr(not(bootstrap), feature(extended_varargs_abi_support))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index 6d23c72ef220..e305b8610c9f 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -17,111 +17,50 @@ pub fn errno() -> RawOsError { pub fn error_string(errno: RawOsError) -> String { // Keep the List in Alphabetical Order // The Messages are taken from UEFI Specification Appendix D - Status Codes - match r_efi::efi::Status::from_usize(errno) { - Status::ABORTED => "The operation was aborted.".to_owned(), - Status::ACCESS_DENIED => "Access was denied.".to_owned(), - Status::ALREADY_STARTED => "The protocol has already been started.".to_owned(), - Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.".to_owned(), - Status::BUFFER_TOO_SMALL => { - "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.".to_owned() - } - Status::COMPROMISED_DATA => { - "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.".to_owned() - } - Status::CONNECTION_FIN => { - "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.".to_owned() - } - Status::CONNECTION_REFUSED => { - "The receiving or transmission operation fails because this connection is refused.".to_owned() - } - Status::CONNECTION_RESET => { - "The connect fails because the connection is reset either by instance itself or the communication peer.".to_owned() - } - Status::CRC_ERROR => "A CRC error was detected.".to_owned(), - Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.".to_owned() - , - Status::END_OF_FILE => { - "The end of the file was reached.".to_owned() - } - Status::END_OF_MEDIA => { - "Beginning or end of media was reached".to_owned() - } - Status::HOST_UNREACHABLE => { - "The remote host is not reachable.".to_owned() - } - Status::HTTP_ERROR => { - "A HTTP error occurred during the network operation.".to_owned() - } - Status::ICMP_ERROR => { - "An ICMP error occurred during the network operation.".to_owned() - } - Status::INCOMPATIBLE_VERSION => { - "The function encountered an internal version that was incompatible with a version requested by the caller.".to_owned() - } - Status::INVALID_LANGUAGE => { - "The language specified was invalid.".to_owned() - } - Status::INVALID_PARAMETER => { - "A parameter was incorrect.".to_owned() - } - Status::IP_ADDRESS_CONFLICT => { - "There is an address conflict address allocation".to_owned() - } - Status::LOAD_ERROR => { - "The image failed to load.".to_owned() - } - Status::MEDIA_CHANGED => { - "The medium in the device has changed since the last access.".to_owned() - } - Status::NETWORK_UNREACHABLE => { - "The network containing the remote host is not reachable.".to_owned() - } - Status::NO_MAPPING => { - "A mapping to a device does not exist.".to_owned() - } - Status::NO_MEDIA => { - "The device does not contain any medium to perform the operation.".to_owned() - } - Status::NO_RESPONSE => { - "The server was not found or did not respond to the request.".to_owned() - } - Status::NOT_FOUND => "The item was not found.".to_owned(), - Status::NOT_READY => { - "There is no data pending upon return.".to_owned() - } - Status::NOT_STARTED => { - "The protocol has not been started.".to_owned() - } - Status::OUT_OF_RESOURCES => { - "A resource has run out.".to_owned() - } - Status::PROTOCOL_ERROR => { - "A protocol error occurred during the network operation.".to_owned() - } - Status::PROTOCOL_UNREACHABLE => { - "An ICMP protocol unreachable error is received.".to_owned() - } - Status::SECURITY_VIOLATION => { - "The function was not performed due to a security violation.".to_owned() - } - Status::TFTP_ERROR => { - "A TFTP error occurred during the network operation.".to_owned() - } - Status::TIMEOUT => "The timeout time expired.".to_owned(), - Status::UNSUPPORTED => { - "The operation is not supported.".to_owned() - } - Status::VOLUME_FULL => { - "There is no more space on the file system.".to_owned() - } - Status::VOLUME_CORRUPTED => { - "An inconstancy was detected on the file system causing the operating to fail.".to_owned() - } - Status::WRITE_PROTECTED => { - "The device cannot be written to.".to_owned() - } - _ => format!("Status: {}", errno), - } + #[rustfmt::skip] + let msg = match r_efi::efi::Status::from_usize(errno) { + Status::ABORTED => "The operation was aborted.", + Status::ACCESS_DENIED => "Access was denied.", + Status::ALREADY_STARTED => "The protocol has already been started.", + Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.", + Status::BUFFER_TOO_SMALL => "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.", + Status::COMPROMISED_DATA => "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.", + Status::CONNECTION_FIN => "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.", + Status::CONNECTION_REFUSED => "The receiving or transmission operation fails because this connection is refused.", + Status::CONNECTION_RESET => "The connect fails because the connection is reset either by instance itself or the communication peer.", + Status::CRC_ERROR => "A CRC error was detected.", + Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.", + Status::END_OF_FILE => "The end of the file was reached.", + Status::END_OF_MEDIA => "Beginning or end of media was reached", + Status::HOST_UNREACHABLE => "The remote host is not reachable.", + Status::HTTP_ERROR => "A HTTP error occurred during the network operation.", + Status::ICMP_ERROR => "An ICMP error occurred during the network operation.", + Status::INCOMPATIBLE_VERSION => "The function encountered an internal version that was incompatible with a version requested by the caller.", + Status::INVALID_LANGUAGE => "The language specified was invalid.", + Status::INVALID_PARAMETER => "A parameter was incorrect.", + Status::IP_ADDRESS_CONFLICT => "There is an address conflict address allocation", + Status::LOAD_ERROR => "The image failed to load.", + Status::MEDIA_CHANGED => "The medium in the device has changed since the last access.", + Status::NETWORK_UNREACHABLE => "The network containing the remote host is not reachable.", + Status::NO_MAPPING => "A mapping to a device does not exist.", + Status::NO_MEDIA => "The device does not contain any medium to perform the operation.", + Status::NO_RESPONSE => "The server was not found or did not respond to the request.", + Status::NOT_FOUND => "The item was not found.", + Status::NOT_READY => "There is no data pending upon return.", + Status::NOT_STARTED => "The protocol has not been started.", + Status::OUT_OF_RESOURCES => "A resource has run out.", + Status::PROTOCOL_ERROR => "A protocol error occurred during the network operation.", + Status::PROTOCOL_UNREACHABLE => "An ICMP protocol unreachable error is received.", + Status::SECURITY_VIOLATION => "The function was not performed due to a security violation.", + Status::TFTP_ERROR => "A TFTP error occurred during the network operation.", + Status::TIMEOUT => "The timeout time expired.", + Status::UNSUPPORTED => "The operation is not supported.", + Status::VOLUME_FULL => "There is no more space on the file system.", + Status::VOLUME_CORRUPTED => "An inconstancy was detected on the file system causing the operating to fail.", + Status::WRITE_PROTECTED => "The device cannot be written to.", + _ => return format!("Status: {errno}"), + }; + msg.to_owned() } pub fn getcwd() -> io::Result { @@ -314,7 +253,7 @@ mod uefi_env { let mut start = 0; - // UEFI Shell returns all keys seperated by NULL. + // UEFI Shell returns all keys separated by NULL. // End of string is denoted by two NULLs for i in 0.. { if unsafe { *val.add(i) } == 0 { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index f6f9067b9c6f..a2375842bdde 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -191,7 +191,7 @@ impl Step for Std { // The LLD wrappers and `rust-lld` are self-contained linking components that can be // necessary to link the stdlib on some targets. We'll also need to copy these binaries to // the `stage0-sysroot` to ensure the linker is found when bootstrapping on such a target. - if compiler.stage == 0 && compiler.host == builder.config.build { + if compiler.stage == 0 && builder.is_builder_target(&compiler.host) { // We want to copy the host `bin` folder within the `rustlib` folder in the sysroot. let src_sysroot_bin = builder .rustc_snapshot_sysroot() @@ -1105,9 +1105,7 @@ pub fn rustc_cargo( cargo.rustflag("-Zdefault-visibility=protected"); } - // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary - // and may just be a time sink. - if compiler.stage != 0 { + if is_lto_stage(compiler) { match builder.config.rust_lto { RustcLto::Thin | RustcLto::Fat => { // Since using LTO for optimizing dylibs is currently experimental, @@ -2312,7 +2310,8 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) // FIXME: to make things simpler for now, limit this to the host and target where we know // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not // cross-compiling. Expand this to other appropriate targets in the future. - if target != "x86_64-unknown-linux-gnu" || target != builder.config.build || !path.exists() { + if target != "x86_64-unknown-linux-gnu" || !builder.is_builder_target(&target) || !path.exists() + { return; } @@ -2335,3 +2334,8 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) // everything else (standard library, future stages...) to be rebuilt. t!(file.set_modified(previous_mtime)); } + +/// We only use LTO for stage 2+, to speed up build time of intermediate stages. +pub fn is_lto_stage(build_compiler: &Compiler) -> bool { + build_compiler.stage != 0 +} diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 18f920b85eee..ae3761a97e50 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -582,7 +582,7 @@ impl Step for DebuggerScripts { fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool { // The only true set of target libraries came from the build triple, so // let's reduce redundant work by only producing archives from that host. - if compiler.host != builder.config.build { + if !builder.is_builder_target(&compiler.host) { builder.info("\tskipping, not a build host"); true } else { @@ -637,7 +637,7 @@ fn copy_target_libs( for (path, dependency_type) in builder.read_stamp_file(stamp) { if dependency_type == DependencyType::TargetSelfContained { builder.copy_link(&path, &self_contained_dst.join(path.file_name().unwrap())); - } else if dependency_type == DependencyType::Target || builder.config.build == target { + } else if dependency_type == DependencyType::Target || builder.is_builder_target(&target) { builder.copy_link(&path, &dst.join(path.file_name().unwrap())); } } @@ -786,7 +786,7 @@ impl Step for Analysis { fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; - if compiler.host != builder.config.build { + if !builder.is_builder_target(&compiler.host) { return None; } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 9dd350570621..ee60dbef7b98 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -516,7 +516,7 @@ impl Step for Llvm { } // https://llvm.org/docs/HowToCrossCompileLLVM.html - if target != builder.config.build { + if !builder.is_builder_target(&target) { let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build }); if !builder.config.dry_run() { @@ -661,7 +661,7 @@ fn configure_cmake( } cfg.target(&target.triple).host(&builder.config.build.triple); - if target != builder.config.build { + if !builder.is_builder_target(&target) { cfg.define("CMAKE_CROSSCOMPILING", "True"); if target.contains("netbsd") { @@ -1111,7 +1111,7 @@ impl Step for Lld { .define("LLVM_CMAKE_DIR", llvm_cmake_dir) .define("LLVM_INCLUDE_TESTS", "OFF"); - if target != builder.config.build { + if !builder.is_builder_target(&target) { // Use the host llvm-tblgen binary. cfg.define( "LLVM_TABLEGEN_EXE", diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index c452f4cd6ae0..509875a469f1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2742,7 +2742,7 @@ impl Step for Crate { cargo } else { // Also prepare a sysroot for the target. - if builder.config.build != target { + if !builder.is_builder_target(&target) { builder.ensure(compile::Std::new(compiler, target).force_recompile(true)); builder.ensure(RemoteCopyLibs { compiler, target }); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 793fa24991b7..1291a634a6f6 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use std::{env, fs}; +use crate::core::build_steps::compile::is_lto_stage; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, llvm}; use crate::core::builder; @@ -659,14 +660,16 @@ impl Step for Rustdoc { ); // rustdoc is performance sensitive, so apply LTO to it. - let lto = match builder.config.rust_lto { - RustcLto::Off => Some("off"), - RustcLto::Thin => Some("thin"), - RustcLto::Fat => Some("fat"), - RustcLto::ThinLocal => None, - }; - if let Some(lto) = lto { - cargo.env(cargo_profile_var("LTO", &builder.config), lto); + if is_lto_stage(&build_compiler) { + let lto = match builder.config.rust_lto { + RustcLto::Off => Some("off"), + RustcLto::Thin => Some("thin"), + RustcLto::Fat => Some("fat"), + RustcLto::ThinLocal => None, + }; + if let Some(lto) = lto { + cargo.env(cargo_profile_var("LTO", &builder.config), lto); + } } let _guard = builder.msg_tool( diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 994975ed5a8b..a0be474ca3e3 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1065,3 +1065,19 @@ fn test_prebuilt_llvm_config_path_resolution() { .join(exe("llvm-config", builder.config.build)); assert_eq!(expected, actual); } + +#[test] +fn test_is_builder_target() { + let target1 = TargetSelection::from_user(TEST_TRIPLE_1); + let target2 = TargetSelection::from_user(TEST_TRIPLE_2); + + for (target1, target2) in [(target1, target2), (target2, target1)] { + let mut config = configure("build", &[], &[]); + config.build = target1; + let build = Build::new(config); + let builder = Builder::new(&build); + + assert!(builder.is_builder_target(&target1)); + assert!(!builder.is_builder_target(&target2)); + } +} diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 6c8cda18548e..9e4a0816e0d4 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -329,7 +329,7 @@ than building it. if target.contains("musl") && !target.contains("unikraft") { // If this is a native target (host is also musl) and no musl-root is given, // fall back to the system toolchain in /usr before giving up - if build.musl_root(*target).is_none() && build.config.build == *target { + if build.musl_root(*target).is_none() && build.is_builder_target(target) { let target = build.config.target_config.entry(*target).or_default(); target.musl_root = Some("/usr".into()); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index e564a4b97514..665ab117002e 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -739,7 +739,7 @@ impl Build { /// Note that if LLVM is configured externally then the directory returned /// will likely be empty. fn llvm_out(&self, target: TargetSelection) -> PathBuf { - if self.config.llvm_from_ci && self.config.build == target { + if self.config.llvm_from_ci && self.is_builder_target(&target) { self.config.ci_llvm_root() } else { self.out.join(target).join("llvm") @@ -789,7 +789,7 @@ impl Build { fn is_system_llvm(&self, target: TargetSelection) -> bool { match self.config.target_config.get(&target) { Some(Target { llvm_config: Some(_), .. }) => { - let ci_llvm = self.config.llvm_from_ci && target == self.config.build; + let ci_llvm = self.config.llvm_from_ci && self.is_builder_target(&target); !ci_llvm } // We're building from the in-tree src/llvm-project sources. @@ -1274,7 +1274,7 @@ Executed at: {executed_at}"#, // need to use CXX compiler as linker to resolve the exception functions // that are only existed in CXX libraries Some(self.cxx.borrow()[&target].path().into()) - } else if target != self.config.build + } else if !self.is_builder_target(&target) && helpers::use_host_linker(target) && !target.is_msvc() { @@ -1925,6 +1925,11 @@ to download LLVM rather than building it. stream.reset().unwrap(); result } + + /// Checks if the given target is the same as the builder target. + fn is_builder_target(&self, target: &TargetSelection) -> bool { + &self.config.build == target + } } #[cfg(unix)] diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 29342cc5a2c5..1c8cc4025df1 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 000000000000..28f5563a589b --- /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 f6afd50afcef..45797c1276c5 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/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 8ae6d543bc59..c08104e796b9 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -12,15 +12,15 @@ runners: # Large runner used mainly for its bigger disk capacity - &job-linux-4c-largedisk - os: ubuntu-22.04-4core-16gb + os: ubuntu-24.04-4core-16gb <<: *base-job - &job-linux-8c - os: ubuntu-22.04-8core-32gb + os: ubuntu-24.04-8core-32gb <<: *base-job - &job-linux-16c - os: ubuntu-22.04-16core-64gb + os: ubuntu-24.04-16core-64gb <<: *base-job - &job-macos-xl @@ -460,26 +460,26 @@ auto: - name: x86_64-msvc-1 env: - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-py <<: *job-windows-25 - name: x86_64-msvc-2 env: - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-ps1 <<: *job-windows-25 # i686-msvc is split into two jobs to run tests in parallel. - name: i686-msvc-1 env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc --enable-sanitizers SCRIPT: make ci-msvc-py <<: *job-windows - name: i686-msvc-2 env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc --enable-sanitizers SCRIPT: make ci-msvc-ps1 <<: *job-windows diff --git a/src/doc/edition-guide b/src/doc/edition-guide index f56aecc3b036..8dbdda7cae4f 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit f56aecc3b036dff16404b525a83b00f911b9bbea +Subproject commit 8dbdda7cae4fa030f09f8f5b63994d4d1dde74b9 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index ddbf1b4e2858..0b8219ac23a3 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit ddbf1b4e2858fedb71b7c42eb15c4576517dc125 +Subproject commit 0b8219ac23a3e09464e4e0166c768cf1c4bba0d5 diff --git a/src/doc/reference b/src/doc/reference index 4249fb411dd2..de2d5289e455 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 4249fb411dd27f945e2881eb0378044b94cee06f +Subproject commit de2d5289e45506b11dd652bef4f99de64be70e1c diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 743766929f1e..66543bbc5b7d 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 743766929f1e53e72fab74394ae259bbfb4a7619 +Subproject commit 66543bbc5b7dbd4e679092c07ae06ba6c73fd912 diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index 615927d55e59..dc5395a19dd0 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -3,8 +3,8 @@ name: rustc-pull on: workflow_dispatch: schedule: - # Run at 04:00 UTC every Monday - - cron: '0 4 * * 1' + # Run at 04:00 UTC every Monday and Thursday + - cron: '0 4 * * 1,4' jobs: pull: @@ -34,8 +34,25 @@ jobs: git config --global user.name 'The rustc-dev-guide Cronjob Bot' git config --global user.email 'github-actions@github.com' - name: Perform rustc-pull - run: cargo run --manifest-path josh-sync/Cargo.toml -- rustc-pull + id: rustc-pull + # Turn off -e to disable early exit + shell: bash {0} + run: | + cargo run --manifest-path josh-sync/Cargo.toml -- rustc-pull + exitcode=$? + + # If no pull was performed, we want to mark this job as successful, + # but we do not want to perform the follow-up steps. + if [ $exitcode -eq 0 ]; then + echo "pull_result=pull-finished" >> $GITHUB_OUTPUT + elif [ $exitcode -eq 2 ]; then + echo "pull_result=skipped" >> $GITHUB_OUTPUT + exitcode=0 + fi + + exit ${exitcode} - name: Push changes to a branch + if: ${{ steps.rustc-pull.outputs.pull_result == 'pull-finished' }} run: | # Update a sticky branch that is used only for rustc pulls BRANCH="rustc-pull" @@ -43,6 +60,9 @@ jobs: git push -u origin $BRANCH --force - name: Create pull request id: update-pr + if: ${{ steps.rustc-pull.outputs.pull_result == 'pull-finished' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Check if an open pull request for an rustc pull update already exists # If it does, the previous push has just updated it @@ -54,26 +74,35 @@ jobs: echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT else PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title` + echo "Updating pull request ${PR_URL}" echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} send-zulip-message: needs: [pull] if: ${{ !cancelled() }} runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 - name: Compute message - id: message + id: create-message + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - if [ "${{ needs.pull.result }}" == "failure" ]; - then + if [ "${{ needs.pull.result }}" == "failure" ]; then WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" echo "message=Rustc pull sync failed. Check out the [workflow URL]($WORKFLOW_URL)." >> $GITHUB_OUTPUT else - echo "message=Rustc pull sync succeeded. Check out the [PR](${{ needs.pull.outputs.pr_url }})." >> $GITHUB_OUTPUT + CREATED_AT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].createdAt' --json createdAt,title` + PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title` + week_ago=$(date +%F -d '7 days ago') + + # If there is an open PR that is at least a week old, post a message about it + if [[ -n $DATE_GH && $DATE_GH < $week_ago ]]; then + echo "message=A PR with a Rustc pull has been opened for more a week. Check out the [PR](${PR_URL})." >> $GITHUB_OUTPUT + fi fi - name: Send a Zulip message about updated PR + if: ${{ steps.create-message.outputs.message != '' }} uses: zulip/github-actions-zulip/send-message@e4c8f27c732ba9bd98ac6be0583096dea82feea5 with: api-key: ${{ secrets.ZULIP_API_TOKEN }} diff --git a/src/doc/rustc-dev-guide/josh-sync/src/main.rs b/src/doc/rustc-dev-guide/josh-sync/src/main.rs index 84613ad86890..175f016f7390 100644 --- a/src/doc/rustc-dev-guide/josh-sync/src/main.rs +++ b/src/doc/rustc-dev-guide/josh-sync/src/main.rs @@ -1,5 +1,5 @@ use clap::Parser; -use crate::sync::GitSync; +use crate::sync::{GitSync, RustcPullError}; mod sync; @@ -22,7 +22,18 @@ fn main() -> anyhow::Result<()> { let sync = GitSync::from_current_dir()?; match args { Args::RustcPull => { - sync.rustc_pull(None)?; + if let Err(error) = sync.rustc_pull(None) { + match error { + RustcPullError::NothingToPull => { + eprintln!("Nothing to pull"); + std::process::exit(2); + } + RustcPullError::PullFailed(error) => { + eprintln!("Pull failure: {error:?}"); + std::process::exit(1); + } + } + } } Args::RustcPush { github_username, branch } => { sync.rustc_push(github_username, branch)?; diff --git a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs index eff80b1091d3..cd64be636703 100644 --- a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs +++ b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs @@ -11,6 +11,19 @@ const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide"; const JOSH_PORT: u16 = 42042; const UPSTREAM_REPO: &str = "rust-lang/rust"; +pub enum RustcPullError { + /// No changes are available to be pulled. + NothingToPull, + /// A rustc-pull has failed, probably a git operation error has occurred. + PullFailed(anyhow::Error) +} + +impl From for RustcPullError where E: Into { + fn from(error: E) -> Self { + Self::PullFailed(error.into()) + } +} + pub struct GitSync { dir: PathBuf, } @@ -24,7 +37,7 @@ impl GitSync { }) } - pub fn rustc_pull(&self, commit: Option) -> anyhow::Result<()> { + pub fn rustc_pull(&self, commit: Option) -> Result<(), RustcPullError> { let sh = Shell::new()?; sh.change_dir(&self.dir); let commit = commit.map(Ok).unwrap_or_else(|| { @@ -38,7 +51,7 @@ impl GitSync { })?; // Make sure the repo is clean. if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() { - bail!("working directory must be clean before performing rustc pull"); + return Err(anyhow::anyhow!("working directory must be clean before performing rustc pull").into()); } // Make sure josh is running. let josh = Self::start_josh()?; @@ -47,7 +60,7 @@ impl GitSync { let previous_base_commit = sh.read_file("rust-version")?.trim().to_string(); if previous_base_commit == commit { - return Err(anyhow::anyhow!("No changes since last pull")); + return Err(RustcPullError::NothingToPull); } // Update rust-version file. As a separate commit, since making it part of @@ -94,12 +107,13 @@ impl GitSync { cmd!(sh, "git reset --hard HEAD^") .run() .expect("FAILED to clean up after creating the preparation commit"); - return Err(anyhow::anyhow!("No merge was performed, nothing to pull. Rolled back the preparation commit.")); + eprintln!("No merge was performed, no changes to pull were found. Rolled back the preparation commit."); + return Err(RustcPullError::NothingToPull); } // Check that the number of roots did not increase. if num_roots()? != num_roots_before { - bail!("Josh created a new root commit. This is probably not the history you want."); + return Err(anyhow::anyhow!("Josh created a new root commit. This is probably not the history you want.").into()); } drop(josh); diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 183d26b29384..78e9ecdf174b 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -66d6064f9eb888018775e08f84747ee6f39ba28e +124cc92199ffa924f6b4c7cc819a85b65e0c3984 diff --git a/src/doc/rustc-dev-guide/src/appendix/bibliography.md b/src/doc/rustc-dev-guide/src/appendix/bibliography.md index 8f6810cbcaea..93426b645a61 100644 --- a/src/doc/rustc-dev-guide/src/appendix/bibliography.md +++ b/src/doc/rustc-dev-guide/src/appendix/bibliography.md @@ -82,7 +82,7 @@ Rust, as well as publications about Rust. * [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](https://amitlevy.com/papers/tock-plos2015.pdf) * [You can't spell trust without Rust](https://faultlore.com/blah/papers/thesis.pdf). Aria Beingessner's master's thesis. * [Rust-Bio: a fast and safe bioinformatics library](https://rust-bio.github.io/). Johannes Köster -* [Safe, Correct, and Fast Low-Level Networking](https://octarineparrot.com/assets/msci_paper.pdf). Robert Clipsham's master's thesis. +* [Safe, Correct, and Fast Low-Level Networking](https://csperkins.org/research/thesis-msci-clipsham.pdf). Robert Clipsham's master's thesis. * [Formalizing Rust traits](https://open.library.ubc.ca/cIRcle/collections/ubctheses/24/items/1.0220521). Jonatan Milewski's master's thesis. * [Rust as a Language for High Performance GC Implementation](https://dl.acm.org/doi/pdf/10.1145/3241624.2926707) * [Simple Verification of Rust Programs via Functional Purification](https://github.com/Kha/electrolysis). Sebastian Ullrich's master's thesis. diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index bf5ffbc00afd..2c6c3fe1df84 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -135,24 +135,24 @@ and follow the same instructions as above. ### Emacs Emacs provides support for rust-analyzer with project-local configuration -through [Eglot](https://www.gnu.org/software/emacs/manual/html_node/eglot/). +through [Eglot](https://www.gnu.org/software/emacs/manual/html_node/eglot/). Steps for setting up Eglot with rust-analyzer can be [found -here](https://rust-analyzer.github.io/manual.html#eglot). +here](https://rust-analyzer.github.io/manual.html#eglot). Having set up Emacs & Eglot for Rust development in general, you can run `./x setup editor` and select `emacs`, which will prompt you to create `.dir-locals.el` with the recommended configuration for Eglot. -The recommended settings live at [`src/etc/rust_analyzer_eglot.el`]. +The recommended settings live at [`src/etc/rust_analyzer_eglot.el`]. For more information on project-specific Eglot configuration, consult [the manual](https://www.gnu.org/software/emacs/manual/html_node/eglot/Project_002dspecific-configuration.html). ### Helix -Helix comes with built-in LSP and rust-analyzer support. +Helix comes with built-in LSP and rust-analyzer support. It can be configured through `languages.toml`, as described -[here](https://docs.helix-editor.com/languages.html). +[here](https://docs.helix-editor.com/languages.html). You can run `./x setup editor` and select `helix`, which will prompt you to create `languages.toml` with the recommended configuration for Helix. The -recommended settings live at [`src/etc/rust_analyzer_helix.toml`]. +recommended settings live at [`src/etc/rust_analyzer_helix.toml`]. ## Check, check, and check again @@ -181,7 +181,7 @@ example, running `tidy` and `linkchecker` is useful when editing Markdown files, whereas UI tests are much less likely to be helpful. While `x suggest` is a useful tool, it does not guarantee perfect coverage (just as PR CI isn't a substitute for bors). See the [dedicated chapter](../tests/suggest-tests.md) for -more information and contribution instructions. +more information and contribution instructions. Please note that `x suggest` is in a beta state currently and the tests that it will suggest are limited. @@ -332,28 +332,21 @@ git worktree add -b my-feature ../rust2 master You can then use that rust2 folder as a separate workspace for modifying and building `rustc`! -## Using nix-shell +## Working with nix -If you're using nix, you can use the following nix-shell to work on Rust: +Several nix configurations are defined in `src/tools/nix-dev-shell`. -```nix -{ pkgs ? import {} }: -pkgs.mkShell { - name = "rustc"; - nativeBuildInputs = with pkgs; [ - binutils cmake ninja pkg-config python3 git curl cacert patchelf nix - ]; - buildInputs = with pkgs; [ - openssl glibc.out glibc.static - ]; - # Avoid creating text files for ICEs. - RUSTC_ICE = "0"; - # Provide `libstdc++.so.6` for the self-contained lld. - LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [ - stdenv.cc.cc.lib - ]}"; -} +If you're using direnv, you can create a symbol link to `src/tools/nix-dev-shell/envrc-flake` or `src/tools/nix-dev-shell/envrc-shell` + +```bash +ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc # Use flake ``` +or +```bash +ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc # Use nix-shell +``` + +### Note Note that when using nix on a not-NixOS distribution, it may be necessary to set **`patch-binaries-for-nix = true` in `config.toml`**. Bootstrap tries to detect diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 8f389640d271..972309b5cd34 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -601,8 +601,8 @@ The trait implementation allows you to check certain syntactic constructs as the linter walks the AST. You can then choose to emit lints in a very similar way to compile errors. -You also declare the metadata of a particular lint via the `declare_lint!` -macro. [This macro](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/macro.declare_lint.html) includes the name, the default level, a short description, and some +You also declare the metadata of a particular lint via the [`declare_lint!`] +macro. This macro includes the name, the default level, a short description, and some more details. Note that the lint and the lint pass must be registered with the compiler. @@ -671,6 +671,8 @@ example-use-loop = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` ``` +[`declare_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/macro.declare_lint.html + ### Edition-gated lints Sometimes we want to change the behavior of a lint in a new edition. To do this, diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 4cb1d0b31ebd..8bf14bef2a03 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -101,7 +101,6 @@ it's easy to pick up work without a large time commitment: - [Rustdoc Askama Migration](https://github.com/rust-lang/rust/issues/108868) - [Diagnostic Translation](https://github.com/rust-lang/rust/issues/100717) - [Move UI tests to subdirectories](https://github.com/rust-lang/rust/issues/73494) -- [Port run-make tests from Make to Rust](https://github.com/rust-lang/rust/issues/121876) If you find more recurring work, please feel free to add it here! 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 d87afeaedce6..5b67ccd7f4c5 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/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md b/src/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md index 391e562910fa..f6cff2d6c63c 100644 --- a/src/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md +++ b/src/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md @@ -21,7 +21,7 @@ Creating an env from an arbitrary set of where clauses is usually unnecessary an Creating an empty environment via `ParamEnv::empty` is almost always wrong. There are very few places where we actually know that the environment should be empty. One of the only places where we do actually know this is after monomorphization, however the `ParamEnv` there should be constructed via `ParamEnv::reveal_all` instead as at this point we should be able to determine the hidden type of opaque types. Codegen/Post-mono is one of the only places that should be using `ParamEnv::reveal_all`. -An additional piece of complexity here is specifying the [`Reveal`][reveal] (see linked docs for explanation of what reveal does) used for the `ParamEnv`. When constructing a param env using the `param_env` query it will have `Reveal::UserFacing`, if `Reveal::All` is desired then the [`tcx.param_env_reveal_all_normalized`][env_reveal_all_normalized] query can be used instead. +An additional piece of complexity here is specifying the `Reveal` (see linked docs for explanation of what reveal does) used for the `ParamEnv`. When constructing a param env using the `param_env` query it will have `Reveal::UserFacing`, if `Reveal::All` is desired then the [`tcx.param_env_reveal_all_normalized`][env_reveal_all_normalized] query can be used instead. The `ParamEnv` type has a method [`ParamEnv::with_reveal_all_normalized`][with_reveal_all] which converts an existing `ParamEnv` into one with `Reveal::All` specified. Where possible the previously mentioned query should be preferred as it is more efficient. @@ -38,7 +38,6 @@ The `ParamEnv` type has a method [`ParamEnv::with_reveal_all_normalized`][with_r [with_reveal_all]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.with_reveal_all_normalized [env_reveal_all]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.reveal_all [env_empty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.empty -[reveal]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/traits/enum.Reveal.html [pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html [param_env_query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#structfield.param_env [method_pred_entailment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html diff --git a/src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md b/src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md index ca09518d99f4..5c2f4d594052 100644 --- a/src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md +++ b/src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md @@ -3,7 +3,7 @@ The type system relies on information in the environment in order for it to function correctly. This information is stored in the [`ParamEnv`][pe] type and it is important to use the correct `ParamEnv` when interacting with the type system. -The information represented by `ParamEnv` is a list of in-scope where-clauses, and a [`Reveal`][reveal] (see linked docs for more information). A `ParamEnv` typically corresponds to a specific item's where clauses, some clauses are not explicitly written bounds and instead are implicitly added in [`predicates_of`][predicates_of] such as `ConstArgHasType` or some implied bounds. +The information represented by `ParamEnv` is a list of in-scope where-clauses, and a `Reveal` (see linked docs for more information). A `ParamEnv` typically corresponds to a specific item's where clauses, some clauses are not explicitly written bounds and instead are implicitly added in [`predicates_of`][predicates_of] such as `ConstArgHasType` or some implied bounds. A `ParamEnv` can also be created with arbitrary data that is not derived from a specific item such as in [`compare_method_predicate_entailment`][method_pred_entailment] which creates a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses. In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. @@ -57,4 +57,3 @@ It's very important to use the correct `ParamEnv` when interacting with the type [method_pred_entailment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html [pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html [query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.param_env -[reveal]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/traits/enum.Reveal.html \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md index ddf8ec405f81..3506431118ba 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md @@ -46,8 +46,8 @@ For space savings, it's also written without newlines or spaces. ] ``` -[`src/librustdoc/html/static/js/externs.js`] -defines an actual schema in a Closure `@typedef`. +[`src/librustdoc/html/static/js/rustdoc.d.ts`] +defines an actual schema in a TypeScript `type`. | Key | Name | Description | | --- | -------------------- | ------------ | @@ -68,7 +68,7 @@ with a free function called `function_name` and a struct called `Data`, with the type signature `Data, i32 -> str`, and an alias, `get_name`, that equivalently refers to `function_name`. -[`src/librustdoc/html/static/js/externs.js`]: https://github.com/rust-lang/rust/blob/79b710c13968a1a48d94431d024d2b1677940866/src/librustdoc/html/static/js/externs.js#L204-L258 +[`src/librustdoc/html/static/js/rustdoc.d.ts`]: https://github.com/rust-lang/rust/blob/2f92f050e83bf3312ce4ba73c31fe843ad3cbc60/src/librustdoc/html/static/js/rustdoc.d.ts#L344-L390 The search index needs to fit the needs of the `rustdoc` compiler, the `search.js` frontend, @@ -469,7 +469,7 @@ want the libs team to be able to add new items without causing unrelated tests to fail, but standalone tests will use it more often. The `ResultsTable` and `ParsedQuery` types are specified in -[`externs.js`](https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/js/externs.js). +[`rustdoc.d.ts`](https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/js/rustdoc.d.ts). For example, imagine we needed to fix a bug where a function named `constructor` couldn't be found. To do this, write two files: diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 9dde407895e2..a4b22392f197 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -322,7 +322,7 @@ Our CI workflow uses various caching mechanisms, mainly for two things: ### Docker images caching The Docker images we use to run most of the Linux-based builders take a *long* -time to fully build. To speed up the build, we cache it using [Docker registry +time to fully build. To speed up the build, we cache them using [Docker registry caching], with the intermediate artifacts being stored on [ghcr.io]. We also push the built Docker images to ghcr, so that they can be reused by other tools (rustup) or by developers running the Docker build locally (to speed up their @@ -334,6 +334,13 @@ override the cache for the others. Instead, we store the images under different tags, identifying them with a custom hash made from the contents of all the Dockerfiles and related scripts. +The CI calculates a hash key, so that the cache of a Docker image is +invalidated if one of the following changes: + +- Dockerfile +- Files copied into the Docker image in the Dockerfile +- The architecture of the GitHub runner (x86 or ARM) + [ghcr.io]: https://github.com/rust-lang-ci/rust/pkgs/container/rust-ci [Docker registry caching]: https://docs.docker.com/build/cache/backends/registry/ @@ -341,9 +348,18 @@ Dockerfiles and related scripts. We build some C/C++ stuff in various CI jobs, and we rely on [sccache] to cache the intermediate LLVM artifacts. Sccache is a distributed ccache developed by -Mozilla, which can use an object storage bucket as the storage backend. In our -case, the artefacts are uploaded to an S3 bucket that we control -(`rust-lang-ci-sccache2`). +Mozilla, which can use an object storage bucket as the storage backend. + +With sccache there's no need to calculate the hash key ourselves. Sccache +invalidates the cache automatically when it detects changes to relevant inputs, +such as the source code, the version of the compiler, and important environment +variables. +So we just pass the sccache wrapper on top of cargo and sccache does the rest. + +We store the persistent artifacts on the S3 bucket `rust-lang-ci-sccache2`. So +when the CI runs, if sccache sees that LLVM is being compiled with the same C/C++ +compiler and the LLVM source code is the same, sccache retrieves the individual +compiled translation units from S3. [sccache]: https://github.com/mozilla/sccache diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 9e0f8f9c279c..b6209bcb2d80 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -192,6 +192,8 @@ settings: specified atomic widths, e.g. the test with `//@ needs-target-has-atomic: 8, 16, ptr` will only run if it supports the comma-separated list of atomic widths. +- `needs-dynamic-linking` - ignores if target does not support dynamic linking + (which is orthogonal to it being unable to create `dylib` and `cdylib` crate types) The following directives will check LLVM support: diff --git a/src/doc/rustc-dev-guide/src/tests/docker.md b/src/doc/rustc-dev-guide/src/tests/docker.md index a0aa8bd3e77b..2ca08d42130a 100644 --- a/src/doc/rustc-dev-guide/src/tests/docker.md +++ b/src/doc/rustc-dev-guide/src/tests/docker.md @@ -1,36 +1,44 @@ # Testing with Docker -The Rust tree includes [Docker] image definitions for the platforms used on -GitHub Actions in [`src/ci/docker`]. -The script [`src/ci/docker/run.sh`] is used to build the Docker image, run it, -build Rust within the image, and run the tests. - -You can run these images on your local development machine. This can be -helpful to test environments different from your local system. First you will +The [`src/ci/docker`] directory includes [Docker] image definitions for Linux-based jobs executed on GitHub Actions (non-Linux jobs run outside Docker). You can run these jobs on your local development machine, which can be +helpful to test environments different from your local system. You will need to install Docker on a Linux, Windows, or macOS system (typically Linux will be much faster than Windows or macOS because the latter use virtual -machines to emulate a Linux environment). To enter interactive mode which will -start a bash shell in the container, run `src/ci/docker/run.sh --dev ` -where `` is one of the directory names in `src/ci/docker` (for example -`x86_64-gnu` is a fairly standard Ubuntu environment). +machines to emulate a Linux environment). -The docker script will mount your local Rust source tree in read-only mode, -and an `obj` directory in read-write mode. All of the compiler artifacts will -be stored in the `obj` directory. The shell will start out in the `obj` -directory. From there, you can run `../src/ci/run.sh` which will run the build -as defined by the image. +Jobs running in CI are configured through a set of bash scripts, and it is not always trivial to reproduce their behavior locally. If you want to run a CI job locally in the simplest way possible, you can use a provided helper Python script that tries to replicate what happens on CI as closely as possible: -Alternatively, you can run individual commands to do specific tasks. For -example, you can run `../x test tests/ui` to just run UI tests. -Note that there is some configuration in the [`src/ci/run.sh`] script that you -may need to recreate. Particularly, set `submodules = false` in your -`config.toml` so that it doesn't attempt to modify the read-only directory. +```bash +python3 src/ci/github-actions/ci.py run-local +# For example: +python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux-alt +``` -Some additional notes about using the Docker images: +If the above script does not work for you, you would like to have more control of the Docker image execution, or you want to understand what exactly happens during Docker job execution, then continue reading below. +## The `run.sh` script +The [`src/ci/docker/run.sh`] script is used to build a specific Docker image, run it, +build Rust within the image, and either run tests or prepare a set of archives designed for distribution. The script will mount your local Rust source tree in read-only mode, and an `obj` directory in read-write mode. All the compiler artifacts will be stored in the `obj` directory. The shell will start out in the `obj`directory. From there, it will execute `../src/ci/run.sh` which starts the build as defined by the Docker image. + +You can run `src/ci/docker/run.sh ` directly. A few important notes regarding the `run.sh` script: +- When executed on CI, the script expects that all submodules are checked out. If some submodule that is accessed by the job is not available, the build will result in an error. You should thus make sure that you have all required submodules checked out locally. You can either do that manually through git, or set `submodules = true` in your `config.toml` and run a command such as `x build` to let bootstrap download the most important submodules (this might not be enough for the given CI job that you are trying to execute though). +- `` corresponds to a single directory located in one of the `src/ci/docker/host-*` directories. Note that image name does not necessarily correspond to a job name, as some jobs execute the same image, but with different environment variables or Docker build arguments (this is a part of the complexity that makes it difficult to run CI jobs locally). +- If you are executing a "dist" job (job beginning with `dist-`), you should set the `DEPLOY=1` environment variable. +- If you are executing an "alternative dist" job (job beginning with `dist-` and ending with `-alt`), you should set the `DEPLOY_ALT=1` environment variable. - Some of the std tests require IPv6 support. Docker on Linux seems to have it disabled by default. Run the commands in [`enable-docker-ipv6.sh`] to enable IPv6 before creating the container. This only needs to be done once. + +### Interactive mode + +Sometimes, it can be useful to build a specific Docker image, and then run custom commands inside it, so that you can experiment with how the given system behaves. You can do that using an interactive mode, which will +start a bash shell in the container, using `src/ci/docker/run.sh --dev `. + +When inside the Docker container, you can run individual commands to do specific tasks. For +example, you can run `../x test tests/ui` to just run UI tests. + +Some additional notes about using the interactive mode: + - The container will be deleted automatically when you exit the shell, however the build artifacts persist in the `obj` directory. If you are switching between different Docker images, the artifacts from previous environments @@ -45,15 +53,6 @@ Some additional notes about using the Docker images: containers. With the container name, run `docker exec -it /bin/bash` where `` is the container name like `4ba195e95cef`. -The approach described above is a relatively low-level interface for running the Docker images -directly. If you want to run a full CI Linux job locally with Docker, in a way that is as close to CI as possible, you can use the following command: - -```bash -python3 src/ci/github-actions/ci.py run-local -# For example: -python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux-alt -``` - [Docker]: https://www.docker.com/ [`src/ci/docker`]: https://github.com/rust-lang/rust/tree/master/src/ci/docker [`src/ci/docker/run.sh`]: https://github.com/rust-lang/rust/blob/master/src/ci/docker/run.sh diff --git a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md index 05693dcd5a18..cdcb90d3e2ed 100644 --- a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md +++ b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md @@ -40,7 +40,7 @@ requirements of impls and functions as explicit predicates. ### using implicit implied bounds as assumptions These bounds are not added to the `ParamEnv` of the affected item itself. For lexical -region resolution they are added using [`fn OutlivesEnvironment::new`]. +region resolution they are added using [`fn OutlivesEnvironment::from_normalized_bounds`]. Similarly, during MIR borrowck we add them using [`fn UniversalRegionRelationsBuilder::add_implied_bounds`]. @@ -55,7 +55,7 @@ The assumed outlives constraints for implicit bounds are computed using the MIR borrowck adds the outlives constraints for both the normalized and unnormalized types, lexical region resolution [only uses the unnormalized types][notnorm]. -[`fn OutlivesEnvironment::new`]: TODO +[`fn OutlivesEnvironment::from_normalized_bounds`]: https://github.com/rust-lang/rust/blob/8239a37f9c0951a037cfc51763ea52a20e71e6bd/compiler/rustc_infer/src/infer/outlives/env.rs#L50-L55 [`fn UniversalRegionRelationsBuilder::add_implied_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L316 [mir]: https://github.com/rust-lang/rust/blob/91cae1dcdcf1a31bd8a92e4a63793d65cfe289bb/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L258-L332 [`fn assumed_wf_types`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_ty_utils/src/implied_bounds.rs#L21 diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index c62ca9fd9ad6..00add2651ae8 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -135,7 +135,7 @@ As of `2025-01-02T`, the list of known names is as follows: - `windows` > Starting with 1.85.0, the `test` cfg is consider to be a "userspace" config -> despite being also set by `rustc` and should be managed by the build-system it-self. +> despite being also set by `rustc` and should be managed by the build system itself. Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` as argument to `--check-cfg`. diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index bb89d97a7984..28bb15952d0a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -165,11 +165,11 @@ target | std | notes `i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] -[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([PentiumPro with SSE](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] +[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI] [`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI] -[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? (Pentium 4, softfloat) | 32-bit UEFI +[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat) [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI) [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] @@ -311,12 +311,12 @@ target | std | host | notes [`i386-apple-ios`](platform-support/apple-ios.md) | ✓ | | 32-bit x86 iOS (Penryn) [^x86_32-floats-return-ABI] [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS (Pentium 4) [^x86_32-floats-return-ABI] [`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86 (original Pentium) [^x86_32-floats-x87] +[`i586-unknown-redox`](platform-support/redox.md) | ✓ | | 32-bit x86 Redox OS (PentiumPro) [^x86_32-floats-x87] [`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI] `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI] -[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-x87] +[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI] -[`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS (PentiumPro) [^x86_32-floats-x87] `i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] [`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] diff --git a/src/doc/rustc/src/platform-support/redox.md b/src/doc/rustc/src/platform-support/redox.md index 1b3321956ef7..2bba92d504c4 100644 --- a/src/doc/rustc/src/platform-support/redox.md +++ b/src/doc/rustc/src/platform-support/redox.md @@ -9,7 +9,7 @@ Target triplets available so far: - `x86_64-unknown-redox` (tier 2) - `aarch64-unknown-redox` (tier 3) -- `i686-unknown-redox` (tier 3) +- `i586-unknown-redox` (tier 3) ## Target maintainers @@ -36,7 +36,7 @@ target = [ "", "x86_64-unknown-redox", "aarch64-unknown-redox", - "i686-unknown-redox", + "i586-unknown-redox", ] ``` diff --git a/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md b/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md new file mode 100644 index 000000000000..b20c30ec8f1c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md @@ -0,0 +1,10 @@ +# `extended_varargs_abi_support` + +The tracking issue for this feature is: [#100189] + +[#100189]: https://github.com/rust-lang/rust/issues/100189 + +------------------------ + +This feature adds the possibility of using `sysv64`, `win64` or `efiapi` calling +conventions on functions with varargs. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index b6a73602a322..086a85aa616f 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 8c91cae49310..ed4b97d36252 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,72 +48,80 @@ 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], ) { write_header(out, "rust-example-rendered", None, tooltip, extra_classes); - write_code(out, src, None, None); + write_code(out, src, None, None, None); write_footer(out, playground_button); } 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`
@@ -150,6 +158,7 @@ struct TokenHandler<'a, 'tcx, F: Write> {
     /// used to generate links.
     pending_elems: Vec<(&'a str, Option)>,
     href_context: Option>,
+    write_line_number: fn(&mut F, u32, &'static str),
 }
 
 impl TokenHandler<'_, '_, F> {
@@ -182,7 +191,14 @@ impl TokenHandler<'_, '_, F> {
             && can_merge(current_class, Some(*parent_class), "")
         {
             for (text, class) in self.pending_elems.iter() {
-                string(self.out, EscapeBodyText(text), *class, &self.href_context, false);
+                string(
+                    self.out,
+                    EscapeBodyText(text),
+                    *class,
+                    &self.href_context,
+                    false,
+                    self.write_line_number,
+                );
             }
         } else {
             // We only want to "open" the tag ourselves if we have more than one pending and if the
@@ -204,6 +220,7 @@ impl TokenHandler<'_, '_, F> {
                     *class,
                     &self.href_context,
                     close_tag.is_none(),
+                    self.write_line_number,
                 );
             }
             if let Some(close_tag) = close_tag {
@@ -213,6 +230,11 @@ impl TokenHandler<'_, '_, F> {
         self.pending_elems.clear();
         true
     }
+
+    #[inline]
+    fn write_line_number(&mut self, line: u32, extra: &'static str) {
+        (self.write_line_number)(&mut self.out, line, extra);
+    }
 }
 
 impl Drop for TokenHandler<'_, '_, F> {
@@ -226,6 +248,43 @@ impl Drop for TokenHandler<'_, '_, F> {
     }
 }
 
+fn write_scraped_line_number(out: &mut impl Write, line: u32, extra: &'static str) {
+    // https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
+    // Do not show "1 2 3 4 5 ..." in web search results.
+    write!(out, "{extra}{line}",).unwrap();
+}
+
+fn write_line_number(out: &mut impl Write, line: u32, extra: &'static str) {
+    // https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
+    // Do not show "1 2 3 4 5 ..." in web search results.
+    write!(out, "{extra}{line}",).unwrap();
+}
+
+fn empty_line_number(out: &mut impl Write, _: u32, extra: &'static str) {
+    out.write_str(extra).unwrap();
+}
+
+#[derive(Clone, Copy)]
+pub(super) struct LineInfo {
+    pub(super) start_line: u32,
+    max_lines: u32,
+    pub(super) is_scraped_example: bool,
+}
+
+impl LineInfo {
+    pub(super) fn new(max_lines: u32) -> Self {
+        Self { start_line: 1, max_lines: max_lines + 1, is_scraped_example: false }
+    }
+
+    pub(super) fn new_scraped(max_lines: u32, start_line: u32) -> Self {
+        Self {
+            start_line: start_line + 1,
+            max_lines: max_lines + start_line + 1,
+            is_scraped_example: true,
+        }
+    }
+}
+
 /// Convert the given `src` source code into HTML by adding classes for highlighting.
 ///
 /// This code is used to render code blocks (in the documentation) as well as the source code pages.
@@ -242,6 +301,7 @@ pub(super) fn write_code(
     src: &str,
     href_context: Option>,
     decoration_info: Option<&DecorationInfo>,
+    line_info: Option,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
@@ -252,6 +312,23 @@ pub(super) fn write_code(
         current_class: None,
         pending_elems: Vec::new(),
         href_context,
+        write_line_number: match line_info {
+            Some(line_info) => {
+                if line_info.is_scraped_example {
+                    write_scraped_line_number
+                } else {
+                    write_line_number
+                }
+            }
+            None => empty_line_number,
+        },
+    };
+
+    let (mut line, max_lines) = if let Some(line_info) = line_info {
+        token_handler.write_line_number(line_info.start_line, "");
+        (line_info.start_line, line_info.max_lines)
+    } else {
+        (0, u32::MAX)
     };
 
     Classifier::new(
@@ -282,7 +359,14 @@ pub(super) fn write_code(
                 if need_current_class_update {
                     token_handler.current_class = class.map(Class::dummy);
                 }
-                token_handler.pending_elems.push((text, class));
+                if text == "\n" {
+                    line += 1;
+                    if line < max_lines {
+                        token_handler.pending_elems.push((text, Some(Class::Backline(line))));
+                    }
+                } else {
+                    token_handler.pending_elems.push((text, class));
+                }
             }
             Highlight::EnterSpan { class } => {
                 let mut should_add = true;
@@ -322,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. @@ -348,6 +432,7 @@ enum Class { PreludeVal(Span), QuestionMark, Decoration(&'static str), + Backline(u32), } impl Class { @@ -396,6 +481,7 @@ impl Class { Class::PreludeVal(_) => "prelude-val", Class::QuestionMark => "question-mark", Class::Decoration(kind) => kind, + Class::Backline(_) => "", } } @@ -419,7 +505,8 @@ impl Class { | Self::Bool | Self::Lifetime | Self::QuestionMark - | Self::Decoration(_) => None, + | Self::Decoration(_) + | Self::Backline(_) => None, } } } @@ -694,8 +781,13 @@ impl<'src> Classifier<'src> { ) { let lookahead = self.peek(); let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None }); + let whitespace = |sink: &mut dyn FnMut(_)| { + for part in text.split('\n').intersperse("\n").filter(|s| !s.is_empty()) { + sink(Highlight::Token { text: part, class: None }); + } + }; let class = match token { - TokenKind::Whitespace => return no_highlight(sink), + TokenKind::Whitespace => return whitespace(sink), TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => { if doc_style.is_some() { Class::DocComment @@ -716,7 +808,7 @@ impl<'src> Classifier<'src> { // or a reference or pointer type. Unless, of course, it looks like // a logical and or a multiplication operator: `&&` or `* `. TokenKind::Star => match self.tokens.peek() { - Some((TokenKind::Whitespace, _)) => return no_highlight(sink), + Some((TokenKind::Whitespace, _)) => return whitespace(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) }); @@ -740,7 +832,7 @@ impl<'src> Classifier<'src> { sink(Highlight::Token { text: "&=", class: None }); return; } - Some((TokenKind::Whitespace, _)) => return no_highlight(sink), + Some((TokenKind::Whitespace, _)) => return whitespace(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) }); @@ -887,7 +979,9 @@ impl<'src> Classifier<'src> { }; // Anything that didn't return above is the simple case where we the // class just spans a single token, so we can use the `string` method. - sink(Highlight::Token { text, class: Some(class) }); + for part in text.split('\n').intersperse("\n").filter(|s| !s.is_empty()) { + sink(Highlight::Token { text: part, class: Some(class) }); + } } fn peek(&mut self) -> Option { @@ -939,14 +1033,18 @@ fn exit_span(out: &mut impl Write, closing_tag: &str) { /// Note that if `context` is not `None` and that the given `klass` contains a `Span`, the function /// will then try to find this `span` in the `span_correspondence_map`. If found, it'll then /// generate a link for this element (which corresponds to where its definition is located). -fn string( - out: &mut impl Write, +fn string( + out: &mut W, text: T, klass: Option, href_context: &Option>, open_tag: bool, + write_line_number_callback: fn(&mut W, u32, &'static str), ) { - if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag) + if let Some(Class::Backline(line)) = klass { + write_line_number_callback(out, line, "\n"); + } else if let Some(closing_tag) = + string_without_closing_tag(out, text, klass, href_context, open_tag) { out.write_str(closing_tag).unwrap(); } diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index fccbb98f80ff..2603e887bead 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#"