mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Merge pull request #19169 from lnicola/sync-from-rust
minor: Sync from downstream
This commit is contained in:
commit
0c9c489355
@ -9,6 +9,8 @@ end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[!src/llvm-project]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
|
@ -29,3 +29,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8
|
||||
99cb0c6bc399fb94a0ddde7e9b38e9c00d523bad
|
||||
# reformat with rustfmt edition 2024
|
||||
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
|
||||
# reformat with updated edition 2024
|
||||
1fcae03369abb4c2cc180cd5a49e1f4440a81300
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -54,6 +54,8 @@ no_llvm_build
|
||||
/library/target
|
||||
/src/bootstrap/target
|
||||
/src/tools/x/target
|
||||
# Created by `x vendor`
|
||||
/vendor
|
||||
# Created by default with `src/ci/docker/run.sh`
|
||||
/obj/
|
||||
# Created by nix dev shell / .envrc
|
||||
|
63
Cargo.lock
63
Cargo.lock
@ -420,9 +420,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.7"
|
||||
version = "1.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
|
||||
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@ -1209,16 +1209,6 @@ dependencies = [
|
||||
"tidy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "field-offset"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.25"
|
||||
@ -2007,7 +1997,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"fs-err",
|
||||
"rustc-hash 2.1.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -2295,15 +2285,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@ -3207,7 +3188,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rinja_parser",
|
||||
"rustc-hash 2.1.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
@ -3271,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"
|
||||
@ -3336,7 +3317,6 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand_xoshiro",
|
||||
"rustc_data_structures",
|
||||
"rustc_feature",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
@ -3398,6 +3378,7 @@ dependencies = [
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
@ -3428,7 +3409,6 @@ dependencies = [
|
||||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
@ -3673,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",
|
||||
@ -3702,6 +3682,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"ctrlc",
|
||||
"libc",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_lowering",
|
||||
"rustc_ast_passes",
|
||||
@ -4173,7 +4154,6 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"either",
|
||||
"field-offset",
|
||||
"gsgdt",
|
||||
"polonius-engine",
|
||||
"rustc-rayon-core",
|
||||
@ -4357,6 +4337,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_lowering",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
@ -4380,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,7 +4402,6 @@ dependencies = [
|
||||
name = "rustc_query_impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"field-offset",
|
||||
"measureme",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
@ -4442,6 +4422,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"parking_lot",
|
||||
"rustc-rayon-core",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
@ -4453,7 +4434,6 @@ dependencies = [
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"smallvec",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
@ -4776,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",
|
||||
]
|
||||
@ -5427,7 +5407,7 @@ dependencies = [
|
||||
"ignore",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
"rustc-hash 2.1.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"semver",
|
||||
"serde",
|
||||
"similar",
|
||||
@ -6215,16 +6195,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.58.0"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91cd28d93c692351f3a6e5615567c56756e330bee1c99c6bdd57bfc5ab15f589"
|
||||
checksum = "9b7fb600834d7e868f6e5bb748a86101427330fafbf9485c331b9d5f562d54a5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.96",
|
||||
"windows-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6305,12 +6280,6 @@ dependencies = [
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-metadata"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e837f3c3012cfe9e7086302a93f441a7999439be1ad4c530d55d2f6d2921809"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
|
127
RELEASES.md
127
RELEASES.md
@ -1,3 +1,130 @@
|
||||
Version 1.85.0 (2025-02-20)
|
||||
==========================
|
||||
|
||||
<a id="1.85.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [The 2024 Edition is now stable.](https://github.com/rust-lang/rust/pull/133349)
|
||||
See [the edition guide](https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html) for more details.
|
||||
- [Stabilize async closures](https://github.com/rust-lang/rust/pull/132706)
|
||||
See [RFC 3668](https://rust-lang.github.io/rfcs/3668-async-closures.html) for more details.
|
||||
- [Stabilize `#[diagnostic::do_not_recommend]`](https://github.com/rust-lang/rust/pull/132056)
|
||||
- [Add `unpredictable_function_pointer_comparisons` lint to warn against function pointer comparisons](https://github.com/rust-lang/rust/pull/118833)
|
||||
- [Lint on combining `#[no_mangle]` and `#[export_name]` attributes.](https://github.com/rust-lang/rust/pull/131558)
|
||||
|
||||
<a id="1.85.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [The unstable flag `-Zpolymorphize` has been removed](https://github.com/rust-lang/rust/pull/133883), see https://github.com/rust-lang/compiler-team/issues/810 for some background.
|
||||
|
||||
<a id="1.85.0-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
- [Promote `powerpc64le-unknown-linux-musl` to tier 2 with host tools](https://github.com/rust-lang/rust/pull/133801)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.85.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Panics in the standard library now have a leading `library/` in their path](https://github.com/rust-lang/rust/pull/132390)
|
||||
- [`std::env::home_dir()` on Windows now ignores the non-standard `$HOME` environment variable](https://github.com/rust-lang/rust/pull/132515)
|
||||
It will be un-deprecated in a subsequent release.
|
||||
- [Add `AsyncFn*` to the prelude in all editions.](https://github.com/rust-lang/rust/pull/132611)
|
||||
|
||||
<a id="1.85.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`BuildHasherDefault::new`](https://doc.rust-lang.org/stable/std/hash/struct.BuildHasherDefault.html#method.new)
|
||||
- [`ptr::fn_addr_eq`](https://doc.rust-lang.org/std/ptr/fn.fn_addr_eq.html)
|
||||
- [`io::ErrorKind::QuotaExceeded`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.QuotaExceeded)
|
||||
- [`io::ErrorKind::CrossesDevices`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.CrossesDevices)
|
||||
- [`{float}::midpoint`](https://doc.rust-lang.org/core/primitive.f32.html#method.midpoint)
|
||||
- [Unsigned `{integer}::midpoint`](https://doc.rust-lang.org/std/primitive.u64.html#method.midpoint)
|
||||
- [`NonZeroU*::midpoint`](https://doc.rust-lang.org/std/num/type.NonZeroU32.html#method.midpoint)
|
||||
- [impl `std::iter::Extend` for tuples with arity 1 through 12](https://doc.rust-lang.org/stable/std/iter/trait.Extend.html#impl-Extend%3C(A,)%3E-for-(EA,))
|
||||
- [`FromIterator<(A, ...)>` for tuples with arity 1 through 12](https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html#impl-FromIterator%3C(EA,)%3E-for-(A,))
|
||||
- [`std::task::Waker::noop`](https://doc.rust-lang.org/stable/std/task/struct.Waker.html#method.noop)
|
||||
|
||||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`mem::size_of_val`](https://doc.rust-lang.org/stable/std/mem/fn.size_of_val.html)
|
||||
- [`mem::align_of_val`](https://doc.rust-lang.org/stable/std/mem/fn.align_of_val.html)
|
||||
- [`Layout::for_value`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.for_value)
|
||||
- [`Layout::align_to`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.align_to)
|
||||
- [`Layout::pad_to_align`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.pad_to_align)
|
||||
- [`Layout::extend`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.extend)
|
||||
- [`Layout::array`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.array)
|
||||
- [`std::mem::swap`](https://doc.rust-lang.org/stable/std/mem/fn.swap.html)
|
||||
- [`std::ptr::swap`](https://doc.rust-lang.org/stable/std/ptr/fn.swap.html)
|
||||
- [`NonNull::new`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new)
|
||||
- [`HashMap::with_hasher`](https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html#method.with_hasher)
|
||||
- [`HashSet::with_hasher`](https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html#method.with_hasher)
|
||||
- [`BuildHasherDefault::new`](https://doc.rust-lang.org/stable/std/hash/struct.BuildHasherDefault.html#method.new)
|
||||
- [`<float>::recip`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.recip)
|
||||
- [`<float>::to_degrees`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.to_degrees)
|
||||
- [`<float>::to_radians`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.to_radians)
|
||||
- [`<float>::max`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.max)
|
||||
- [`<float>::min`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.min)
|
||||
- [`<float>::clamp`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.clamp)
|
||||
- [`<float>::abs`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.abs)
|
||||
- [`<float>::signum`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.signum)
|
||||
- [`<float>::copysign`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.copysign)
|
||||
- [`MaybeUninit::write`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.write)
|
||||
|
||||
<a id="1.85.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Add future-incompatibility warning against keywords in cfgs and add raw-idents](https://github.com/rust-lang/cargo/pull/14671/)
|
||||
- [Stabilize higher precedence trailing flags](https://github.com/rust-lang/cargo/pull/14900/)
|
||||
- [Pass `CARGO_CFG_FEATURE` to build scripts](https://github.com/rust-lang/cargo/pull/14902/)
|
||||
|
||||
<a id="1.85.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
- [Doc comment on impl blocks shows the first line, even when the impl block is collapsed](https://github.com/rust-lang/rust/pull/132155)
|
||||
|
||||
<a id="1.85.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [`rustc` no longer treats the `test` cfg as a well known check-cfg](https://github.com/rust-lang/rust/pull/131729), instead it is up to the build systems and users of `--check-cfg`[^check-cfg] to set it as a well known cfg using `--check-cfg=cfg(test)`.
|
||||
This is done to enable build systems like Cargo to set it conditionally, as not all source files are suitable for unit tests.
|
||||
[Cargo (for now) unconditionally sets the `test` cfg as a well known cfg](https://github.com/rust-lang/cargo/pull/14963).
|
||||
[^check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
|
||||
- [Disable potentially incorrect type inference if there are trivial and non-trivial where-clauses](https://github.com/rust-lang/rust/pull/132325)
|
||||
- `std::env::home_dir()` has been deprecated for years, because it can give surprising results in some Windows configurations if the `HOME` environment variable is set (which is not the normal configuration on Windows). We had previously avoided changing its behavior, out of concern for compatibility with code depending on this non-standard configuration. Given how long this function has been deprecated, we're now fixing its behavior as a bugfix. A subsequent release will remove the deprecation for this function.
|
||||
- [Make `core::ffi::c_char` signedness more closely match that of the platform-default `char`](https://github.com/rust-lang/rust/pull/132975)
|
||||
This changed `c_char` from an `i8` to `u8` or vice versa on many Tier 2 and 3
|
||||
targets (mostly Arm and RISC-V embedded targets). The new definition may
|
||||
result in compilation failures but fixes compatibility issues with C.
|
||||
The `libc` crate matches this change as of its 0.2.169 release.
|
||||
- [When compiling a nested `macro_rules` macro from an external crate, the content of the inner `macro_rules` is now built with the edition of the external crate, not the local crate.](https://github.com/rust-lang/rust/pull/133274)
|
||||
- [Increase `sparcv9-sun-solaris` and `x86_64-pc-solaris` Solaris baseline to 11.4.](https://github.com/rust-lang/rust/pull/133293)
|
||||
- [Show `abi_unsupported_vector_types` lint in future breakage reports](https://github.com/rust-lang/rust/pull/133374)
|
||||
- [Error if multiple super-trait instantiations of `dyn Trait` need associated types to be specified but only one is provided](https://github.com/rust-lang/rust/pull/133392)
|
||||
- [Change `powerpc64-ibm-aix` default `codemodel` to large](https://github.com/rust-lang/rust/pull/133811)
|
||||
|
||||
<a id="1.85.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Build `x86_64-unknown-linux-gnu` with LTO for C/C++ code (e.g., `jemalloc`)](https://github.com/rust-lang/rust/pull/134690)
|
||||
|
||||
Version 1.84.1 (2025-01-30)
|
||||
==========================
|
||||
|
||||
|
@ -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,12 +73,128 @@ 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.
|
||||
// * EfiApi is based on Win64 or C, so it also supports it.
|
||||
// * System falls back to C for functions with varargs.
|
||||
//
|
||||
// * Stdcall does not, because it would be impossible for the callee to clean
|
||||
// up the arguments. (callee doesn't know how many arguments are there)
|
||||
@ -83,7 +203,6 @@ impl Abi {
|
||||
match self {
|
||||
Self::C { .. }
|
||||
| Self::Cdecl { .. }
|
||||
| Self::System { .. }
|
||||
| Self::Aapcs { .. }
|
||||
| Self::Win64 { .. }
|
||||
| Self::SysV64 { .. }
|
||||
@ -93,255 +212,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)]
|
||||
|
@ -30,14 +30,6 @@ pub enum DiffMode {
|
||||
Forward,
|
||||
/// The target function, to be created using reverse mode AD.
|
||||
Reverse,
|
||||
/// The target function, to be created using forward mode AD.
|
||||
/// This target function will also be used as a source for higher order derivatives,
|
||||
/// so compute it before all Forward/Reverse targets and optimize it through llvm.
|
||||
ForwardFirst,
|
||||
/// The target function, to be created using reverse mode AD.
|
||||
/// This target function will also be used as a source for higher order derivatives,
|
||||
/// so compute it before all Forward/Reverse targets and optimize it through llvm.
|
||||
ReverseFirst,
|
||||
}
|
||||
|
||||
/// Dual and Duplicated (and their Only variants) are getting lowered to the same Enzyme Activity.
|
||||
@ -92,10 +84,10 @@ pub struct AutoDiffAttrs {
|
||||
|
||||
impl DiffMode {
|
||||
pub fn is_rev(&self) -> bool {
|
||||
matches!(self, DiffMode::Reverse | DiffMode::ReverseFirst)
|
||||
matches!(self, DiffMode::Reverse)
|
||||
}
|
||||
pub fn is_fwd(&self) -> bool {
|
||||
matches!(self, DiffMode::Forward | DiffMode::ForwardFirst)
|
||||
matches!(self, DiffMode::Forward)
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,8 +98,6 @@ impl Display for DiffMode {
|
||||
DiffMode::Source => write!(f, "Source"),
|
||||
DiffMode::Forward => write!(f, "Forward"),
|
||||
DiffMode::Reverse => write!(f, "Reverse"),
|
||||
DiffMode::ForwardFirst => write!(f, "ForwardFirst"),
|
||||
DiffMode::ReverseFirst => write!(f, "ReverseFirst"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,12 +115,12 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
|
||||
match mode {
|
||||
DiffMode::Error => false,
|
||||
DiffMode::Source => false,
|
||||
DiffMode::Forward | DiffMode::ForwardFirst => {
|
||||
DiffMode::Forward => {
|
||||
activity == DiffActivity::Dual
|
||||
|| activity == DiffActivity::DualOnly
|
||||
|| activity == DiffActivity::Const
|
||||
}
|
||||
DiffMode::Reverse | DiffMode::ReverseFirst => {
|
||||
DiffMode::Reverse => {
|
||||
activity == DiffActivity::Const
|
||||
|| activity == DiffActivity::Active
|
||||
|| activity == DiffActivity::ActiveOnly
|
||||
@ -166,10 +156,10 @@ pub fn valid_input_activity(mode: DiffMode, activity: DiffActivity) -> bool {
|
||||
return match mode {
|
||||
DiffMode::Error => false,
|
||||
DiffMode::Source => false,
|
||||
DiffMode::Forward | DiffMode::ForwardFirst => {
|
||||
DiffMode::Forward => {
|
||||
matches!(activity, Dual | DualOnly | Const)
|
||||
}
|
||||
DiffMode::Reverse | DiffMode::ReverseFirst => {
|
||||
DiffMode::Reverse => {
|
||||
matches!(activity, Active | ActiveOnly | Duplicated | DuplicatedOnly | Const)
|
||||
}
|
||||
};
|
||||
@ -200,8 +190,6 @@ impl FromStr for DiffMode {
|
||||
"Source" => Ok(DiffMode::Source),
|
||||
"Forward" => Ok(DiffMode::Forward),
|
||||
"Reverse" => Ok(DiffMode::Reverse),
|
||||
"ForwardFirst" => Ok(DiffMode::ForwardFirst),
|
||||
"ReverseFirst" => Ok(DiffMode::ReverseFirst),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
@ -419,7 +407,7 @@ fn compute_hir_hash(
|
||||
.iter_enumerated()
|
||||
.filter_map(|(def_id, info)| {
|
||||
let info = info.as_owner()?;
|
||||
let def_path_hash = tcx.hir().def_path_hash(def_id);
|
||||
let def_path_hash = tcx.hir_def_path_hash(def_id);
|
||||
Some((def_path_hash, info))
|
||||
})
|
||||
.collect();
|
||||
@ -509,7 +497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
"adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}",
|
||||
node_id,
|
||||
def_kind,
|
||||
self.tcx.hir().def_key(self.local_def_id(node_id)),
|
||||
self.tcx.hir_def_key(self.local_def_id(node_id)),
|
||||
);
|
||||
|
||||
let def_id = self.tcx.at(span).create_def(parent, name, def_kind).def_id();
|
||||
@ -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,
|
||||
|
@ -14,7 +14,7 @@ use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{Map, Visitor, walk_block, walk_expr};
|
||||
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};
|
||||
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
@ -348,13 +348,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
expr: Option<&'hir hir::Expr<'hir>>,
|
||||
pat: Option<&'hir hir::Pat<'hir>>,
|
||||
parent_pat: Option<&'hir hir::Pat<'hir>>,
|
||||
hir: rustc_middle::hir::map::Map<'hir>,
|
||||
tcx: TyCtxt<'hir>,
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.hir
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||
@ -396,7 +396,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
expr: None,
|
||||
pat: None,
|
||||
parent_pat: None,
|
||||
hir,
|
||||
tcx: self.infcx.tcx,
|
||||
};
|
||||
finder.visit_expr(expr);
|
||||
if let Some(span) = span
|
||||
@ -1082,7 +1082,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
] {
|
||||
for (destination, sp) in elements {
|
||||
if let Ok(hir_id) = destination.target_id
|
||||
&& let hir::Node::Expr(expr) = tcx.hir().hir_node(hir_id)
|
||||
&& let hir::Node::Expr(expr) = tcx.hir_node(hir_id)
|
||||
&& !matches!(
|
||||
sp.desugaring_kind(),
|
||||
Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop)
|
||||
@ -1437,7 +1437,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let Some(hir_generics) = tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
||||
.and_then(|def_id| tcx.hir_get_generics(def_id))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@ -1889,7 +1889,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
|
||||
fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'infcx>, place: Place<'tcx>) {
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
|
||||
|
||||
struct FindUselessClone<'tcx> {
|
||||
@ -1917,7 +1916,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
|
||||
let mut expr_finder = FindUselessClone::new(tcx, self.mir_def_id());
|
||||
|
||||
let body = hir.body(body_id).value;
|
||||
let body = tcx.hir_body(body_id).value;
|
||||
expr_finder.visit_expr(body);
|
||||
|
||||
struct Holds<'tcx> {
|
||||
@ -2106,7 +2105,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?;
|
||||
let mut expr_finder = FindExprBySpan::new(span, tcx);
|
||||
expr_finder.visit_expr(tcx.hir().body(body_id).value);
|
||||
expr_finder.visit_expr(tcx.hir_body(body_id).value);
|
||||
expr_finder.result
|
||||
}
|
||||
|
||||
@ -2258,7 +2257,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
) {
|
||||
let issue_span = issued_spans.args_or_use();
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
|
||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
|
||||
let typeck_results = tcx.typeck(self.mir_def_id());
|
||||
@ -2346,7 +2344,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
pat_span: None,
|
||||
head: None,
|
||||
};
|
||||
finder.visit_expr(hir.body(body_id).value);
|
||||
finder.visit_expr(tcx.hir_body(body_id).value);
|
||||
|
||||
if let Some(body_expr) = finder.body_expr
|
||||
&& let Some(loop_span) = finder.loop_span
|
||||
@ -2454,10 +2452,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
// Get the body the error happens in
|
||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
|
||||
|
||||
let body_expr = hir.body(body_id).value;
|
||||
let body_expr = tcx.hir_body(body_id).value;
|
||||
|
||||
struct ClosureFinder<'hir> {
|
||||
hir: rustc_middle::hir::map::Map<'hir>,
|
||||
tcx: TyCtxt<'hir>,
|
||||
borrow_span: Span,
|
||||
res: Option<(&'hir hir::Expr<'hir>, &'hir hir::Closure<'hir>)>,
|
||||
/// The path expression with the `borrow_span` span
|
||||
@ -2466,8 +2464,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
impl<'hir> Visitor<'hir> for ClosureFinder<'hir> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.hir
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
||||
@ -2493,7 +2491,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
|
||||
// Find the closure that most tightly wraps `capture_kind_span`
|
||||
let mut finder =
|
||||
ClosureFinder { hir, borrow_span: capture_kind_span, res: None, error_path: None };
|
||||
ClosureFinder { tcx, borrow_span: capture_kind_span, res: None, error_path: None };
|
||||
finder.visit_expr(body_expr);
|
||||
let Some((closure_expr, closure)) = finder.res else { return };
|
||||
|
||||
@ -2558,7 +2556,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
|
||||
let mut finder = VariableUseFinder { local_id, spans: Vec::new() };
|
||||
finder.visit_expr(hir.body(closure.body).value);
|
||||
finder.visit_expr(tcx.hir_body(closure.body).value);
|
||||
|
||||
spans = finder.spans;
|
||||
} else {
|
||||
@ -3211,7 +3209,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
if let Some(scope) = self.body.source_scopes.get(source_info.scope)
|
||||
&& let ClearCrossCrate::Set(scope_data) = &scope.local_data
|
||||
&& let Some(id) = self.infcx.tcx.hir_node(scope_data.lint_root).body_id()
|
||||
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
|
||||
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir_body(id).value.kind
|
||||
{
|
||||
for stmt in block.stmts {
|
||||
let mut visitor = NestedStatementVisitor {
|
||||
|
@ -75,10 +75,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
|
||||
if let Some(span) = borrow_span {
|
||||
let def_id = body.source.def_id();
|
||||
if let Some(node) = tcx.hir().get_if_local(def_id)
|
||||
if let Some(node) = tcx.hir_get_if_local(def_id)
|
||||
&& let Some(body_id) = node.body_id()
|
||||
{
|
||||
let body = tcx.hir().body(body_id);
|
||||
let body = tcx.hir_body(body_id);
|
||||
let mut expr_finder = FindExprBySpan::new(span, tcx);
|
||||
expr_finder.visit_expr(body.value);
|
||||
if let Some(mut expr) = expr_finder.result {
|
||||
@ -256,8 +256,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
|
||||
impl<'hir> rustc_hir::intravisit::Visitor<'hir> for FindLetExpr<'hir> {
|
||||
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
|
||||
if let hir::ExprKind::If(cond, _conseq, _alt)
|
||||
@ -308,9 +308,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
|
||||
} else if let Some((old, new)) = multiple_borrow_span
|
||||
&& let def_id = body.source.def_id()
|
||||
&& let Some(node) = tcx.hir().get_if_local(def_id)
|
||||
&& let Some(node) = tcx.hir_get_if_local(def_id)
|
||||
&& let Some(body_id) = node.body_id()
|
||||
&& let hir_body = tcx.hir().body(body_id)
|
||||
&& let hir_body = tcx.hir_body(body_id)
|
||||
&& let mut expr_finder = (FindLetExpr { span: old, result: None, tcx })
|
||||
&& let Some((let_expr_span, let_expr_pat, let_expr_init)) = {
|
||||
expr_finder.visit_expr(hir_body.value);
|
||||
|
@ -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
|
||||
@ -1220,7 +1220,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
.tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id))
|
||||
.and_then(|def_id| self.infcx.tcx.hir_get_generics(def_id))
|
||||
&& let spans = hir_generics
|
||||
.predicates
|
||||
.iter()
|
||||
|
@ -7,7 +7,7 @@ use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{self as hir, CaptureBy, ExprKind, HirId, Node};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
|
||||
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
||||
@ -347,7 +347,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
// Find the closure that captured the binding.
|
||||
let mut expr_finder = FindExprBySpan::new(args_span, tcx);
|
||||
expr_finder.include_closures = true;
|
||||
expr_finder.visit_expr(tcx.hir().body(body_id).value);
|
||||
expr_finder.visit_expr(tcx.hir_body(body_id).value);
|
||||
let Some(closure_expr) = expr_finder.result else { return };
|
||||
let ExprKind::Closure(closure) = closure_expr.kind else { return };
|
||||
// We'll only suggest cloning the binding if it's a `move` closure.
|
||||
@ -357,7 +357,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let use_span = use_spans.var_or_use();
|
||||
let mut expr_finder = FindExprBySpan::new(use_span, tcx);
|
||||
expr_finder.include_closures = true;
|
||||
expr_finder.visit_expr(tcx.hir().body(body_id).value);
|
||||
expr_finder.visit_expr(tcx.hir_body(body_id).value);
|
||||
let Some(use_expr) = expr_finder.result else { return };
|
||||
let parent = tcx.parent_hir_node(use_expr.hir_id);
|
||||
if let Node::Expr(expr) = parent
|
||||
@ -690,7 +690,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
/// make it bind by reference instead (if possible)
|
||||
struct BindingFinder<'tcx> {
|
||||
typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||
hir: rustc_middle::hir::map::Map<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
/// Input: the span of the pattern we're finding bindings in
|
||||
pat_span: Span,
|
||||
/// Input: the spans of the bindings we're providing suggestions for
|
||||
@ -709,8 +709,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> {
|
||||
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.hir
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
||||
@ -782,7 +782,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
let mut finder = BindingFinder {
|
||||
typeck_results,
|
||||
hir,
|
||||
tcx: self.infcx.tcx,
|
||||
pat_span,
|
||||
binding_spans,
|
||||
found_pat: false,
|
||||
|
@ -936,11 +936,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) {
|
||||
err.span_label(sp, format!("cannot {act}"));
|
||||
|
||||
let hir = self.infcx.tcx.hir();
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
let closure_id = self.mir_hir_id();
|
||||
let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
|
||||
let fn_call_id = self.infcx.tcx.parent_hir_id(closure_id);
|
||||
let node = self.infcx.tcx.hir_node(fn_call_id);
|
||||
let closure_span = tcx.def_span(self.mir_def_id());
|
||||
let fn_call_id = tcx.parent_hir_id(closure_id);
|
||||
let node = tcx.hir_node(fn_call_id);
|
||||
let def_id = hir.enclosing_body_owner(fn_call_id);
|
||||
let mut look_at_return = true;
|
||||
|
||||
@ -951,7 +952,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
return None;
|
||||
};
|
||||
|
||||
let typeck_results = self.infcx.tcx.typeck(def_id);
|
||||
let typeck_results = tcx.typeck(def_id);
|
||||
|
||||
match kind {
|
||||
hir::ExprKind::Call(expr, args) => {
|
||||
@ -980,7 +981,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
.map(|(pos, _)| pos)
|
||||
.next();
|
||||
|
||||
let arg = match hir.get_if_local(callee_def_id) {
|
||||
let arg = match tcx.hir_get_if_local(callee_def_id) {
|
||||
Some(
|
||||
hir::Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Fn { sig, .. }, ..
|
||||
@ -1022,7 +1023,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
if look_at_return && hir.get_fn_id_for_return_block(closure_id).is_some() {
|
||||
// ...otherwise we are probably in the tail expression of the function, point at the
|
||||
// return type.
|
||||
match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
|
||||
match tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
|
||||
hir::Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Fn { sig, .. }, ..
|
||||
})
|
||||
@ -1050,9 +1051,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
|
||||
fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
|
||||
let source = self.body.source;
|
||||
let hir = self.infcx.tcx.hir();
|
||||
if let InstanceKind::Item(def_id) = source.instance
|
||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) =
|
||||
self.infcx.tcx.hir_get_if_local(def_id)
|
||||
&& let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
|
||||
&& let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
|
||||
{
|
||||
|
@ -14,7 +14,10 @@ use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
|
||||
use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor};
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor,
|
||||
};
|
||||
use rustc_span::{Ident, Span, kw};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::error_reporting::infer::nice_region_error::{
|
||||
@ -147,9 +150,7 @@ pub(crate) enum RegionErrorKind<'tcx> {
|
||||
pub(crate) struct ErrorConstraintInfo<'tcx> {
|
||||
// fr: outlived_fr
|
||||
pub(super) fr: RegionVid,
|
||||
pub(super) fr_is_local: bool,
|
||||
pub(super) outlived_fr: RegionVid,
|
||||
pub(super) outlived_fr_is_local: bool,
|
||||
|
||||
// Category and span for best blame constraint
|
||||
pub(super) category: ConstraintCategory<'tcx>,
|
||||
@ -185,6 +186,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the regions in the type to named regions, where possible.
|
||||
fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
fold_regions(tcx, ty, |region, _| match *region {
|
||||
ty::ReVar(vid) => self.to_error_region(vid).unwrap_or(region),
|
||||
_ => region,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
|
||||
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
|
||||
if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref()
|
||||
@ -207,7 +219,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
lower_bound: RegionVid,
|
||||
) {
|
||||
let mut suggestions = vec![];
|
||||
let hir = self.infcx.tcx.hir();
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
// find generic associated types in the given region 'lower_bound'
|
||||
let gat_id_and_generics = self
|
||||
@ -216,12 +228,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
.map(|placeholder| {
|
||||
if let Some(id) = placeholder.bound.kind.get_id()
|
||||
&& let Some(placeholder_id) = id.as_local()
|
||||
&& let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id)
|
||||
&& let Some(generics_impl) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id))
|
||||
.generics()
|
||||
&& let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id)
|
||||
&& let Some(generics_impl) =
|
||||
tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics()
|
||||
{
|
||||
Some((gat_hir_id, generics_impl))
|
||||
} else {
|
||||
@ -242,7 +251,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
};
|
||||
if bound_generic_params
|
||||
.iter()
|
||||
.rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
|
||||
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
|
||||
.is_some()
|
||||
{
|
||||
for bound in *bounds {
|
||||
@ -258,7 +267,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
return;
|
||||
};
|
||||
diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static);
|
||||
let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local())
|
||||
let Some(generics_fn) = tcx.hir_get_generics(self.body.source.def_id().expect_local())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@ -316,13 +325,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let type_test_span = type_test.span;
|
||||
|
||||
if let Some(lower_bound_region) = lower_bound_region {
|
||||
let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
|
||||
let generic_ty = self.name_regions(
|
||||
self.infcx.tcx,
|
||||
type_test.generic_kind.to_ty(self.infcx.tcx),
|
||||
);
|
||||
let origin = RelateParamBound(type_test_span, generic_ty, None);
|
||||
self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure(
|
||||
self.body.source.def_id().expect_local(),
|
||||
type_test_span,
|
||||
Some(origin),
|
||||
type_test.generic_kind,
|
||||
self.name_regions(self.infcx.tcx, type_test.generic_kind),
|
||||
lower_bound_region,
|
||||
));
|
||||
} else {
|
||||
@ -353,9 +365,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
|
||||
RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => {
|
||||
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
|
||||
let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
|
||||
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
|
||||
let named_ty =
|
||||
self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, hidden_ty);
|
||||
let named_key =
|
||||
self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, key);
|
||||
let named_region = self
|
||||
.regioncx
|
||||
.name_regions_for_member_constraint(self.infcx.tcx, member_region);
|
||||
let diag = unexpected_hidden_region_diagnostic(
|
||||
self.infcx,
|
||||
self.mir_def_id(),
|
||||
@ -468,14 +484,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
fr_is_local, outlived_fr_is_local, category
|
||||
);
|
||||
|
||||
let errci = ErrorConstraintInfo {
|
||||
fr,
|
||||
outlived_fr,
|
||||
fr_is_local,
|
||||
outlived_fr_is_local,
|
||||
category,
|
||||
span: cause.span,
|
||||
};
|
||||
let errci = ErrorConstraintInfo { fr, outlived_fr, category, span: cause.span };
|
||||
|
||||
let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
|
||||
(ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
|
||||
@ -677,11 +686,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
&& self.regioncx.universal_regions().defining_ty.is_fn_def())
|
||||
|| self.regioncx.universal_regions().defining_ty.is_const()
|
||||
{
|
||||
return self.report_general_error(&ErrorConstraintInfo {
|
||||
fr_is_local: true,
|
||||
outlived_fr_is_local: false,
|
||||
..*errci
|
||||
});
|
||||
return self.report_general_error(errci);
|
||||
}
|
||||
|
||||
let mut diag =
|
||||
@ -759,15 +764,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
|
||||
let ErrorConstraintInfo {
|
||||
fr,
|
||||
fr_is_local,
|
||||
outlived_fr,
|
||||
outlived_fr_is_local,
|
||||
span,
|
||||
category,
|
||||
..
|
||||
} = errci;
|
||||
let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci;
|
||||
|
||||
let mir_def_name = self.infcx.tcx.def_descr(self.mir_def_id().to_def_id());
|
||||
|
||||
@ -786,19 +783,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
|
||||
outlived_fr_name.highlight_region_name(&mut diag);
|
||||
|
||||
let err_category = match (category, outlived_fr_is_local, fr_is_local) {
|
||||
(ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn {
|
||||
let err_category = if matches!(category, ConstraintCategory::Return(_))
|
||||
&& self.regioncx.universal_regions().is_local_free_region(*outlived_fr)
|
||||
{
|
||||
LifetimeReturnCategoryErr::WrongReturn {
|
||||
span: *span,
|
||||
mir_def_name,
|
||||
outlived_fr_name,
|
||||
fr_name: &fr_name,
|
||||
},
|
||||
_ => LifetimeReturnCategoryErr::ShortReturn {
|
||||
}
|
||||
} else {
|
||||
LifetimeReturnCategoryErr::ShortReturn {
|
||||
span: *span,
|
||||
category_desc: category.description(),
|
||||
free_region_name: &fr_name,
|
||||
outlived_fr_name,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
diag.subdiagnostic(err_category);
|
||||
@ -1159,7 +1159,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
|
||||
if ocx.select_all_or_error().is_empty() && count > 0 {
|
||||
diag.span_suggestion_verbose(
|
||||
tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
|
||||
tcx.hir_body(*body).value.peel_blocks().span.shrink_to_lo(),
|
||||
fluent::borrowck_dereference_suggestion,
|
||||
"*".repeat(count),
|
||||
Applicability::MachineApplicable,
|
||||
|
@ -204,7 +204,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// that the regions produced are in fact equal to the named region they are
|
||||
/// replaced with. This is fine because this function is only to improve the
|
||||
/// region names in error messages.
|
||||
pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
|
||||
///
|
||||
/// This differs from `MirBorrowckCtxt::name_regions` since it is particularly
|
||||
/// lax with mapping region vids that are *shorter* than a universal region to
|
||||
/// that universal region. This is useful for member region constraints since
|
||||
/// we want to suggest a universal region name to capture even if it's technically
|
||||
/// not equal to the error region.
|
||||
pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -188,8 +188,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# FIXME update at some point in the future once most distros use a newer glibc
|
||||
- os: ubuntu-20.04
|
||||
# Intentionally using an older ubuntu version to lower the glibc requirements of the distributed cg_clif
|
||||
- os: ubuntu-22.04
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
|
@ -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 {}
|
||||
|
@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../core" }
|
||||
-compiler_builtins = { version = "=0.1.145", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.145", features = ['rustc-dep-of-std', 'no-f16-f128'] }
|
||||
-compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std', 'no-f16-f128'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
|
@ -1,4 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2025-02-07"
|
||||
channel = "nightly-2025-02-15"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
profile = "minimal"
|
||||
|
@ -3,8 +3,9 @@ ignore = [
|
||||
]
|
||||
|
||||
# Matches rustfmt.toml of rustc
|
||||
version = "Two"
|
||||
style_edition = "2024"
|
||||
use_small_heuristics = "Max"
|
||||
merge_derives = false
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Module"
|
||||
use_field_init_shorthand = true
|
||||
|
@ -65,11 +65,7 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call
|
||||
sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented");
|
||||
}
|
||||
|
||||
Conv::Msp430Intr
|
||||
| Conv::PtxKernel
|
||||
| Conv::GpuKernel
|
||||
| Conv::AvrInterrupt
|
||||
| Conv::AvrNonBlockingInterrupt => {
|
||||
Conv::Msp430Intr | Conv::GpuKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => {
|
||||
unreachable!("tried to use {c:?} call conv which only exists on an unsupported target");
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ pub(super) fn from_casted_value<'tcx>(
|
||||
// It may also be smaller for example when the type is a wrapper around an integer with a
|
||||
// larger alignment than the integer.
|
||||
std::cmp::max(abi_param_size, layout_size),
|
||||
u32::try_from(layout.align.pref.bytes()).unwrap(),
|
||||
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
||||
);
|
||||
let mut offset = 0;
|
||||
let mut block_params_iter = block_params.iter().copied();
|
||||
|
@ -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 {
|
||||
|
@ -382,6 +382,11 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
||||
}
|
||||
|
||||
pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer {
|
||||
assert!(
|
||||
size % align == 0,
|
||||
"size must be a multiple of alignment (size={size}, align={align})"
|
||||
);
|
||||
|
||||
let abi_align = if self.tcx.sess.target.arch == "s390x" { 8 } else { 16 };
|
||||
if align <= abi_align {
|
||||
let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData {
|
||||
@ -403,7 +408,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
||||
align_shift: 4,
|
||||
});
|
||||
let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0);
|
||||
let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align));
|
||||
let misalign_offset = self.bcx.ins().band_imm(base_ptr, i64::from(align - 1));
|
||||
let realign_offset = self.bcx.ins().irsub_imm(misalign_offset, i64::from(align));
|
||||
Pointer::new(self.bcx.ins().iadd(base_ptr, realign_offset))
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ impl DebugContext {
|
||||
entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id)));
|
||||
entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line));
|
||||
|
||||
entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.pref.bytes()));
|
||||
entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.abi.bytes()));
|
||||
|
||||
let mut expr = Expression::new();
|
||||
expr.op_addr(address_for_data(data_id));
|
||||
|
@ -166,7 +166,7 @@ impl DebugContext {
|
||||
let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id);
|
||||
tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name)));
|
||||
tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes()));
|
||||
tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.pref.bytes()));
|
||||
tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.abi.bytes()));
|
||||
|
||||
for (i, (ty, dw_ty)) in components.into_iter().enumerate() {
|
||||
let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member);
|
||||
@ -179,7 +179,7 @@ impl DebugContext {
|
||||
member_entry.set(
|
||||
gimli::DW_AT_alignment,
|
||||
AttributeValue::Udata(
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.pref.bytes(),
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.abi.bytes(),
|
||||
),
|
||||
);
|
||||
member_entry.set(
|
||||
|
@ -124,7 +124,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec<
|
||||
crate::constant::codegen_static(tcx, &mut jit_module, def_id);
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
let item = tcx.hir().item(item_id);
|
||||
let item = tcx.hir_item(item_id);
|
||||
tcx.dcx().span_fatal(item.span, "Global asm is not supported in JIT mode");
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use rustc_target::asm::InlineAsmArch;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
|
||||
let item = tcx.hir().item(item_id);
|
||||
let item = tcx.hir_item(item_id);
|
||||
if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
|
||||
let is_x86 =
|
||||
matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
|
||||
|
@ -871,7 +871,8 @@ fn call_inline_asm<'tcx>(
|
||||
inputs: Vec<(Size, Value)>,
|
||||
outputs: Vec<(Size, CPlace<'tcx>)>,
|
||||
) {
|
||||
let stack_slot = fx.create_stack_slot(u32::try_from(slot_size.bytes()).unwrap(), 16);
|
||||
let stack_slot =
|
||||
fx.create_stack_slot(u32::try_from(slot_size.bytes().next_multiple_of(16)).unwrap(), 16);
|
||||
|
||||
let inline_asm_func = fx
|
||||
.module
|
||||
|
@ -289,7 +289,7 @@ fn build_isa(sess: &Session) -> Arc<dyn TargetIsa + 'static> {
|
||||
flags_builder.set("opt_level", "none").unwrap();
|
||||
}
|
||||
OptLevel::Less
|
||||
| OptLevel::Default
|
||||
| OptLevel::More
|
||||
| OptLevel::Size
|
||||
| OptLevel::SizeMin
|
||||
| OptLevel::Aggressive => {
|
||||
|
@ -101,7 +101,7 @@ impl<'tcx> CValue<'tcx> {
|
||||
/// The is represented by a dangling pointer of suitable alignment.
|
||||
pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
|
||||
assert!(layout.is_zst());
|
||||
CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout)
|
||||
CValue::by_ref(crate::Pointer::dangling(layout.align.abi), layout)
|
||||
}
|
||||
|
||||
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
@ -392,7 +392,7 @@ impl<'tcx> CPlace<'tcx> {
|
||||
assert!(layout.is_sized());
|
||||
if layout.size.bytes() == 0 {
|
||||
return CPlace {
|
||||
inner: CPlaceInner::Addr(Pointer::dangling(layout.align.pref), None),
|
||||
inner: CPlaceInner::Addr(Pointer::dangling(layout.align.abi), None),
|
||||
layout,
|
||||
};
|
||||
}
|
||||
@ -405,7 +405,7 @@ impl<'tcx> CPlace<'tcx> {
|
||||
|
||||
let stack_slot = fx.create_stack_slot(
|
||||
u32::try_from(layout.size.bytes()).unwrap(),
|
||||
u32::try_from(layout.align.pref.bytes()).unwrap(),
|
||||
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
||||
);
|
||||
CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout }
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -710,10 +710,6 @@ pub struct ThinBuffer {
|
||||
context: Arc<SyncContext>,
|
||||
}
|
||||
|
||||
// TODO: check if this makes sense to make ThinBuffer Send and Sync.
|
||||
unsafe impl Send for ThinBuffer {}
|
||||
unsafe impl Sync for ThinBuffer {}
|
||||
|
||||
impl ThinBuffer {
|
||||
pub(crate) fn new(context: &Arc<SyncContext>) -> Self {
|
||||
Self { context: Arc::clone(context) }
|
||||
|
@ -665,6 +665,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
a + b
|
||||
}
|
||||
|
||||
// TODO(antoyo): should we also override the `unchecked_` versions?
|
||||
fn sub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_sub(a, b)
|
||||
}
|
||||
@ -832,31 +833,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
set_rvalue_location(self, self.gcc_not(a))
|
||||
}
|
||||
|
||||
fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
set_rvalue_location(self, self.gcc_add(a, b))
|
||||
}
|
||||
|
||||
fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
set_rvalue_location(self, self.gcc_add(a, b))
|
||||
}
|
||||
|
||||
fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
set_rvalue_location(self, self.gcc_sub(a, b))
|
||||
}
|
||||
|
||||
fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// TODO(antoyo): should generate poison value?
|
||||
set_rvalue_location(self, self.gcc_sub(a, b))
|
||||
}
|
||||
|
||||
fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
set_rvalue_location(self, self.gcc_mul(a, b))
|
||||
}
|
||||
|
||||
fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
set_rvalue_location(self, self.gcc_mul(a, b))
|
||||
}
|
||||
|
||||
fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
set_rvalue_location(self, lhs + rhs)
|
||||
|
@ -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 { .. });
|
||||
|
||||
|
@ -476,7 +476,7 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
|
||||
Some(level) => match level {
|
||||
OptLevel::No => OptimizationLevel::None,
|
||||
OptLevel::Less => OptimizationLevel::Limited,
|
||||
OptLevel::Default => OptimizationLevel::Standard,
|
||||
OptLevel::More => OptimizationLevel::Standard,
|
||||
OptLevel::Aggressive => OptimizationLevel::Aggressive,
|
||||
OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
|
||||
},
|
||||
|
@ -38,9 +38,6 @@ codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type wit
|
||||
codegen_llvm_mismatch_data_layout =
|
||||
data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`
|
||||
|
||||
codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found
|
||||
codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
|
||||
|
||||
codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
|
||||
codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
|
||||
|
||||
|
@ -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
|
||||
@ -687,7 +687,6 @@ impl llvm::CallConv {
|
||||
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
|
||||
Conv::ArmAapcs => llvm::ArmAapcsCallConv,
|
||||
Conv::Msp430Intr => llvm::Msp430Intr,
|
||||
Conv::PtxKernel => llvm::PtxKernel,
|
||||
Conv::X86Fastcall => llvm::X86FastcallCallConv,
|
||||
Conv::X86Intr => llvm::X86_Intr,
|
||||
Conv::X86Stdcall => llvm::X86StdcallCallConv,
|
||||
|
@ -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 {
|
||||
|
@ -286,7 +286,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
InlineAsmArch::M68k => {
|
||||
constraints.push("~{ccr}".to_string());
|
||||
}
|
||||
InlineAsmArch::CSKY => {}
|
||||
InlineAsmArch::CSKY => {
|
||||
constraints.push("~{psr}".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
if !options.contains(InlineAsmOptions::NOMEM) {
|
||||
|
@ -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())
|
||||
|
@ -606,10 +606,31 @@ pub(crate) fn run_pass_manager(
|
||||
|
||||
// If this rustc version was build with enzyme/autodiff enabled, and if users applied the
|
||||
// `#[autodiff]` macro at least once, then we will later call llvm_optimize a second time.
|
||||
let first_run = true;
|
||||
debug!("running llvm pm opt pipeline");
|
||||
unsafe {
|
||||
write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage, first_run)?;
|
||||
write::llvm_optimize(
|
||||
cgcx,
|
||||
dcx,
|
||||
module,
|
||||
config,
|
||||
opt_level,
|
||||
opt_stage,
|
||||
write::AutodiffStage::DuringAD,
|
||||
)?;
|
||||
}
|
||||
// FIXME(ZuseZ4): Make this more granular
|
||||
if cfg!(llvm_enzyme) && !thin {
|
||||
unsafe {
|
||||
write::llvm_optimize(
|
||||
cgcx,
|
||||
dcx,
|
||||
module,
|
||||
config,
|
||||
opt_level,
|
||||
llvm::OptStage::FatLTO,
|
||||
write::AutodiffStage::PostAD,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
debug!("lto done");
|
||||
Ok(())
|
||||
@ -621,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) })
|
||||
}
|
||||
}
|
||||
@ -663,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(
|
||||
@ -138,7 +141,7 @@ fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::
|
||||
match cfg {
|
||||
No => (llvm::CodeGenOptLevel::None, llvm::CodeGenOptSizeNone),
|
||||
Less => (llvm::CodeGenOptLevel::Less, llvm::CodeGenOptSizeNone),
|
||||
Default => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeNone),
|
||||
More => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeNone),
|
||||
Aggressive => (llvm::CodeGenOptLevel::Aggressive, llvm::CodeGenOptSizeNone),
|
||||
Size => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeDefault),
|
||||
SizeMin => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeAggressive),
|
||||
@ -150,7 +153,7 @@ fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel
|
||||
match cfg {
|
||||
No => llvm::PassBuilderOptLevel::O0,
|
||||
Less => llvm::PassBuilderOptLevel::O1,
|
||||
Default => llvm::PassBuilderOptLevel::O2,
|
||||
More => llvm::PassBuilderOptLevel::O2,
|
||||
Aggressive => llvm::PassBuilderOptLevel::O3,
|
||||
Size => llvm::PassBuilderOptLevel::Os,
|
||||
SizeMin => llvm::PassBuilderOptLevel::Oz,
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,6 +537,16 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
|
||||
config.instrument_coverage.then(|| c"default_%m_%p.profraw".to_owned())
|
||||
}
|
||||
|
||||
// PreAD will run llvm opts but disable size increasing opts (vectorization, loop unrolling)
|
||||
// DuringAD is the same as above, but also runs the enzyme opt and autodiff passes.
|
||||
// PostAD will run all opts, including size increasing opts.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub(crate) enum AutodiffStage {
|
||||
PreAD,
|
||||
DuringAD,
|
||||
PostAD,
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn llvm_optimize(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
@ -537,7 +554,7 @@ pub(crate) unsafe fn llvm_optimize(
|
||||
config: &ModuleConfig,
|
||||
opt_level: config::OptLevel,
|
||||
opt_stage: llvm::OptStage,
|
||||
skip_size_increasing_opts: bool,
|
||||
autodiff_stage: AutodiffStage,
|
||||
) -> Result<(), FatalError> {
|
||||
// Enzyme:
|
||||
// The whole point of compiler based AD is to differentiate optimized IR instead of unoptimized
|
||||
@ -550,12 +567,16 @@ pub(crate) unsafe fn llvm_optimize(
|
||||
let unroll_loops;
|
||||
let vectorize_slp;
|
||||
let vectorize_loop;
|
||||
let run_enzyme = cfg!(llvm_enzyme) && autodiff_stage == AutodiffStage::DuringAD;
|
||||
|
||||
// When we build rustc with enzyme/autodiff support, we want to postpone size-increasing
|
||||
// optimizations until after differentiation. FIXME(ZuseZ4): Before shipping on nightly,
|
||||
// optimizations until after differentiation. Our pipeline is thus: (opt + enzyme), (full opt).
|
||||
// We therefore have two calls to llvm_optimize, if autodiff is used.
|
||||
//
|
||||
// FIXME(ZuseZ4): Before shipping on nightly,
|
||||
// we should make this more granular, or at least check that the user has at least one autodiff
|
||||
// call in their code, to justify altering the compilation pipeline.
|
||||
if skip_size_increasing_opts && cfg!(llvm_enzyme) {
|
||||
if cfg!(llvm_enzyme) && autodiff_stage != AutodiffStage::PostAD {
|
||||
unroll_loops = false;
|
||||
vectorize_slp = false;
|
||||
vectorize_loop = false;
|
||||
@ -565,7 +586,7 @@ pub(crate) unsafe fn llvm_optimize(
|
||||
vectorize_slp = config.vectorize_slp;
|
||||
vectorize_loop = config.vectorize_loop;
|
||||
}
|
||||
trace!(?unroll_loops, ?vectorize_slp, ?vectorize_loop);
|
||||
trace!(?unroll_loops, ?vectorize_slp, ?vectorize_loop, ?run_enzyme);
|
||||
let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed();
|
||||
let pgo_gen_path = get_pgo_gen_path(config);
|
||||
let pgo_use_path = get_pgo_use_path(config);
|
||||
@ -633,6 +654,7 @@ pub(crate) unsafe fn llvm_optimize(
|
||||
vectorize_loop,
|
||||
config.no_builtins,
|
||||
config.emit_lifetime_markers,
|
||||
run_enzyme,
|
||||
sanitizer_options.as_ref(),
|
||||
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
@ -661,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);
|
||||
|
||||
@ -670,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
|
||||
@ -684,18 +704,14 @@ pub(crate) unsafe fn optimize(
|
||||
_ => llvm::OptStage::PreLinkNoLTO,
|
||||
};
|
||||
|
||||
// If we know that we will later run AD, then we disable vectorization and loop unrolling
|
||||
let skip_size_increasing_opts = cfg!(llvm_enzyme);
|
||||
// If we know that we will later run AD, then we disable vectorization and loop unrolling.
|
||||
// Otherwise we pretend AD is already done and run the normal opt pipeline (=PostAD).
|
||||
// FIXME(ZuseZ4): Make this more granular, only set PreAD if we actually have autodiff
|
||||
// usages, not just if we build rustc with autodiff support.
|
||||
let autodiff_stage =
|
||||
if cfg!(llvm_enzyme) { AutodiffStage::PreAD } else { AutodiffStage::PostAD };
|
||||
return unsafe {
|
||||
llvm_optimize(
|
||||
cgcx,
|
||||
dcx,
|
||||
module,
|
||||
config,
|
||||
opt_level,
|
||||
opt_stage,
|
||||
skip_size_increasing_opts,
|
||||
)
|
||||
llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage, autodiff_stage)
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
@ -744,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.
|
||||
@ -887,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 {
|
||||
@ -925,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 => {
|
||||
@ -1066,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 {
|
||||
@ -1123,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.
|
||||
|
@ -421,6 +421,37 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
unchecked_umul(x, y) => LLVMBuildNUWMul,
|
||||
}
|
||||
|
||||
fn unchecked_suadd(&mut self, a: &'ll Value, b: &'ll Value) -> &'ll Value {
|
||||
unsafe {
|
||||
let add = llvm::LLVMBuildAdd(self.llbuilder, a, b, UNNAMED);
|
||||
if llvm::LLVMIsAInstruction(add).is_some() {
|
||||
llvm::LLVMSetNUW(add, True);
|
||||
llvm::LLVMSetNSW(add, True);
|
||||
}
|
||||
add
|
||||
}
|
||||
}
|
||||
fn unchecked_susub(&mut self, a: &'ll Value, b: &'ll Value) -> &'ll Value {
|
||||
unsafe {
|
||||
let sub = llvm::LLVMBuildSub(self.llbuilder, a, b, UNNAMED);
|
||||
if llvm::LLVMIsAInstruction(sub).is_some() {
|
||||
llvm::LLVMSetNUW(sub, True);
|
||||
llvm::LLVMSetNSW(sub, True);
|
||||
}
|
||||
sub
|
||||
}
|
||||
}
|
||||
fn unchecked_sumul(&mut self, a: &'ll Value, b: &'ll Value) -> &'ll Value {
|
||||
unsafe {
|
||||
let mul = llvm::LLVMBuildMul(self.llbuilder, a, b, UNNAMED);
|
||||
if llvm::LLVMIsAInstruction(mul).is_some() {
|
||||
llvm::LLVMSetNUW(mul, True);
|
||||
llvm::LLVMSetNSW(mul, True);
|
||||
}
|
||||
mul
|
||||
}
|
||||
}
|
||||
|
||||
fn or_disjoint(&mut self, a: &'ll Value, b: &'ll Value) -> &'ll Value {
|
||||
unsafe {
|
||||
let or = llvm::LLVMBuildOr(self.llbuilder, a, b, UNNAMED);
|
||||
@ -543,7 +574,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
unsafe {
|
||||
let alloca = llvm::LLVMBuildAlloca(bx.llbuilder, ty, UNNAMED);
|
||||
llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
|
||||
alloca
|
||||
// Cast to default addrspace if necessary
|
||||
llvm::LLVMBuildPointerCast(bx.llbuilder, alloca, self.cx().type_ptr(), UNNAMED)
|
||||
}
|
||||
}
|
||||
|
||||
@ -552,7 +584,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
let alloca =
|
||||
llvm::LLVMBuildArrayAlloca(self.llbuilder, self.cx().type_i8(), size, UNNAMED);
|
||||
llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
|
||||
alloca
|
||||
// Cast to default addrspace if necessary
|
||||
llvm::LLVMBuildPointerCast(self.llbuilder, alloca, self.cx().type_ptr(), UNNAMED)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,9 @@ use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivit
|
||||
use rustc_codegen_ssa::ModuleCodegen;
|
||||
use rustc_codegen_ssa::back::write::ModuleConfig;
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_session::config::Lto;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::back::write::{llvm_err, llvm_optimize};
|
||||
use crate::back::write::llvm_err;
|
||||
use crate::builder::SBuilder;
|
||||
use crate::context::SimpleCx;
|
||||
use crate::declare::declare_simple_fn;
|
||||
@ -53,8 +52,6 @@ fn generate_enzyme_call<'ll>(
|
||||
let mut ad_name: String = match attrs.mode {
|
||||
DiffMode::Forward => "__enzyme_fwddiff",
|
||||
DiffMode::Reverse => "__enzyme_autodiff",
|
||||
DiffMode::ForwardFirst => "__enzyme_fwddiff",
|
||||
DiffMode::ReverseFirst => "__enzyme_autodiff",
|
||||
_ => panic!("logic bug in autodiff, unrecognized mode"),
|
||||
}
|
||||
.to_string();
|
||||
@ -153,7 +150,7 @@ fn generate_enzyme_call<'ll>(
|
||||
_ => {}
|
||||
}
|
||||
|
||||
trace!("matching autodiff arguments");
|
||||
debug!("matching autodiff arguments");
|
||||
// We now handle the issue that Rust level arguments not always match the llvm-ir level
|
||||
// arguments. A slice, `&[f32]`, for example, is represented as a pointer and a length on
|
||||
// llvm-ir level. The number of activities matches the number of Rust level arguments, so we
|
||||
@ -164,10 +161,10 @@ fn generate_enzyme_call<'ll>(
|
||||
let mut activity_pos = 0;
|
||||
let outer_args: Vec<&llvm::Value> = get_params(outer_fn);
|
||||
while activity_pos < inputs.len() {
|
||||
let activity = inputs[activity_pos as usize];
|
||||
let diff_activity = inputs[activity_pos as usize];
|
||||
// Duplicated arguments received a shadow argument, into which enzyme will write the
|
||||
// gradient.
|
||||
let (activity, duplicated): (&Metadata, bool) = match activity {
|
||||
let (activity, duplicated): (&Metadata, bool) = match diff_activity {
|
||||
DiffActivity::None => panic!("not a valid input activity"),
|
||||
DiffActivity::Const => (enzyme_const, false),
|
||||
DiffActivity::Active => (enzyme_out, false),
|
||||
@ -222,7 +219,15 @@ fn generate_enzyme_call<'ll>(
|
||||
// A duplicated pointer will have the following two outer_fn arguments:
|
||||
// (..., ptr, ptr, ...). We add the following llvm-ir to our __enzyme call:
|
||||
// (..., metadata! enzyme_dup, ptr, ptr, ...).
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Pointer);
|
||||
if matches!(
|
||||
diff_activity,
|
||||
DiffActivity::Duplicated | DiffActivity::DuplicatedOnly
|
||||
) {
|
||||
assert!(
|
||||
llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Pointer
|
||||
);
|
||||
}
|
||||
// In the case of Dual we don't have assumptions, e.g. f32 would be valid.
|
||||
args.push(next_outer_arg);
|
||||
outer_pos += 2;
|
||||
activity_pos += 1;
|
||||
@ -277,7 +282,7 @@ pub(crate) fn differentiate<'ll>(
|
||||
module: &'ll ModuleCodegen<ModuleLlvm>,
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
diff_items: Vec<AutoDiffItem>,
|
||||
config: &ModuleConfig,
|
||||
_config: &ModuleConfig,
|
||||
) -> Result<(), FatalError> {
|
||||
for item in &diff_items {
|
||||
trace!("{}", item);
|
||||
@ -318,29 +323,6 @@ pub(crate) fn differentiate<'ll>(
|
||||
|
||||
// FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts
|
||||
|
||||
if let Some(opt_level) = config.opt_level {
|
||||
let opt_stage = match cgcx.lto {
|
||||
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
|
||||
Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
|
||||
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
|
||||
_ => llvm::OptStage::PreLinkNoLTO,
|
||||
};
|
||||
// This is our second opt call, so now we run all opts,
|
||||
// to make sure we get the best performance.
|
||||
let skip_size_increasing_opts = false;
|
||||
trace!("running Module Optimization after differentiation");
|
||||
unsafe {
|
||||
llvm_optimize(
|
||||
cgcx,
|
||||
diag_handler.handle(),
|
||||
module,
|
||||
config,
|
||||
opt_level,
|
||||
opt_stage,
|
||||
skip_size_increasing_opts,
|
||||
)?
|
||||
};
|
||||
}
|
||||
trace!("done with differentiate()");
|
||||
|
||||
Ok(())
|
||||
|
@ -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);
|
||||
|
@ -194,6 +194,12 @@ pub(crate) unsafe fn create_module<'ll>(
|
||||
target_data_layout = target_data_layout.replace("-i128:128", "");
|
||||
}
|
||||
}
|
||||
if llvm_version < (21, 0, 0) {
|
||||
if sess.target.arch == "nvptx64" {
|
||||
// LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961
|
||||
target_data_layout = target_data_layout.replace("e-p6:32:32-i64", "e-i64");
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the data-layout values hardcoded remain the defaults.
|
||||
{
|
||||
@ -616,12 +622,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> {
|
||||
|
@ -11,7 +11,8 @@ use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
|
||||
};
|
||||
use rustc_middle::mir::coverage::{
|
||||
CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op,
|
||||
BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,
|
||||
MappingKind, Op,
|
||||
};
|
||||
use rustc_middle::ty::{Instance, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
@ -53,7 +54,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
|
||||
let fn_cov_info = tcx.instance_mir(instance.def).function_coverage_info.as_deref()?;
|
||||
let ids_info = tcx.coverage_ids_info(instance.def)?;
|
||||
|
||||
let expressions = prepare_expressions(fn_cov_info, ids_info, is_used);
|
||||
let expressions = prepare_expressions(ids_info);
|
||||
|
||||
let mut covfun = CovfunRecord {
|
||||
mangled_function_name: tcx.symbol_name(instance).name,
|
||||
@ -75,26 +76,14 @@ pub(crate) fn prepare_covfun_record<'tcx>(
|
||||
}
|
||||
|
||||
/// Convert the function's coverage-counter expressions into a form suitable for FFI.
|
||||
fn prepare_expressions(
|
||||
fn_cov_info: &FunctionCoverageInfo,
|
||||
ids_info: &CoverageIdsInfo,
|
||||
is_used: bool,
|
||||
) -> Vec<ffi::CounterExpression> {
|
||||
// If any counters or expressions were removed by MIR opts, replace their
|
||||
// terms with zero.
|
||||
let counter_for_term = |term| {
|
||||
if !is_used || ids_info.is_zero_term(term) {
|
||||
ffi::Counter::ZERO
|
||||
} else {
|
||||
ffi::Counter::from_term(term)
|
||||
}
|
||||
};
|
||||
fn prepare_expressions(ids_info: &CoverageIdsInfo) -> Vec<ffi::CounterExpression> {
|
||||
let counter_for_term = ffi::Counter::from_term;
|
||||
|
||||
// We know that LLVM will optimize out any unused expressions before
|
||||
// producing the final coverage map, so there's no need to do the same
|
||||
// thing on the Rust side unless we're confident we can do much better.
|
||||
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
|
||||
fn_cov_info
|
||||
ids_info
|
||||
.expressions
|
||||
.iter()
|
||||
.map(move |&Expression { lhs, op, rhs }| ffi::CounterExpression {
|
||||
@ -136,11 +125,16 @@ fn fill_region_tables<'tcx>(
|
||||
|
||||
// For each counter/region pair in this function+file, convert it to a
|
||||
// form suitable for FFI.
|
||||
let is_zero_term = |term| !covfun.is_used || ids_info.is_zero_term(term);
|
||||
for &Mapping { ref kind, span } in &fn_cov_info.mappings {
|
||||
// If the mapping refers to counters/expressions that were removed by
|
||||
// MIR opts, replace those occurrences with zero.
|
||||
let kind = kind.map_terms(|term| if is_zero_term(term) { CovTerm::Zero } else { term });
|
||||
// If this function is unused, replace all counters with zero.
|
||||
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
|
||||
let term = if covfun.is_used {
|
||||
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
|
||||
} else {
|
||||
CovTerm::Zero
|
||||
};
|
||||
ffi::Counter::from_term(term)
|
||||
};
|
||||
|
||||
// Convert the `Span` into coordinates that we can pass to LLVM, or
|
||||
// discard the span if conversion fails. In rare, cases _all_ of a
|
||||
@ -154,23 +148,22 @@ fn fill_region_tables<'tcx>(
|
||||
continue;
|
||||
}
|
||||
|
||||
match kind {
|
||||
MappingKind::Code(term) => {
|
||||
code_regions
|
||||
.push(ffi::CodeRegion { cov_span, counter: ffi::Counter::from_term(term) });
|
||||
match *kind {
|
||||
MappingKind::Code { bcb } => {
|
||||
code_regions.push(ffi::CodeRegion { cov_span, counter: counter_for_bcb(bcb) });
|
||||
}
|
||||
MappingKind::Branch { true_term, false_term } => {
|
||||
MappingKind::Branch { true_bcb, false_bcb } => {
|
||||
branch_regions.push(ffi::BranchRegion {
|
||||
cov_span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
true_counter: counter_for_bcb(true_bcb),
|
||||
false_counter: counter_for_bcb(false_bcb),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
|
||||
MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params } => {
|
||||
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
|
||||
cov_span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
true_counter: counter_for_bcb(true_bcb),
|
||||
false_counter: counter_for_bcb(false_bcb),
|
||||
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
|
||||
});
|
||||
}
|
||||
|
@ -160,21 +160,12 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
||||
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
|
||||
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
|
||||
),
|
||||
CoverageKind::CounterIncrement { id } => {
|
||||
// The number of counters passed to `llvm.instrprof.increment` might
|
||||
// be smaller than the number originally inserted by the instrumentor,
|
||||
// if some high-numbered counters were removed by MIR optimizations.
|
||||
// If so, LLVM's profiler runtime will use fewer physical counters.
|
||||
let num_counters = ids_info.num_counters_after_mir_opts();
|
||||
assert!(
|
||||
num_counters as usize <= function_coverage_info.num_counters,
|
||||
"num_counters disagreement: query says {num_counters} but function info only has {}",
|
||||
function_coverage_info.num_counters
|
||||
);
|
||||
|
||||
CoverageKind::VirtualCounter { bcb }
|
||||
if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
|
||||
{
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
let num_counters = bx.const_u32(num_counters);
|
||||
let num_counters = bx.const_u32(ids_info.num_counters);
|
||||
let index = bx.const_u32(id.as_u32());
|
||||
debug!(
|
||||
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
|
||||
@ -182,10 +173,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
||||
);
|
||||
bx.instrprof_increment(fn_name, hash, num_counters, index);
|
||||
}
|
||||
CoverageKind::ExpressionUsed { id: _ } => {
|
||||
// Expression-used statements are markers that are handled by
|
||||
// `coverage_ids_info`, so there's nothing to codegen here.
|
||||
}
|
||||
// If a BCB doesn't have an associated physical counter, there's nothing to codegen.
|
||||
CoverageKind::VirtualCounter { .. } => {}
|
||||
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
|
||||
let cond_bitmap = coverage_cx
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
|
@ -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);
|
||||
|
@ -437,6 +437,12 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
|
||||
.source_info
|
||||
.unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
|
||||
|
||||
let discr = discr_value.opt_single_val().map(|value| {
|
||||
let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
|
||||
let size = cx.size_of(tag_base_type);
|
||||
cx.const_uint_big(cx.type_ix(size.bits()), value)
|
||||
});
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateVariantMemberType(
|
||||
DIB(cx),
|
||||
@ -448,7 +454,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
|
||||
enum_type_and_layout.size.bits(),
|
||||
enum_type_and_layout.align.abi.bits() as u32,
|
||||
Size::ZERO.bits(),
|
||||
discr_value.opt_single_val().map(|value| cx.const_u128(value)),
|
||||
discr,
|
||||
DIFlags::FlagZero,
|
||||
variant_member_info.variant_struct_type_di_node,
|
||||
)
|
||||
|
@ -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 }
|
||||
})
|
||||
}
|
||||
|
@ -131,8 +131,6 @@ pub enum LlvmError<'a> {
|
||||
LoadBitcode { name: CString },
|
||||
#[diag(codegen_llvm_write_thinlto_key)]
|
||||
WriteThinLtoKey { err: std::io::Error },
|
||||
#[diag(codegen_llvm_multiple_source_dicompileunit)]
|
||||
MultipleSourceDiCompileUnit,
|
||||
#[diag(codegen_llvm_prepare_thin_lto_module)]
|
||||
PrepareThinLtoModule,
|
||||
#[diag(codegen_llvm_parse_bitcode)]
|
||||
@ -155,9 +153,6 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for WithLlvmError<'_> {
|
||||
PrepareThinLtoContext => fluent::codegen_llvm_prepare_thin_lto_context_with_llvm_err,
|
||||
LoadBitcode { .. } => fluent::codegen_llvm_load_bitcode_with_llvm_err,
|
||||
WriteThinLtoKey { .. } => fluent::codegen_llvm_write_thinlto_key_with_llvm_err,
|
||||
MultipleSourceDiCompileUnit => {
|
||||
fluent::codegen_llvm_multiple_source_dicompileunit_with_llvm_err
|
||||
}
|
||||
PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
|
||||
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
|
||||
PrepareAutoDiff { .. } => fluent::codegen_llvm_prepare_autodiff_with_llvm_err,
|
||||
|
@ -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
|
||||
|
@ -13,6 +13,7 @@
|
||||
#![feature(extern_types)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_chains)]
|
||||
@ -29,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};
|
||||
@ -244,9 +245,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
|
||||
unsafe impl Sync for LlvmCodegenBackend {}
|
||||
|
||||
impl LlvmCodegenBackend {
|
||||
pub fn new() -> Box<dyn CodegenBackend> {
|
||||
Box::new(LlvmCodegenBackend(()))
|
||||
|
@ -26,7 +26,7 @@ impl ArchiveRO {
|
||||
///
|
||||
/// If this archive is used with a mutable method, then an error will be
|
||||
/// raised.
|
||||
pub fn open(dst: &Path) -> Result<ArchiveRO, String> {
|
||||
pub(crate) fn open(dst: &Path) -> Result<ArchiveRO, String> {
|
||||
unsafe {
|
||||
let s = path_to_c_string(dst);
|
||||
let ar = super::LLVMRustOpenArchive(s.as_ptr()).ok_or_else(|| {
|
||||
@ -36,7 +36,7 @@ impl ArchiveRO {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<'_> {
|
||||
pub(crate) fn iter(&self) -> Iter<'_> {
|
||||
unsafe { Iter { raw: super::LLVMRustArchiveIteratorNew(self.raw) } }
|
||||
}
|
||||
}
|
||||
@ -71,7 +71,7 @@ impl<'a> Drop for Iter<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Child<'a> {
|
||||
pub fn name(&self) -> Option<&'a str> {
|
||||
pub(crate) fn name(&self) -> Option<&'a str> {
|
||||
unsafe {
|
||||
let mut name_len = 0;
|
||||
let name_ptr = super::LLVMRustArchiveChildName(self.raw, &mut name_len);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![expect(dead_code)]
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
|
||||
@ -8,23 +9,23 @@ use crate::llvm::Bool;
|
||||
#[link(name = "llvm-wrapper", kind = "static")]
|
||||
extern "C" {
|
||||
// Enzyme
|
||||
pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
|
||||
pub fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
|
||||
pub fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
|
||||
pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
|
||||
pub fn LLVMRustEraseInstFromParent(V: &Value);
|
||||
pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
|
||||
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
pub(crate) fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
|
||||
pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
|
||||
pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
|
||||
pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
|
||||
pub(crate) fn LLVMRustEraseInstFromParent(V: &Value);
|
||||
pub(crate) fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
|
||||
pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// Enzyme
|
||||
pub fn LLVMDumpModule(M: &Module);
|
||||
pub fn LLVMDumpValue(V: &Value);
|
||||
pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
|
||||
pub fn LLVMGetReturnType(T: &Type) -> &Type;
|
||||
pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);
|
||||
pub fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
|
||||
pub(crate) fn LLVMDumpModule(M: &Module);
|
||||
pub(crate) fn LLVMDumpValue(V: &Value);
|
||||
pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
|
||||
pub(crate) fn LLVMGetReturnType(T: &Type) -> &Type;
|
||||
pub(crate) fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);
|
||||
pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ mod ffi;
|
||||
pub use self::enzyme_ffi::*;
|
||||
|
||||
impl LLVMRustResult {
|
||||
pub fn into_result(self) -> Result<(), ()> {
|
||||
pub(crate) fn into_result(self) -> Result<(), ()> {
|
||||
match self {
|
||||
LLVMRustResult::Success => Ok(()),
|
||||
LLVMRustResult::Failure => Err(()),
|
||||
@ -32,13 +32,17 @@ impl LLVMRustResult {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn AddFunctionAttributes<'ll>(llfn: &'ll Value, idx: AttributePlace, attrs: &[&'ll Attribute]) {
|
||||
pub(crate) fn AddFunctionAttributes<'ll>(
|
||||
llfn: &'ll Value,
|
||||
idx: AttributePlace,
|
||||
attrs: &[&'ll Attribute],
|
||||
) {
|
||||
unsafe {
|
||||
LLVMRustAddFunctionAttributes(llfn, idx.as_uint(), attrs.as_ptr(), attrs.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn AddCallSiteAttributes<'ll>(
|
||||
pub(crate) fn AddCallSiteAttributes<'ll>(
|
||||
callsite: &'ll Value,
|
||||
idx: AttributePlace,
|
||||
attrs: &[&'ll Attribute],
|
||||
@ -48,7 +52,11 @@ pub fn AddCallSiteAttributes<'ll>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &str, value: &str) -> &'ll Attribute {
|
||||
pub(crate) fn CreateAttrStringValue<'ll>(
|
||||
llcx: &'ll Context,
|
||||
attr: &str,
|
||||
value: &str,
|
||||
) -> &'ll Attribute {
|
||||
unsafe {
|
||||
LLVMCreateStringAttribute(
|
||||
llcx,
|
||||
@ -60,7 +68,7 @@ pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &str, value: &str) -
|
||||
}
|
||||
}
|
||||
|
||||
pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
|
||||
pub(crate) fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
|
||||
unsafe {
|
||||
LLVMCreateStringAttribute(
|
||||
llcx,
|
||||
@ -72,39 +80,39 @@ pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn CreateAlignmentAttr(llcx: &Context, bytes: u64) -> &Attribute {
|
||||
pub(crate) fn CreateAlignmentAttr(llcx: &Context, bytes: u64) -> &Attribute {
|
||||
unsafe { LLVMRustCreateAlignmentAttr(llcx, bytes) }
|
||||
}
|
||||
|
||||
pub fn CreateDereferenceableAttr(llcx: &Context, bytes: u64) -> &Attribute {
|
||||
pub(crate) fn CreateDereferenceableAttr(llcx: &Context, bytes: u64) -> &Attribute {
|
||||
unsafe { LLVMRustCreateDereferenceableAttr(llcx, bytes) }
|
||||
}
|
||||
|
||||
pub fn CreateDereferenceableOrNullAttr(llcx: &Context, bytes: u64) -> &Attribute {
|
||||
pub(crate) fn CreateDereferenceableOrNullAttr(llcx: &Context, bytes: u64) -> &Attribute {
|
||||
unsafe { LLVMRustCreateDereferenceableOrNullAttr(llcx, bytes) }
|
||||
}
|
||||
|
||||
pub fn CreateByValAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
|
||||
pub(crate) fn CreateByValAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
|
||||
unsafe { LLVMRustCreateByValAttr(llcx, ty) }
|
||||
}
|
||||
|
||||
pub fn CreateStructRetAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
|
||||
pub(crate) fn CreateStructRetAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
|
||||
unsafe { LLVMRustCreateStructRetAttr(llcx, ty) }
|
||||
}
|
||||
|
||||
pub fn CreateUWTableAttr(llcx: &Context, async_: bool) -> &Attribute {
|
||||
pub(crate) fn CreateUWTableAttr(llcx: &Context, async_: bool) -> &Attribute {
|
||||
unsafe { LLVMRustCreateUWTableAttr(llcx, async_) }
|
||||
}
|
||||
|
||||
pub fn CreateAllocSizeAttr(llcx: &Context, size_arg: u32) -> &Attribute {
|
||||
pub(crate) fn CreateAllocSizeAttr(llcx: &Context, size_arg: u32) -> &Attribute {
|
||||
unsafe { LLVMRustCreateAllocSizeAttr(llcx, size_arg) }
|
||||
}
|
||||
|
||||
pub fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribute {
|
||||
pub(crate) fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribute {
|
||||
unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) }
|
||||
}
|
||||
|
||||
pub fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute {
|
||||
pub(crate) fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute {
|
||||
let lower = range.start;
|
||||
let upper = range.end.wrapping_add(1);
|
||||
let lower_words = [lower as u64, (lower >> 64) as u64];
|
||||
@ -127,7 +135,7 @@ pub enum AttributePlace {
|
||||
}
|
||||
|
||||
impl AttributePlace {
|
||||
pub fn as_uint(self) -> c_uint {
|
||||
pub(crate) fn as_uint(self) -> c_uint {
|
||||
match self {
|
||||
AttributePlace::ReturnValue => 0,
|
||||
AttributePlace::Argument(i) => 1 + i,
|
||||
@ -159,12 +167,12 @@ impl FromStr for ArchiveKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn SetInstructionCallConv(instr: &Value, cc: CallConv) {
|
||||
pub(crate) fn SetInstructionCallConv(instr: &Value, cc: CallConv) {
|
||||
unsafe {
|
||||
LLVMSetInstructionCallConv(instr, cc as c_uint);
|
||||
}
|
||||
}
|
||||
pub fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
|
||||
pub(crate) fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
|
||||
unsafe {
|
||||
LLVMSetFunctionCallConv(fn_, cc as c_uint);
|
||||
}
|
||||
@ -176,20 +184,20 @@ pub fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
|
||||
// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
|
||||
// function.
|
||||
// For more details on COMDAT sections see e.g., https://www.airs.com/blog/archives/52
|
||||
pub fn SetUniqueComdat(llmod: &Module, val: &Value) {
|
||||
pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) {
|
||||
let name_buf = get_value_name(val).to_vec();
|
||||
let name =
|
||||
CString::from_vec_with_nul(name_buf).or_else(|buf| CString::new(buf.into_bytes())).unwrap();
|
||||
set_comdat(llmod, val, &name);
|
||||
}
|
||||
|
||||
pub fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
|
||||
pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
|
||||
unsafe {
|
||||
LLVMSetUnnamedAddress(global, unnamed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
|
||||
pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
|
||||
unsafe {
|
||||
LLVMSetThreadLocalMode(global, mode);
|
||||
}
|
||||
@ -197,61 +205,65 @@ pub fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
|
||||
|
||||
impl AttributeKind {
|
||||
/// Create an LLVM Attribute with no associated value.
|
||||
pub fn create_attr(self, llcx: &Context) -> &Attribute {
|
||||
pub(crate) fn create_attr(self, llcx: &Context) -> &Attribute {
|
||||
unsafe { LLVMRustCreateAttrNoValue(llcx, self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryEffects {
|
||||
/// Create an LLVM Attribute with these memory effects.
|
||||
pub fn create_attr(self, llcx: &Context) -> &Attribute {
|
||||
pub(crate) fn create_attr(self, llcx: &Context) -> &Attribute {
|
||||
unsafe { LLVMRustCreateMemoryEffectsAttr(llcx, self) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_section(llglobal: &Value, section_name: &CStr) {
|
||||
pub(crate) fn set_section(llglobal: &Value, section_name: &CStr) {
|
||||
unsafe {
|
||||
LLVMSetSection(llglobal, section_name.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name_cstr: &CStr) -> &'a Value {
|
||||
pub(crate) fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name_cstr: &CStr) -> &'a Value {
|
||||
unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn set_initializer(llglobal: &Value, constant_val: &Value) {
|
||||
pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) {
|
||||
unsafe {
|
||||
LLVMSetInitializer(llglobal, constant_val);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
|
||||
pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) {
|
||||
unsafe {
|
||||
LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_linkage(llglobal: &Value) -> Linkage {
|
||||
pub(crate) fn get_linkage(llglobal: &Value) -> Linkage {
|
||||
unsafe { LLVMGetLinkage(llglobal) }.to_rust()
|
||||
}
|
||||
|
||||
pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
|
||||
pub(crate) fn set_linkage(llglobal: &Value, linkage: Linkage) {
|
||||
unsafe {
|
||||
LLVMSetLinkage(llglobal, linkage);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_visibility(llglobal: &Value) -> Visibility {
|
||||
pub(crate) fn is_declaration(llglobal: &Value) -> bool {
|
||||
unsafe { LLVMIsDeclaration(llglobal) == ffi::True }
|
||||
}
|
||||
|
||||
pub(crate) fn get_visibility(llglobal: &Value) -> Visibility {
|
||||
unsafe { LLVMGetVisibility(llglobal) }.to_rust()
|
||||
}
|
||||
|
||||
pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
|
||||
pub(crate) fn set_visibility(llglobal: &Value, visibility: Visibility) {
|
||||
unsafe {
|
||||
LLVMSetVisibility(llglobal, visibility);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_alignment(llglobal: &Value, align: Align) {
|
||||
pub(crate) fn set_alignment(llglobal: &Value, align: Align) {
|
||||
unsafe {
|
||||
ffi::LLVMSetAlignment(llglobal, align.bytes() as c_uint);
|
||||
}
|
||||
@ -261,7 +273,7 @@ pub fn set_alignment(llglobal: &Value, align: Align) {
|
||||
///
|
||||
/// Inserts the comdat into `llmod` if it does not exist.
|
||||
/// It is an error to call this if the target does not support comdat.
|
||||
pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &CStr) {
|
||||
pub(crate) fn set_comdat(llmod: &Module, llglobal: &Value, name: &CStr) {
|
||||
unsafe {
|
||||
let comdat = LLVMGetOrInsertComdat(llmod, name.as_ptr());
|
||||
LLVMSetComdat(llglobal, comdat);
|
||||
@ -269,7 +281,7 @@ pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &CStr) {
|
||||
}
|
||||
|
||||
/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
|
||||
pub fn get_param(llfn: &Value, index: c_uint) -> &Value {
|
||||
pub(crate) fn get_param(llfn: &Value, index: c_uint) -> &Value {
|
||||
unsafe {
|
||||
assert!(
|
||||
index < LLVMCountParams(llfn),
|
||||
@ -282,7 +294,7 @@ pub fn get_param(llfn: &Value, index: c_uint) -> &Value {
|
||||
}
|
||||
|
||||
/// Safe wrapper for `LLVMGetValueName2` into a byte slice
|
||||
pub fn get_value_name(value: &Value) -> &[u8] {
|
||||
pub(crate) fn get_value_name(value: &Value) -> &[u8] {
|
||||
unsafe {
|
||||
let mut len = 0;
|
||||
let data = LLVMGetValueName2(value, &mut len);
|
||||
@ -291,28 +303,28 @@ pub fn get_value_name(value: &Value) -> &[u8] {
|
||||
}
|
||||
|
||||
/// Safe wrapper for `LLVMSetValueName2` from a byte slice
|
||||
pub fn set_value_name(value: &Value, name: &[u8]) {
|
||||
pub(crate) fn set_value_name(value: &Value, name: &[u8]) {
|
||||
unsafe {
|
||||
let data = name.as_c_char_ptr();
|
||||
LLVMSetValueName2(value, data, name.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
|
||||
pub(crate) fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
|
||||
String::from_utf8(RustString::build_byte_buffer(f))
|
||||
}
|
||||
|
||||
pub fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
|
||||
pub(crate) fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
|
||||
RustString::build_byte_buffer(f)
|
||||
}
|
||||
|
||||
pub fn twine_to_string(tr: &Twine) -> String {
|
||||
pub(crate) fn twine_to_string(tr: &Twine) -> String {
|
||||
unsafe {
|
||||
build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_error() -> Option<String> {
|
||||
pub(crate) fn last_error() -> Option<String> {
|
||||
unsafe {
|
||||
let cstr = LLVMRustGetLastError();
|
||||
if cstr.is_null() {
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ bitflags = "2.4.1"
|
||||
bstr = "1.11.3"
|
||||
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
|
||||
# `cc` in `rustc_llvm` if you update the `cc` here.
|
||||
cc = "=1.2.7"
|
||||
cc = "=1.2.13"
|
||||
either = "1.5.0"
|
||||
itertools = "0.12"
|
||||
pathdiff = "0.2.0"
|
||||
|
@ -410,7 +410,7 @@ impl<'a> GccLinker<'a> {
|
||||
let opt_level = match self.sess.opts.optimize {
|
||||
config::OptLevel::No => "O0",
|
||||
config::OptLevel::Less => "O1",
|
||||
config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
|
||||
config::OptLevel::More | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
|
||||
config::OptLevel::Aggressive => "O3",
|
||||
};
|
||||
|
||||
@ -685,7 +685,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
|
||||
// GNU-style linkers support optimization with -O. GNU ld doesn't
|
||||
// need a numeric argument, but other linkers do.
|
||||
if self.sess.opts.optimize == config::OptLevel::Default
|
||||
if self.sess.opts.optimize == config::OptLevel::More
|
||||
|| self.sess.opts.optimize == config::OptLevel::Aggressive
|
||||
{
|
||||
self.link_arg("-O1");
|
||||
@ -1213,7 +1213,7 @@ impl<'a> Linker for EmLinker<'a> {
|
||||
self.cc_arg(match self.sess.opts.optimize {
|
||||
OptLevel::No => "-O0",
|
||||
OptLevel::Less => "-O1",
|
||||
OptLevel::Default => "-O2",
|
||||
OptLevel::More => "-O2",
|
||||
OptLevel::Aggressive => "-O3",
|
||||
OptLevel::Size => "-Os",
|
||||
OptLevel::SizeMin => "-Oz",
|
||||
@ -1384,7 +1384,7 @@ impl<'a> Linker for WasmLd<'a> {
|
||||
self.link_arg(match self.sess.opts.optimize {
|
||||
OptLevel::No => "-O0",
|
||||
OptLevel::Less => "-O1",
|
||||
OptLevel::Default => "-O2",
|
||||
OptLevel::More => "-O2",
|
||||
OptLevel::Aggressive => "-O3",
|
||||
// Currently LLD doesn't support `Os` and `Oz`, so pass through `O2`
|
||||
// instead.
|
||||
@ -1451,7 +1451,7 @@ impl<'a> WasmLd<'a> {
|
||||
let opt_level = match self.sess.opts.optimize {
|
||||
config::OptLevel::No => "O0",
|
||||
config::OptLevel::Less => "O1",
|
||||
config::OptLevel::Default => "O2",
|
||||
config::OptLevel::More => "O2",
|
||||
config::OptLevel::Aggressive => "O3",
|
||||
// wasm-ld only handles integer LTO opt levels. Use O2
|
||||
config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
|
||||
@ -1525,7 +1525,7 @@ impl<'a> Linker for L4Bender<'a> {
|
||||
fn optimize(&mut self) {
|
||||
// GNU-style linkers support optimization with -O. GNU ld doesn't
|
||||
// need a numeric argument, but other linkers do.
|
||||
if self.sess.opts.optimize == config::OptLevel::Default
|
||||
if self.sess.opts.optimize == config::OptLevel::More
|
||||
|| self.sess.opts.optimize == config::OptLevel::Aggressive
|
||||
{
|
||||
self.link_arg("-O1");
|
||||
@ -1776,6 +1776,7 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
|
||||
symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
|
||||
tcx, symbol, cnum,
|
||||
));
|
||||
symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1929,7 +1930,7 @@ impl<'a> Linker for LlbcLinker<'a> {
|
||||
match self.sess.opts.optimize {
|
||||
OptLevel::No => "-O0",
|
||||
OptLevel::Less => "-O1",
|
||||
OptLevel::Default => "-O2",
|
||||
OptLevel::More => "-O2",
|
||||
OptLevel::Aggressive => "-O3",
|
||||
OptLevel::Size => "-Os",
|
||||
OptLevel::SizeMin => "-Oz",
|
||||
@ -2006,7 +2007,7 @@ impl<'a> Linker for BpfLinker<'a> {
|
||||
self.link_arg(match self.sess.opts.optimize {
|
||||
OptLevel::No => "-O0",
|
||||
OptLevel::Less => "-O1",
|
||||
OptLevel::Default => "-O2",
|
||||
OptLevel::More => "-O2",
|
||||
OptLevel::Aggressive => "-O3",
|
||||
OptLevel::Size => "-Os",
|
||||
OptLevel::SizeMin => "-Oz",
|
||||
|
@ -10,9 +10,10 @@ use rustc_middle::middle::exported_symbols::{
|
||||
ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, metadata_symbol_name,
|
||||
};
|
||||
use rustc_middle::query::LocalCrate;
|
||||
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, TyCtxt};
|
||||
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, Ty, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_session::config::{CrateType, OomStrategy};
|
||||
use rustc_target::callconv::Conv;
|
||||
use rustc_target::spec::{SanitizerSet, TlsModel};
|
||||
use tracing::debug;
|
||||
|
||||
@ -584,6 +585,42 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn calling_convention_for_symbol<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
symbol: ExportedSymbol<'tcx>,
|
||||
) -> (Conv, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) {
|
||||
let instance = match symbol {
|
||||
ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _)
|
||||
if tcx.is_static(def_id) =>
|
||||
{
|
||||
None
|
||||
}
|
||||
ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)),
|
||||
ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)),
|
||||
// DropGlue always use the Rust calling convention and thus follow the target's default
|
||||
// symbol decoration scheme.
|
||||
ExportedSymbol::DropGlue(..) => None,
|
||||
// AsyncDropGlueCtorShim always use the Rust calling convention and thus follow the
|
||||
// target's default symbol decoration scheme.
|
||||
ExportedSymbol::AsyncDropGlueCtorShim(..) => None,
|
||||
// NoDefId always follow the target's default symbol decoration scheme.
|
||||
ExportedSymbol::NoDefId(..) => None,
|
||||
// ThreadLocalShim always follow the target's default symbol decoration scheme.
|
||||
ExportedSymbol::ThreadLocalShim(..) => None,
|
||||
};
|
||||
|
||||
instance
|
||||
.map(|i| {
|
||||
tcx.fn_abi_of_instance(
|
||||
ty::TypingEnv::fully_monomorphized().as_query_input((i, ty::List::empty())),
|
||||
)
|
||||
.unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed"))
|
||||
})
|
||||
.map(|fnabi| (fnabi.conv, &fnabi.args[..]))
|
||||
// FIXME(workingjubilee): why don't we know the convention here?
|
||||
.unwrap_or((Conv::Rust, &[]))
|
||||
}
|
||||
|
||||
/// This is the symbol name of the given instance as seen by the linker.
|
||||
///
|
||||
/// On 32-bit Windows symbols are decorated according to their calling conventions.
|
||||
@ -592,8 +629,6 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
|
||||
symbol: ExportedSymbol<'tcx>,
|
||||
instantiating_crate: CrateNum,
|
||||
) -> String {
|
||||
use rustc_target::callconv::Conv;
|
||||
|
||||
let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
|
||||
|
||||
// thread local will not be a function call,
|
||||
@ -617,35 +652,7 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
|
||||
_ => return undecorated,
|
||||
};
|
||||
|
||||
let instance = match symbol {
|
||||
ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _)
|
||||
if tcx.is_static(def_id) =>
|
||||
{
|
||||
None
|
||||
}
|
||||
ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)),
|
||||
ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)),
|
||||
// DropGlue always use the Rust calling convention and thus follow the target's default
|
||||
// symbol decoration scheme.
|
||||
ExportedSymbol::DropGlue(..) => None,
|
||||
// AsyncDropGlueCtorShim always use the Rust calling convention and thus follow the
|
||||
// target's default symbol decoration scheme.
|
||||
ExportedSymbol::AsyncDropGlueCtorShim(..) => None,
|
||||
// NoDefId always follow the target's default symbol decoration scheme.
|
||||
ExportedSymbol::NoDefId(..) => None,
|
||||
// ThreadLocalShim always follow the target's default symbol decoration scheme.
|
||||
ExportedSymbol::ThreadLocalShim(..) => None,
|
||||
};
|
||||
|
||||
let (conv, args) = instance
|
||||
.map(|i| {
|
||||
tcx.fn_abi_of_instance(
|
||||
ty::TypingEnv::fully_monomorphized().as_query_input((i, ty::List::empty())),
|
||||
)
|
||||
.unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed"))
|
||||
})
|
||||
.map(|fnabi| (fnabi.conv, &fnabi.args[..]))
|
||||
.unwrap_or((Conv::Rust, &[]));
|
||||
let (conv, args) = calling_convention_for_symbol(tcx, symbol);
|
||||
|
||||
// Decorate symbols with prefixes, suffixes and total number of bytes of arguments.
|
||||
// Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170
|
||||
@ -677,6 +684,27 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>(
|
||||
maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated)
|
||||
}
|
||||
|
||||
/// On amdhsa, `gpu-kernel` functions have an associated metadata object with a `.kd` suffix.
|
||||
/// Add it to the symbols list for all kernel functions, so that it is exported in the linked
|
||||
/// object.
|
||||
pub(crate) fn extend_exported_symbols<'tcx>(
|
||||
symbols: &mut Vec<String>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
symbol: ExportedSymbol<'tcx>,
|
||||
instantiating_crate: CrateNum,
|
||||
) {
|
||||
let (conv, _) = calling_convention_for_symbol(tcx, symbol);
|
||||
|
||||
if conv != Conv::GpuKernel || tcx.sess.target.os != "amdhsa" {
|
||||
return;
|
||||
}
|
||||
|
||||
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
|
||||
|
||||
// Add the symbol for the kernel descriptor (with .kd suffix)
|
||||
symbols.push(format!("{undecorated}.kd"));
|
||||
}
|
||||
|
||||
fn maybe_emutls_symbol_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
symbol: ExportedSymbol<'tcx>,
|
||||
|
@ -236,7 +236,7 @@ impl ModuleConfig {
|
||||
// Copy what clang does by turning on loop vectorization at O2 and
|
||||
// slp vectorization at O3.
|
||||
vectorize_loop: !sess.opts.cg.no_vectorize_loops
|
||||
&& (sess.opts.optimize == config::OptLevel::Default
|
||||
&& (sess.opts.optimize == config::OptLevel::More
|
||||
|| sess.opts.optimize == config::OptLevel::Aggressive),
|
||||
vectorize_slp: !sess.opts.cg.no_vectorize_slp
|
||||
&& sess.opts.optimize == config::OptLevel::Aggressive,
|
||||
@ -260,7 +260,7 @@ impl ModuleConfig {
|
||||
MergeFunctions::Trampolines | MergeFunctions::Aliases => {
|
||||
use config::OptLevel::*;
|
||||
match sess.opts.optimize {
|
||||
Aggressive | Default | SizeMin | Size => true,
|
||||
Aggressive | More | SizeMin | Size => true,
|
||||
Less | No => false,
|
||||
}
|
||||
}
|
||||
|
@ -1054,12 +1054,12 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||
config::OptLevel::No => return config::OptLevel::No,
|
||||
// If globally optimise-speed is already specified, just use that level.
|
||||
config::OptLevel::Less => return config::OptLevel::Less,
|
||||
config::OptLevel::Default => return config::OptLevel::Default,
|
||||
config::OptLevel::More => return config::OptLevel::More,
|
||||
config::OptLevel::Aggressive => return config::OptLevel::Aggressive,
|
||||
// If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
|
||||
// are present).
|
||||
config::OptLevel::Size => config::OptLevel::Default,
|
||||
config::OptLevel::SizeMin => config::OptLevel::Default,
|
||||
config::OptLevel::Size => config::OptLevel::More,
|
||||
config::OptLevel::SizeMin => config::OptLevel::More,
|
||||
};
|
||||
|
||||
let defids = tcx.collect_and_partition_mono_items(cratenum).all_mono_items;
|
||||
|
@ -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(),
|
||||
@ -271,10 +272,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
if safe_target_features {
|
||||
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||
// The `#[target_feature]` attribute is allowed on
|
||||
// WebAssembly targets on all functions, including safe
|
||||
// ones. Other targets require that `#[target_feature]` is
|
||||
// only applied to unsafe functions (pending the
|
||||
// `target_feature_11` feature) because on most targets
|
||||
// WebAssembly targets on all functions. Prior to stabilizing
|
||||
// the `target_feature_11` feature, `#[target_feature]` was
|
||||
// only permitted on unsafe functions because on most targets
|
||||
// execution of instructions that are not supported is
|
||||
// considered undefined behavior. For WebAssembly which is a
|
||||
// 100% safe target at execution time it's not possible to
|
||||
@ -288,17 +288,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
// if a target is documenting some wasm-specific code then
|
||||
// it's not spuriously denied.
|
||||
//
|
||||
// This exception needs to be kept in sync with allowing
|
||||
// `#[target_feature]` on `main` and `start`.
|
||||
} else if !tcx.features().target_feature_11() {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::target_feature_11,
|
||||
attr.span,
|
||||
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
|
||||
)
|
||||
.with_span_label(tcx.def_span(did), "not an `unsafe` function")
|
||||
.emit();
|
||||
// Now that `#[target_feature]` is permitted on safe functions,
|
||||
// this exception must still exist for allowing the attribute on
|
||||
// `main`, `start`, and other functions that are not usually
|
||||
// allowed.
|
||||
} else {
|
||||
check_target_feature_trait_unsafe(tcx, did, attr.span);
|
||||
}
|
||||
@ -627,10 +620,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
// its parent function, which effectively inherits the features anyway. Boxing this closure
|
||||
// would result in this closure being compiled without the inherited target features, but this
|
||||
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
|
||||
if tcx.features().target_feature_11()
|
||||
&& tcx.is_closure_like(did.to_def_id())
|
||||
&& !codegen_fn_attrs.inline.always()
|
||||
{
|
||||
if tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always {
|
||||
let owner_id = tcx.parent(did.to_def_id());
|
||||
if tcx.def_kind(owner_id).has_codegen_attrs() {
|
||||
codegen_fn_attrs
|
||||
@ -914,8 +904,6 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
|
||||
let mode = match mode.as_str() {
|
||||
"Forward" => DiffMode::Forward,
|
||||
"Reverse" => DiffMode::Reverse,
|
||||
"ForwardFirst" => DiffMode::ForwardFirst,
|
||||
"ReverseFirst" => DiffMode::ReverseFirst,
|
||||
_ => {
|
||||
span_bug!(mode.span, "rustc_autodiff attribute contains invalid mode");
|
||||
}
|
||||
|
@ -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(");
|
||||
|
@ -1013,7 +1013,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",
|
||||
);
|
||||
@ -1045,7 +1045,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",
|
||||
);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user