Merge from rustc
This commit is contained in:
commit
dc8dbd25a4
1665 changed files with 15292 additions and 10795 deletions
23
Cargo.lock
23
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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Ordering> {
|
||||
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<H: Hasher>(&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<C> HashStable<C> 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<Abi, AbiUnsupported> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -2249,7 +2249,7 @@ pub enum TyKind {
|
|||
CVarArgs,
|
||||
/// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero<u32>`,
|
||||
/// just as part of the type system.
|
||||
Pat(P<Ty>, P<Pat>),
|
||||
Pat(P<Ty>, P<TyPat>),
|
||||
/// 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<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
/// 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<P<AnonConst>>, Option<P<AnonConst>>, Spanned<RangeEnd>),
|
||||
|
||||
/// 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)]
|
||||
|
|
|
|||
|
|
@ -210,6 +210,10 @@ pub trait MutVisitor: Sized {
|
|||
walk_ty(self, t);
|
||||
}
|
||||
|
||||
fn visit_ty_pat(&mut self, t: &mut P<TyPat>) {
|
||||
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<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
|||
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<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
|||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_ty_pat<T: MutVisitor>(vis: &mut T, ty: &mut P<TyPat>) {
|
||||
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<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) {
|
||||
let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod;
|
||||
visit_safety(vis, safety);
|
||||
|
|
|
|||
|
|
@ -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<P<QSelf>>) -> V::Result {
|
||||
if let Some(qself) = qself {
|
||||
let QSelf { ty, path_span: _, position: _ } = &**qself;
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<InvalidAbiReason>,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<InvalidAbiSuggestion>,
|
||||
}
|
||||
|
||||
|
|
@ -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<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<Output = T>` 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<CoroutineKind>,
|
||||
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::<Vec<_>>();
|
||||
|
|
@ -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}\""),
|
||||
|
|
|
|||
|
|
@ -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<ast::ptr::P<ast::Expr>>,
|
||||
pub ensures: Option<FnContractLoweringEnsures<'hir>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct FnContractLoweringEnsures<'hir> {
|
||||
expr: ast::ptr::P<ast::Expr>,
|
||||
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<FnContractLoweringInfo<'hir>>,
|
||||
contract_ensures: Option<(Span, Ident, HirId)>,
|
||||
|
||||
coroutine_kind: Option<hir::CoroutineKind>,
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
142
compiler/rustc_ast_lowering/src/stability.rs
Normal file
142
compiler/rustc_ast_lowering/src/stability.rs
Normal file
|
|
@ -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,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<TyCtxt<'tcx>> + 'tcx> ToUnivers
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + '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<TyCtxt<'tcx>> + '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<ty::Region<'tcx>>,
|
||||
) -> Option<Diag<'infcx>> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -149,6 +149,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.normalize_with_category(value, location, ConstraintCategory::Boring)
|
||||
}
|
||||
|
||||
pub(super) fn deeply_normalize<T>(&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<T>(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -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<ScrubbedTraitError<'tcx>>| 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());
|
||||
|
|
|
|||
|
|
@ -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<ScrubbedTraitError<'tcx>>| 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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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<TokenStream, ErrorGuaranteed> {
|
||||
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<TokenStream, ErrorGuaranteed> {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<Ty>, P<Pat>)> {
|
||||
fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<TyPat>)> {
|
||||
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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ impl<T: ?Sized> LegacyReceiver for Box<T> {}
|
|||
#[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 {}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
|
|||
#[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 {}
|
||||
|
|
|
|||
|
|
@ -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 { .. });
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub struct OwnedTargetMachine {
|
|||
}
|
||||
|
||||
impl OwnedTargetMachine {
|
||||
pub fn new(
|
||||
pub(crate) fn new(
|
||||
triple: &CStr,
|
||||
cpu: &CStr,
|
||||
features: &CStr,
|
||||
|
|
|
|||
|
|
@ -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<ModuleLlvm>, 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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
|||
("aarch64", "fp16") => 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<LLVMFea
|
|||
/// Must express features in the way Rust understands them.
|
||||
///
|
||||
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
|
||||
pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
let mut features: FxHashSet<Symbol> = Default::default();
|
||||
|
||||
// Add base features for the target.
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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(");
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<G: EmissionGuarantee>(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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<TyCtxt<'tcx>>,
|
||||
{
|
||||
debug!("ensure_monomorphic_enough: ty={:?}", ty);
|
||||
if !ty.has_param() {
|
||||
return interp_ok(());
|
||||
}
|
||||
|
||||
struct FoundParam;
|
||||
struct UsedParamsNeedInstantiationVisitor {}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor {
|
||||
type Result = ControlFlow<FoundParam>;
|
||||
|
||||
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> {
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
94
compiler/rustc_error_codes/src/error_codes/E0802.md
Normal file
94
compiler/rustc_error_codes/src/error_codes/E0802.md
Normal file
|
|
@ -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`.
|
||||
|
|
@ -545,6 +545,7 @@ E0798: 0798,
|
|||
E0799: 0799,
|
||||
E0800: 0800,
|
||||
E0801: 0801,
|
||||
E0802: 0802,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ into_diag_arg_using_display!(
|
|||
SplitDebuginfo,
|
||||
ExitStatus,
|
||||
ErrCode,
|
||||
rustc_abi::ExternAbi,
|
||||
);
|
||||
|
||||
impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::TraitRef<I> {
|
||||
|
|
@ -108,13 +109,13 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTrait
|
|||
}
|
||||
|
||||
impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> {
|
||||
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
format!("{self:?}").into_diag_arg()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> {
|
||||
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
format!("{self:?}").into_diag_arg()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<ast::Ty>,
|
||||
default: Option<AnonConst>,
|
||||
) -> 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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||
args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + 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<Span> = segments
|
||||
.clone()
|
||||
.flat_map(|segment| segment.args().args)
|
||||
.map(|arg| arg.span())
|
||||
.collect();
|
||||
let arg_spans: Vec<Span> =
|
||||
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<Item = &'a hir::PathSegment<'a>> + 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<Span> = 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);
|
||||
|
|
|
|||
|
|
@ -1694,7 +1694,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
pub fn prohibit_generic_args<'a>(
|
||||
&self,
|
||||
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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![
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<T>(&self, value: ty::Binder<'tcx, T>) -> T
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#![feature(let_chains)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(try_blocks)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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<T>` 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<Ty<'tcx>> {
|
||||
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 }
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue