Merge from rustc
This commit is contained in:
commit
9d579f5358
1487 changed files with 21017 additions and 14840 deletions
4
.github/ISSUE_TEMPLATE/blank_issue.md
vendored
4
.github/ISSUE_TEMPLATE/blank_issue.md
vendored
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
name: Blank Issue
|
||||
about: Create a blank issue.
|
||||
---
|
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -122,6 +122,9 @@ jobs:
|
|||
# which then uses log commands to actually set them.
|
||||
EXTRA_VARIABLES: ${{ toJson(matrix.env) }}
|
||||
|
||||
- name: setup upstream remote
|
||||
run: src/ci/scripts/setup-upstream-remote.sh
|
||||
|
||||
- name: ensure the channel matches the target branch
|
||||
run: src/ci/scripts/verify-channel.sh
|
||||
|
||||
|
|
2
.mailmap
2
.mailmap
|
@ -74,6 +74,7 @@ Ben Striegel <ben.striegel@gmail.com>
|
|||
Benjamin Jackman <ben@jackman.biz>
|
||||
Benoît Cortier <benoit.cortier@fried-world.eu>
|
||||
Bheesham Persaud <bheesham123@hotmail.com> Bheesham Persaud <bheesham.persaud@live.ca>
|
||||
bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3@users.noreply.github.com>
|
||||
Björn Steinbrink <bsteinbr@gmail.com> <B.Steinbrink@gmx.de>
|
||||
blake2-ppc <ulrik.sverdrup@gmail.com> <blake2-ppc>
|
||||
blyxyas <blyxyas@gmail.com> Alejandra González <blyxyas@gmail.com>
|
||||
|
@ -311,6 +312,7 @@ Josh Driver <keeperofdakeys@gmail.com>
|
|||
Josh Holmer <jholmer.in@gmail.com>
|
||||
Josh Stone <cuviper@gmail.com> <jistone@redhat.com>
|
||||
Josh Stone <cuviper@gmail.com> <jistone@fedoraproject.org>
|
||||
Julia Ryan <juliaryan3.14@gmail.com> <josephryan3.14@gmail.com>
|
||||
Julian Knodt <julianknodt@gmail.com>
|
||||
jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com>
|
||||
Junyoung Cho <june0.cho@samsung.com>
|
||||
|
|
86
Cargo.lock
86
Cargo.lock
|
@ -96,7 +96,7 @@ version = "0.9.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
"yansi-term",
|
||||
]
|
||||
|
||||
|
@ -107,7 +107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -168,7 +168,7 @@ dependencies = [
|
|||
"anstyle",
|
||||
"anstyle-lossy",
|
||||
"html-escape",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -737,7 +737,7 @@ dependencies = [
|
|||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
|
@ -1425,7 +1425,7 @@ version = "0.2.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1788,7 +1788,7 @@ dependencies = [
|
|||
"instant",
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2590,7 +2590,7 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2601,7 +2601,7 @@ checksum = "9ad43c07024ef767f9160710b3a6773976194758c7919b17e63b863db0bdf7fb"
|
|||
dependencies = [
|
||||
"bytecount",
|
||||
"fnv",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3416,6 +3416,7 @@ dependencies = [
|
|||
"measureme",
|
||||
"object 0.36.4",
|
||||
"rustc-demangle",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_codegen_ssa",
|
||||
|
@ -3456,6 +3457,7 @@ dependencies = [
|
|||
"object 0.36.4",
|
||||
"pathdiff",
|
||||
"regex",
|
||||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
@ -3493,6 +3495,7 @@ name = "rustc_const_eval"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
@ -3772,6 +3775,7 @@ name = "rustc_hir_typeck"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_ir",
|
||||
"rustc_attr",
|
||||
|
@ -4027,6 +4031,7 @@ dependencies = [
|
|||
"gsgdt",
|
||||
"polonius-engine",
|
||||
"rustc-rayon-core",
|
||||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
|
@ -4183,7 +4188,7 @@ dependencies = [
|
|||
"thin-vec",
|
||||
"tracing",
|
||||
"unicode-normalization",
|
||||
"unicode-width",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4417,7 +4422,7 @@ dependencies = [
|
|||
"sha1",
|
||||
"sha2",
|
||||
"tracing",
|
||||
"unicode-width",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4522,6 +4527,7 @@ name = "rustc_ty_utils"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
@ -4681,7 +4687,7 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
"unicode-properties",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5091,7 +5097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4c998b0c8b921495196a48aabaf1901ff28be0760136e31604f7967b0792050e"
|
||||
dependencies = [
|
||||
"papergrid",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5640,6 +5646,12 @@ version = "0.1.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
|
@ -5798,16 +5810,16 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-component-ld"
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde17bc96539700198e12516230c76095cc215c84ef39ad206e1af3f84243e0f"
|
||||
checksum = "4d4aa6bd7fbe7cffbed29fe3e236fda74419def1bdef6f80f989ec51137edf44"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"lexopt",
|
||||
"tempfile",
|
||||
"wasi-preview1-component-adapter-provider",
|
||||
"wasmparser 0.218.0",
|
||||
"wasmparser 0.219.0",
|
||||
"wat",
|
||||
"wit-component",
|
||||
"wit-parser",
|
||||
|
@ -5831,19 +5843,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.218.0"
|
||||
version = "0.219.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a"
|
||||
checksum = "e2b1b95711b3ad655656a341e301cc64e33cbee94de9a99a1c5a2ab88efab79d"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
"wasmparser 0.218.0",
|
||||
"wasmparser 0.219.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.218.0"
|
||||
version = "0.219.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa5eeb071abe8a2132fdd5565dabffee70775ee8c24fc7e300ac43f51f4a8a91"
|
||||
checksum = "96132fe00dd17d092d2be289eeed5a0a68ad3cf30b68e8875bc953b96f55f0be"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
|
@ -5851,8 +5863,8 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder 0.218.0",
|
||||
"wasmparser 0.218.0",
|
||||
"wasm-encoder 0.219.0",
|
||||
"wasmparser 0.219.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5867,9 +5879,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.218.0"
|
||||
version = "0.219.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc"
|
||||
checksum = "324b4e56d24439495b88cd81439dad5e97f3c7b1eedc3c7e10455ed1e045e9a2"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bitflags 2.6.0",
|
||||
|
@ -5881,22 +5893,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "218.0.0"
|
||||
version = "219.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a53cd1f0fa505df97557e36a58bddb8296e2fcdcd089529545ebfdb18a1b9d7"
|
||||
checksum = "06880ecb25662bc21db6a83f4fcc27c41f71fbcba4f1980b650c88ada92728e1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128",
|
||||
"memchr",
|
||||
"unicode-width",
|
||||
"wasm-encoder 0.218.0",
|
||||
"unicode-width 0.1.14",
|
||||
"wasm-encoder 0.219.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.218.0"
|
||||
version = "1.219.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f87f8e14e776762e07927c27c2054d2cf678aab9aae2d431a79b3e31e4dd391"
|
||||
checksum = "11e56dbf9fc89111b0d97c91e683d7895b1a6e5633a729f2ccad2303724005b6"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
@ -6173,9 +6185,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.218.0"
|
||||
version = "0.219.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa53aa7e6bf2b3e8ccaffbcc963fbdb672a603dc0af393a481b6cec24c266406"
|
||||
checksum = "99a76111c20444a814019de20499d30940ecd219b9512ee296f034a5edb18a2d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.6.0",
|
||||
|
@ -6184,17 +6196,17 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder 0.218.0",
|
||||
"wasm-encoder 0.219.0",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.218.0",
|
||||
"wasmparser 0.219.0",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.218.0"
|
||||
version = "0.219.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55"
|
||||
checksum = "23102e180c0c464f36e293d31a27b524e3ece930d7b5527d2f33f9d2c963de64"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -6205,7 +6217,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.218.0",
|
||||
"wasmparser 0.219.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
20
INSTALL.md
20
INSTALL.md
|
@ -79,9 +79,23 @@ See [the rustc-dev-guide for more info][sysllvm].
|
|||
./configure
|
||||
```
|
||||
|
||||
If you plan to use `x.py install` to create an installation, it is
|
||||
recommended that you set the `prefix` value in the `[install]` section to a
|
||||
directory: `./configure --set install.prefix=<path>`
|
||||
If you plan to use `x.py install` to create an installation, you can either
|
||||
set `DESTDIR` environment variable to your custom directory path:
|
||||
|
||||
```bash
|
||||
export DESTDIR=<path>
|
||||
```
|
||||
|
||||
or set `prefix` and `sysconfdir` in the `[install]` section to your custom
|
||||
directory path:
|
||||
|
||||
```sh
|
||||
./configure --set install.prefix=<path> --set install.sysconfdir=<path>
|
||||
```
|
||||
|
||||
When the `DESTDIR` environment variable is present, the `prefix` and
|
||||
`sysconfdir` values are combined with the path from the `DESTDIR`
|
||||
environment variable.
|
||||
|
||||
3. Build and install:
|
||||
|
||||
|
|
254
compiler/rustc_abi/src/callconv.rs
Normal file
254
compiler/rustc_abi/src/callconv.rs
Normal file
|
@ -0,0 +1,254 @@
|
|||
mod abi {
|
||||
pub(crate) use crate::Primitive::*;
|
||||
pub(crate) use crate::Variants;
|
||||
}
|
||||
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub enum RegKind {
|
||||
Integer,
|
||||
Float,
|
||||
Vector,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub struct Reg {
|
||||
pub kind: RegKind,
|
||||
pub size: Size,
|
||||
}
|
||||
|
||||
macro_rules! reg_ctor {
|
||||
($name:ident, $kind:ident, $bits:expr) => {
|
||||
pub fn $name() -> Reg {
|
||||
Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
reg_ctor!(i8, Integer, 8);
|
||||
reg_ctor!(i16, Integer, 16);
|
||||
reg_ctor!(i32, Integer, 32);
|
||||
reg_ctor!(i64, Integer, 64);
|
||||
reg_ctor!(i128, Integer, 128);
|
||||
|
||||
reg_ctor!(f32, Float, 32);
|
||||
reg_ctor!(f64, Float, 64);
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
|
||||
let dl = cx.data_layout();
|
||||
match self.kind {
|
||||
RegKind::Integer => match self.size.bits() {
|
||||
1 => dl.i1_align.abi,
|
||||
2..=8 => dl.i8_align.abi,
|
||||
9..=16 => dl.i16_align.abi,
|
||||
17..=32 => dl.i32_align.abi,
|
||||
33..=64 => dl.i64_align.abi,
|
||||
65..=128 => dl.i128_align.abi,
|
||||
_ => panic!("unsupported integer: {self:?}"),
|
||||
},
|
||||
RegKind::Float => match self.size.bits() {
|
||||
16 => dl.f16_align.abi,
|
||||
32 => dl.f32_align.abi,
|
||||
64 => dl.f64_align.abi,
|
||||
128 => dl.f128_align.abi,
|
||||
_ => panic!("unsupported float: {self:?}"),
|
||||
},
|
||||
RegKind::Vector => dl.vector_align(self.size).abi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return value from the `homogeneous_aggregate` test function.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum HomogeneousAggregate {
|
||||
/// Yes, all the "leaf fields" of this struct are passed in the
|
||||
/// same way (specified in the `Reg` value).
|
||||
Homogeneous(Reg),
|
||||
|
||||
/// There are no leaf fields at all.
|
||||
NoData,
|
||||
}
|
||||
|
||||
/// Error from the `homogeneous_aggregate` test function, indicating
|
||||
/// there are distinct leaf fields passed in different ways,
|
||||
/// or this is uninhabited.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Heterogeneous;
|
||||
|
||||
impl HomogeneousAggregate {
|
||||
/// If this is a homogeneous aggregate, returns the homogeneous
|
||||
/// unit, else `None`.
|
||||
pub fn unit(self) -> Option<Reg> {
|
||||
match self {
|
||||
HomogeneousAggregate::Homogeneous(reg) => Some(reg),
|
||||
HomogeneousAggregate::NoData => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
|
||||
/// the same `struct`. Only succeeds if only one of them has any data,
|
||||
/// or both units are identical.
|
||||
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
|
||||
match (self, other) {
|
||||
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
|
||||
|
||||
(HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
|
||||
if a != b {
|
||||
return Err(Heterogeneous);
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
||||
pub fn is_aggregate(&self) -> bool {
|
||||
match self.abi {
|
||||
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Homogeneous` if this layout is an aggregate containing fields of
|
||||
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
|
||||
/// special-cased in ABIs.
|
||||
///
|
||||
/// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
|
||||
///
|
||||
/// This is public so that it can be used in unit tests, but
|
||||
/// should generally only be relevant to the ABI details of
|
||||
/// specific targets.
|
||||
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
match self.abi {
|
||||
Abi::Uninhabited => Err(Heterogeneous),
|
||||
|
||||
// The primitive for this algorithm.
|
||||
Abi::Scalar(scalar) => {
|
||||
let kind = match scalar.primitive() {
|
||||
abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
|
||||
abi::Float(_) => RegKind::Float,
|
||||
};
|
||||
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
|
||||
}
|
||||
|
||||
Abi::Vector { .. } => {
|
||||
assert!(!self.is_zst());
|
||||
Ok(HomogeneousAggregate::Homogeneous(Reg {
|
||||
kind: RegKind::Vector,
|
||||
size: self.size,
|
||||
}))
|
||||
}
|
||||
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => {
|
||||
// Helper for computing `homogeneous_aggregate`, allowing a custom
|
||||
// starting offset (used below for handling variants).
|
||||
let from_fields_at =
|
||||
|layout: Self,
|
||||
start: Size|
|
||||
-> Result<(HomogeneousAggregate, Size), Heterogeneous> {
|
||||
let is_union = match layout.fields {
|
||||
FieldsShape::Primitive => {
|
||||
unreachable!("aggregates can't have `FieldsShape::Primitive`")
|
||||
}
|
||||
FieldsShape::Array { count, .. } => {
|
||||
assert_eq!(start, Size::ZERO);
|
||||
|
||||
let result = if count > 0 {
|
||||
layout.field(cx, 0).homogeneous_aggregate(cx)?
|
||||
} else {
|
||||
HomogeneousAggregate::NoData
|
||||
};
|
||||
return Ok((result, layout.size));
|
||||
}
|
||||
FieldsShape::Union(_) => true,
|
||||
FieldsShape::Arbitrary { .. } => false,
|
||||
};
|
||||
|
||||
let mut result = HomogeneousAggregate::NoData;
|
||||
let mut total = start;
|
||||
|
||||
for i in 0..layout.fields.count() {
|
||||
let field = layout.field(cx, i);
|
||||
if field.is_1zst() {
|
||||
// No data here and no impact on layout, can be ignored.
|
||||
// (We might be able to also ignore all aligned ZST but that's less clear.)
|
||||
continue;
|
||||
}
|
||||
|
||||
if !is_union && total != layout.fields.offset(i) {
|
||||
// This field isn't just after the previous one we considered, abort.
|
||||
return Err(Heterogeneous);
|
||||
}
|
||||
|
||||
result = result.merge(field.homogeneous_aggregate(cx)?)?;
|
||||
|
||||
// Keep track of the offset (without padding).
|
||||
let size = field.size;
|
||||
if is_union {
|
||||
total = total.max(size);
|
||||
} else {
|
||||
total += size;
|
||||
}
|
||||
}
|
||||
|
||||
Ok((result, total))
|
||||
};
|
||||
|
||||
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
|
||||
|
||||
match &self.variants {
|
||||
abi::Variants::Single { .. } => {}
|
||||
abi::Variants::Multiple { variants, .. } => {
|
||||
// Treat enum variants like union members.
|
||||
// HACK(eddyb) pretend the `enum` field (discriminant)
|
||||
// is at the start of every variant (otherwise the gap
|
||||
// at the start of all variants would disqualify them).
|
||||
//
|
||||
// NB: for all tagged `enum`s (which include all non-C-like
|
||||
// `enum`s with defined FFI representation), this will
|
||||
// match the homogeneous computation on the equivalent
|
||||
// `struct { tag; union { variant1; ... } }` and/or
|
||||
// `union { struct { tag; variant1; } ... }`
|
||||
// (the offsets of variant fields should be identical
|
||||
// between the two for either to be a homogeneous aggregate).
|
||||
let variant_start = total;
|
||||
for variant_idx in variants.indices() {
|
||||
let (variant_result, variant_total) =
|
||||
from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
|
||||
|
||||
result = result.merge(variant_result)?;
|
||||
total = total.max(variant_total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There needs to be no padding.
|
||||
if total != self.size {
|
||||
Err(Heterogeneous)
|
||||
} else {
|
||||
match result {
|
||||
HomogeneousAggregate::Homogeneous(_) => {
|
||||
assert_ne!(total, Size::ZERO);
|
||||
}
|
||||
HomogeneousAggregate::NoData => {
|
||||
assert_eq!(total, Size::ZERO);
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
Abi::Aggregate { sized: false } => Err(Heterogeneous),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,10 @@ use crate::{
|
|||
Variants, WrappingRange,
|
||||
};
|
||||
|
||||
mod ty;
|
||||
|
||||
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
|
||||
// A variant is absent if it's uninhabited and only has ZST fields.
|
||||
// Present uninhabited variants only require space for their fields,
|
||||
// but *not* an encoding of the discriminant (e.g., a tag value).
|
||||
|
|
|
@ -1,24 +1,13 @@
|
|||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub use Float::*;
|
||||
pub use Integer::*;
|
||||
pub use Primitive::*;
|
||||
use Float::*;
|
||||
use Primitive::*;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use crate::json::{Json, ToJson};
|
||||
|
||||
pub mod call;
|
||||
|
||||
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
|
||||
pub use rustc_abi::{Float, *};
|
||||
|
||||
impl ToJson for Endian {
|
||||
fn to_json(&self) -> Json {
|
||||
self.as_str().to_json()
|
||||
}
|
||||
}
|
||||
use crate::{Float, *};
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a field in a variant.
|
||||
|
@ -135,7 +124,7 @@ impl<'a> Layout<'a> {
|
|||
/// Note that the layout is NOT guaranteed to always be identical
|
||||
/// to that obtained from `layout_of(ty)`, as we need to produce
|
||||
/// layouts for which Rust types do not exist, such as enum variants
|
||||
/// or synthetic fields of enums (i.e., discriminants) and fat pointers.
|
||||
/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
pub struct TyAndLayout<'a, Ty> {
|
||||
pub ty: Ty,
|
|
@ -1,6 +1,7 @@
|
|||
// tidy-alphabetical-start
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
#![cfg_attr(feature = "nightly", doc(rust_logo))]
|
||||
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||
#![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
|
||||
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
||||
#![warn(unreachable_pub)]
|
||||
|
@ -22,11 +23,16 @@ use rustc_macros::HashStable_Generic;
|
|||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable_Generic, Encodable_Generic};
|
||||
|
||||
mod callconv;
|
||||
mod layout;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
||||
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
|
||||
pub use layout::{
|
||||
FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface,
|
||||
TyAndLayout, VariantIdx,
|
||||
};
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
|
|
|
@ -511,7 +511,7 @@ pub enum MetaItemKind {
|
|||
/// List meta item.
|
||||
///
|
||||
/// E.g., `#[derive(..)]`, where the field represents the `..`.
|
||||
List(ThinVec<NestedMetaItem>),
|
||||
List(ThinVec<MetaItemInner>),
|
||||
|
||||
/// Name value meta item.
|
||||
///
|
||||
|
@ -523,7 +523,7 @@ pub enum MetaItemKind {
|
|||
///
|
||||
/// E.g., each of `Clone`, `Copy` in `#[derive(Clone, Copy)]`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum NestedMetaItem {
|
||||
pub enum MetaItemInner {
|
||||
/// A full MetaItem, for recursive meta items.
|
||||
MetaItem(MetaItem),
|
||||
|
||||
|
@ -2167,10 +2167,6 @@ pub enum TyKind {
|
|||
Never,
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
Tup(ThinVec<P<Ty>>),
|
||||
/// An anonymous struct type i.e. `struct { foo: Type }`.
|
||||
AnonStruct(NodeId, ThinVec<FieldDef>),
|
||||
/// An anonymous union type i.e. `union { bar: Type }`.
|
||||
AnonUnion(NodeId, ThinVec<FieldDef>),
|
||||
/// A path (`module::module::...::Type`), optionally
|
||||
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
||||
///
|
||||
|
@ -2227,10 +2223,6 @@ impl TyKind {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_anon_adt(&self) -> bool {
|
||||
matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..))
|
||||
}
|
||||
}
|
||||
|
||||
/// Syntax used to declare a trait object.
|
||||
|
@ -2278,7 +2270,7 @@ impl InlineAsmOptions {
|
|||
pub const COUNT: usize = Self::all().bits().count_ones() as usize;
|
||||
|
||||
pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW);
|
||||
pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN);
|
||||
pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW);
|
||||
|
||||
pub fn human_readable_names(&self) -> Vec<&'static str> {
|
||||
let mut options = vec![];
|
||||
|
@ -2434,6 +2426,32 @@ pub enum AsmMacro {
|
|||
NakedAsm,
|
||||
}
|
||||
|
||||
impl AsmMacro {
|
||||
pub const fn macro_name(self) -> &'static str {
|
||||
match self {
|
||||
AsmMacro::Asm => "asm",
|
||||
AsmMacro::GlobalAsm => "global_asm",
|
||||
AsmMacro::NakedAsm => "naked_asm",
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn is_supported_option(self, option: InlineAsmOptions) -> bool {
|
||||
match self {
|
||||
AsmMacro::Asm => true,
|
||||
AsmMacro::GlobalAsm => InlineAsmOptions::GLOBAL_OPTIONS.contains(option),
|
||||
AsmMacro::NakedAsm => InlineAsmOptions::NAKED_OPTIONS.contains(option),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn diverges(self, options: InlineAsmOptions) -> bool {
|
||||
match self {
|
||||
AsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
|
||||
AsmMacro::GlobalAsm => true,
|
||||
AsmMacro::NakedAsm => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Inline assembly.
|
||||
///
|
||||
/// E.g., `asm!("NOP");`.
|
||||
|
|
|
@ -11,7 +11,7 @@ use thin_vec::{ThinVec, thin_vec};
|
|||
|
||||
use crate::ast::{
|
||||
AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID,
|
||||
DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem,
|
||||
DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit,
|
||||
NormalAttr, Path, PathSegment, Safety,
|
||||
};
|
||||
use crate::ptr::P;
|
||||
|
@ -136,7 +136,7 @@ impl Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> {
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => normal.item.meta_item_list(),
|
||||
AttrKind::DocComment(..) => None,
|
||||
|
@ -223,7 +223,7 @@ impl AttrItem {
|
|||
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
|
||||
}
|
||||
|
||||
fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> {
|
||||
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
match &self.args {
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||
|
@ -285,7 +285,7 @@ impl MetaItem {
|
|||
matches!(self.kind, MetaItemKind::Word)
|
||||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
|
||||
pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
|
||||
match &self.kind {
|
||||
MetaItemKind::List(l) => Some(&**l),
|
||||
_ => None,
|
||||
|
@ -393,11 +393,11 @@ impl MetaItem {
|
|||
}
|
||||
|
||||
impl MetaItemKind {
|
||||
fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<NestedMetaItem>> {
|
||||
fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
|
||||
let mut tokens = tokens.trees().peekable();
|
||||
let mut result = ThinVec::new();
|
||||
while tokens.peek().is_some() {
|
||||
let item = NestedMetaItem::from_tokens(&mut tokens)?;
|
||||
let item = MetaItemInner::from_tokens(&mut tokens)?;
|
||||
result.push(item);
|
||||
match tokens.next() {
|
||||
None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
|
||||
|
@ -460,11 +460,11 @@ impl MetaItemKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl NestedMetaItem {
|
||||
impl MetaItemInner {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
NestedMetaItem::MetaItem(item) => item.span,
|
||||
NestedMetaItem::Lit(lit) => lit.span,
|
||||
MetaItemInner::MetaItem(item) => item.span,
|
||||
MetaItemInner::Lit(lit) => lit.span,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,7 @@ impl NestedMetaItem {
|
|||
}
|
||||
|
||||
/// Gets a list of inner meta items from a list `MetaItem` type.
|
||||
pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
|
||||
pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
|
||||
self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
|
||||
}
|
||||
|
||||
|
@ -519,18 +519,28 @@ impl NestedMetaItem {
|
|||
self.meta_item().and_then(|meta_item| meta_item.value_str())
|
||||
}
|
||||
|
||||
/// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s.
|
||||
/// Returns the `MetaItemLit` if `self` is a `MetaItemInner::Literal`s.
|
||||
pub fn lit(&self) -> Option<&MetaItemLit> {
|
||||
match self {
|
||||
NestedMetaItem::Lit(lit) => Some(lit),
|
||||
MetaItemInner::Lit(lit) => Some(lit),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
|
||||
/// Returns the `MetaItem` if `self` is a `MetaItemInner::MetaItem` or if it's
|
||||
/// `MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`.
|
||||
pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
|
||||
match self {
|
||||
MetaItemInner::MetaItem(_item) => Some(self),
|
||||
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `MetaItem` if `self` is a `MetaItemInner::MetaItem`.
|
||||
pub fn meta_item(&self) -> Option<&MetaItem> {
|
||||
match self {
|
||||
NestedMetaItem::MetaItem(item) => Some(item),
|
||||
MetaItemInner::MetaItem(item) => Some(item),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -540,22 +550,22 @@ impl NestedMetaItem {
|
|||
self.meta_item().is_some()
|
||||
}
|
||||
|
||||
fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
|
||||
fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemInner>
|
||||
where
|
||||
I: Iterator<Item = &'a TokenTree>,
|
||||
{
|
||||
match tokens.peek() {
|
||||
Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
|
||||
tokens.next();
|
||||
return Some(NestedMetaItem::Lit(lit));
|
||||
return Some(MetaItemInner::Lit(lit));
|
||||
}
|
||||
Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
|
||||
tokens.next();
|
||||
return NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable());
|
||||
return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
|
||||
MetaItem::from_tokens(tokens).map(MetaItemInner::MetaItem)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,6 +676,6 @@ pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
|
|||
find_by_name(attrs, name).is_some()
|
||||
}
|
||||
|
||||
pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
|
||||
pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
|
||||
items.iter().any(|item| item.has_name(name))
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ pub trait MutVisitor: Sized {
|
|||
walk_crate(self, c)
|
||||
}
|
||||
|
||||
fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) {
|
||||
fn visit_meta_list_item(&mut self, list_item: &mut MetaItemInner) {
|
||||
walk_meta_list_item(self, list_item);
|
||||
}
|
||||
|
||||
|
@ -519,10 +519,6 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
|||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl));
|
||||
}
|
||||
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
|
||||
vis.visit_id(id);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||
}
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
|
@ -659,10 +655,10 @@ fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) {
|
|||
visit_delim_args(vis, body);
|
||||
}
|
||||
|
||||
fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut NestedMetaItem) {
|
||||
fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut MetaItemInner) {
|
||||
match li {
|
||||
NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi),
|
||||
NestedMetaItem::Lit(_lit) => {}
|
||||
MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi),
|
||||
MetaItemInner::Lit(_lit) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -287,12 +287,6 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
|||
| ast::TyKind::Pat(..)
|
||||
| ast::TyKind::Dummy
|
||||
| ast::TyKind::Err(..) => break None,
|
||||
|
||||
// These end in brace, but cannot occur in a let-else statement.
|
||||
// They are only parsed as fields of a data structure. For the
|
||||
// purpose of denying trailing braces in the expression of a
|
||||
// let-else, we can disregard these.
|
||||
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -535,9 +535,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
|||
TyKind::Err(_guar) => {}
|
||||
TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
||||
TyKind::Never | TyKind::CVarArgs => {}
|
||||
TyKind::AnonStruct(_id, ref fields) | TyKind::AnonUnion(_id, ref fields) => {
|
||||
walk_list!(visitor, visit_field_def, fields);
|
||||
}
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
|
|
@ -226,6 +226,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_opaque_ty(&mut self, opaq: &'hir OpaqueTy<'hir>) {
|
||||
self.insert(opaq.span, opaq.hir_id, Node::OpaqueTy(opaq));
|
||||
|
||||
self.with_parent(opaq.hir_id, |this| {
|
||||
intravisit::walk_opaque_ty(this, opaq);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
|
||||
// FIXME: use real span?
|
||||
self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
|
||||
|
|
|
@ -1259,46 +1259,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let kind = match &t.kind {
|
||||
TyKind::Infer => hir::TyKind::Infer,
|
||||
TyKind::Err(guar) => hir::TyKind::Err(*guar),
|
||||
// Lower the anonymous structs or unions in a nested lowering context.
|
||||
//
|
||||
// ```
|
||||
// struct Foo {
|
||||
// _: union {
|
||||
// // ^__________________ <-- within the nested lowering context,
|
||||
// /* fields */ // | we lower all fields defined into an
|
||||
// } // | owner node of struct or union item
|
||||
// // ^_____________________|
|
||||
// }
|
||||
// ```
|
||||
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
|
||||
// Here its `def_id` is created in `build_reduced_graph`.
|
||||
let def_id = self.local_def_id(*node_id);
|
||||
debug!(?def_id);
|
||||
let owner_id = hir::OwnerId { def_id };
|
||||
self.with_hir_id_owner(*node_id, |this| {
|
||||
let fields = this.arena.alloc_from_iter(
|
||||
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
|
||||
);
|
||||
let span = t.span;
|
||||
let variant_data =
|
||||
hir::VariantData::Struct { fields, recovered: ast::Recovered::No };
|
||||
// FIXME: capture the generics from the outer adt.
|
||||
let generics = hir::Generics::empty();
|
||||
let kind = match t.kind {
|
||||
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
|
||||
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
|
||||
ident: Ident::new(kw::Empty, span),
|
||||
owner_id,
|
||||
kind,
|
||||
span: this.lower_span(span),
|
||||
vis_span: this.lower_span(span.shrink_to_lo()),
|
||||
}))
|
||||
});
|
||||
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
|
||||
}
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||
TyKind::Ref(region, mt) => {
|
||||
|
@ -1367,14 +1327,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// takes care of rejecting invalid modifier combinations and
|
||||
// const trait bounds in trait object types.
|
||||
GenericBound::Trait(ty, modifiers) => {
|
||||
// Still, don't pass along the constness here; we don't want to
|
||||
// synthesize any host effect args, it'd only cause problems.
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
..*modifiers
|
||||
};
|
||||
let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers);
|
||||
let polarity = this.lower_trait_bound_modifiers(modifiers);
|
||||
let trait_ref = this.lower_poly_trait_ref(ty, itctx, *modifiers);
|
||||
let polarity = this.lower_trait_bound_modifiers(*modifiers);
|
||||
Some((trait_ref, polarity))
|
||||
}
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
|
@ -1573,11 +1527,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Feature gate for RPITIT + use<..>
|
||||
match origin {
|
||||
rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => {
|
||||
if let Some(span) = bounds.iter().find_map(|bound| match *bound {
|
||||
ast::GenericBound::Use(_, span) => Some(span),
|
||||
_ => None,
|
||||
}) {
|
||||
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span });
|
||||
if !self.tcx.features().precise_capturing_in_traits
|
||||
&& let Some(span) = bounds.iter().find_map(|bound| match *bound {
|
||||
ast::GenericBound::Use(_, span) => Some(span),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
let mut diag =
|
||||
self.tcx.dcx().create_err(errors::NoPreciseCapturesOnRpitit { span });
|
||||
add_feature_diagnostics(
|
||||
&mut diag,
|
||||
self.tcx.sess,
|
||||
sym::precise_capturing_in_traits,
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -1603,7 +1566,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
|
||||
) -> hir::TyKind<'hir> {
|
||||
let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
|
||||
debug!(?opaque_ty_def_id);
|
||||
let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id);
|
||||
debug!(?opaque_ty_def_id, ?opaque_ty_hir_id);
|
||||
|
||||
// Map from captured (old) lifetime to synthetic (new) lifetime.
|
||||
// Used to resolve lifetimes in the bounds of the opaque.
|
||||
|
@ -1676,7 +1640,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
||||
let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| {
|
||||
// Install the remapping from old to new (if any). This makes sure that
|
||||
// any lifetimes that would have resolved to the def-id of captured
|
||||
// lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
|
||||
|
@ -1714,7 +1678,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);
|
||||
|
||||
let opaque_ty_item = hir::OpaqueTy {
|
||||
trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
|
||||
let opaque_ty_def = hir::OpaqueTy {
|
||||
hir_id: opaque_ty_hir_id,
|
||||
def_id: opaque_ty_def_id,
|
||||
generics: this.arena.alloc(hir::Generics {
|
||||
params: generic_params,
|
||||
predicates: &[],
|
||||
|
@ -1725,19 +1692,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
bounds,
|
||||
origin,
|
||||
lifetime_mapping,
|
||||
};
|
||||
|
||||
// Generate an `type Foo = impl Trait;` declaration.
|
||||
trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
|
||||
let opaque_ty_item = hir::Item {
|
||||
owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
|
||||
ident: Ident::empty(),
|
||||
kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
|
||||
vis_span: this.lower_span(span.shrink_to_lo()),
|
||||
span: this.lower_span(opaque_ty_span),
|
||||
};
|
||||
|
||||
hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
|
||||
this.arena.alloc(opaque_ty_def)
|
||||
});
|
||||
|
||||
let generic_args = self.arena.alloc_from_iter(
|
||||
|
@ -1750,10 +1707,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Foo = impl Trait` is, internally, created as a child of the
|
||||
// async fn, so the *type parameters* are inherited. It's
|
||||
// only the lifetime parameters that we must supply.
|
||||
hir::TyKind::OpaqueDef(
|
||||
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
|
||||
generic_args,
|
||||
)
|
||||
hir::TyKind::OpaqueDef(opaque_ty_def, generic_args)
|
||||
}
|
||||
|
||||
fn lower_precise_capturing_args(
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
ast_passes_anon_struct_or_union_not_allowed =
|
||||
anonymous {$struct_or_union}s are not allowed outside of unnamed struct or union fields
|
||||
.label = anonymous {$struct_or_union} declared here
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
@ -160,14 +156,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
|
|||
.type = inherent impl for this type
|
||||
.only_trait = only trait implementations may be annotated with {$annotation}
|
||||
|
||||
ast_passes_invalid_unnamed_field =
|
||||
unnamed fields are not allowed outside of structs or unions
|
||||
.label = unnamed field declared here
|
||||
|
||||
ast_passes_invalid_unnamed_field_ty =
|
||||
unnamed fields can only have struct or union types
|
||||
.label = not a struct or union
|
||||
|
||||
ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
|
||||
.suggestion = remove safe from this item
|
||||
|
||||
|
|
|
@ -244,9 +244,6 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
|
||||
walk_list!(self, visit_struct_field_def, fields)
|
||||
}
|
||||
_ => visit::walk_ty(self, t),
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +252,6 @@ impl<'a> AstValidator<'a> {
|
|||
if let Some(ident) = field.ident
|
||||
&& ident.name == kw::Underscore
|
||||
{
|
||||
self.check_unnamed_field_ty(&field.ty, ident.span);
|
||||
self.visit_vis(&field.vis);
|
||||
self.visit_ident(ident);
|
||||
self.visit_ty_common(&field.ty);
|
||||
|
@ -294,39 +290,6 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) {
|
||||
if matches!(
|
||||
&ty.kind,
|
||||
// We already checked for `kw::Underscore` before calling this function,
|
||||
// so skip the check
|
||||
TyKind::AnonStruct(..) | TyKind::AnonUnion(..)
|
||||
// If the anonymous field contains a Path as type, we can't determine
|
||||
// if the path is a valid struct or union, so skip the check
|
||||
| TyKind::Path(..)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
self.dcx().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
|
||||
}
|
||||
|
||||
fn deny_anon_struct_or_union(&self, ty: &Ty) {
|
||||
let struct_or_union = match &ty.kind {
|
||||
TyKind::AnonStruct(..) => "struct",
|
||||
TyKind::AnonUnion(..) => "union",
|
||||
_ => return,
|
||||
};
|
||||
self.dcx().emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
|
||||
}
|
||||
|
||||
fn deny_unnamed_field(&self, field: &FieldDef) {
|
||||
if let Some(ident) = field.ident
|
||||
&& ident.name == kw::Underscore
|
||||
{
|
||||
self.dcx()
|
||||
.emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
|
||||
let Const::Yes(span) = constness else {
|
||||
return;
|
||||
|
@ -890,15 +853,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
self.visit_ty_common(ty);
|
||||
self.deny_anon_struct_or_union(ty);
|
||||
self.walk_ty(ty)
|
||||
}
|
||||
|
||||
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
||||
self.deny_unnamed_field(field);
|
||||
visit::walk_field_def(self, field)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'a Item) {
|
||||
if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
|
||||
self.has_proc_macro_decls = true;
|
||||
|
|
|
@ -814,33 +814,6 @@ pub(crate) struct NegativeBoundWithParentheticalNotation {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_invalid_unnamed_field_ty)]
|
||||
pub(crate) struct InvalidUnnamedFieldTy {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub ty_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_invalid_unnamed_field)]
|
||||
pub(crate) struct InvalidUnnamedField {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub ident_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_anon_struct_or_union_not_allowed)]
|
||||
pub(crate) struct AnonStructOrUnionNotAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub struct_or_union: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_match_arm_with_no_body)]
|
||||
pub(crate) struct MatchArmWithNoBody {
|
||||
|
|
|
@ -186,9 +186,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
// Check unstable flavors of the `#[doc]` attribute.
|
||||
if attr.has_name(sym::doc) {
|
||||
for nested_meta in attr.meta_item_list().unwrap_or_default() {
|
||||
for meta_item_inner in attr.meta_item_list().unwrap_or_default() {
|
||||
macro_rules! gate_doc { ($($s:literal { $($name:ident => $feature:ident)* })*) => {
|
||||
$($(if nested_meta.has_name(sym::$name) {
|
||||
$($(if meta_item_inner.has_name(sym::$name) {
|
||||
let msg = concat!("`#[doc(", stringify!($name), ")]` is ", $s);
|
||||
gate!(self, $feature, attr.span, msg);
|
||||
})*)*
|
||||
|
@ -541,7 +541,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||
gate_all!(generic_const_items, "generic const items are experimental");
|
||||
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
|
|
|
@ -67,7 +67,7 @@ pub fn vis_to_string(v: &ast::Visibility) -> String {
|
|||
State::new().vis_to_string(v)
|
||||
}
|
||||
|
||||
pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
|
||||
pub fn meta_list_item_to_string(li: &ast::MetaItemInner) -> String {
|
||||
State::new().meta_list_item_to_string(li)
|
||||
}
|
||||
|
||||
|
|
|
@ -1174,14 +1174,6 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.pclose();
|
||||
}
|
||||
ast::TyKind::AnonStruct(_, fields) => {
|
||||
self.head("struct");
|
||||
self.print_record_struct_body(fields, ty.span);
|
||||
}
|
||||
ast::TyKind::AnonUnion(_, fields) => {
|
||||
self.head("union");
|
||||
self.print_record_struct_body(fields, ty.span);
|
||||
}
|
||||
ast::TyKind::Paren(typ) => {
|
||||
self.popen();
|
||||
self.print_type(typ);
|
||||
|
@ -2006,10 +1998,10 @@ impl<'a> State<'a> {
|
|||
self.print_attribute_inline(attr, false)
|
||||
}
|
||||
|
||||
fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
|
||||
fn print_meta_list_item(&mut self, item: &ast::MetaItemInner) {
|
||||
match item {
|
||||
ast::NestedMetaItem::MetaItem(mi) => self.print_meta_item(mi),
|
||||
ast::NestedMetaItem::Lit(lit) => self.print_meta_item_lit(lit),
|
||||
ast::MetaItemInner::MetaItem(mi) => self.print_meta_item(mi),
|
||||
ast::MetaItemInner::Lit(lit) => self.print_meta_item_lit(lit),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2054,7 +2046,7 @@ impl<'a> State<'a> {
|
|||
Self::to_string(|s| s.print_path_segment(p, false))
|
||||
}
|
||||
|
||||
pub(crate) fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
|
||||
pub(crate) fn meta_list_item_to_string(&self, li: &ast::MetaItemInner) -> String {
|
||||
Self::to_string(|s| s.print_meta_list_item(li))
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,8 @@ attr_unknown_version_literal =
|
|||
attr_unstable_cfg_target_compact =
|
||||
compact `cfg(target(..))` is experimental and subject to change
|
||||
|
||||
attr_unsupported_literal_cfg_boolean =
|
||||
literal in `cfg` predicate value must be a boolean
|
||||
attr_unsupported_literal_cfg_string =
|
||||
literal in `cfg` predicate value must be a string
|
||||
attr_unsupported_literal_deprecated_kv_pair =
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::num::NonZero;
|
|||
|
||||
use rustc_abi::Align;
|
||||
use rustc_ast::{
|
||||
self as ast, Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId,
|
||||
self as ast, Attribute, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId,
|
||||
attr,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
|
@ -18,7 +18,7 @@ use rustc_session::parse::feature_err;
|
|||
use rustc_session::{RustcVersion, Session};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use rustc_span::symbol::{Symbol, kw, sym};
|
||||
|
||||
use crate::fluent_generated;
|
||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||
|
@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
|||
pub(crate) enum UnsupportedLiteralReason {
|
||||
Generic,
|
||||
CfgString,
|
||||
CfgBoolean,
|
||||
DeprecatedString,
|
||||
DeprecatedKvPair,
|
||||
}
|
||||
|
@ -533,7 +534,7 @@ pub struct Condition {
|
|||
|
||||
/// Tests if a cfg-pattern matches the cfg set
|
||||
pub fn cfg_matches(
|
||||
cfg: &ast::MetaItem,
|
||||
cfg: &ast::MetaItemInner,
|
||||
sess: &Session,
|
||||
lint_node_id: NodeId,
|
||||
features: Option<&Features>,
|
||||
|
@ -604,22 +605,53 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
|||
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
|
||||
/// evaluate individual items.
|
||||
pub fn eval_condition(
|
||||
cfg: &ast::MetaItem,
|
||||
cfg: &ast::MetaItemInner,
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
eval: &mut impl FnMut(Condition) -> bool,
|
||||
) -> bool {
|
||||
let dcx = sess.dcx();
|
||||
|
||||
let cfg = match cfg {
|
||||
ast::MetaItemInner::MetaItem(meta_item) => meta_item,
|
||||
ast::MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
|
||||
if let Some(features) = features {
|
||||
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
|
||||
// and `true`, and we want to keep the former working without feature gate
|
||||
gate_cfg(
|
||||
&((
|
||||
if *b { kw::True } else { kw::False },
|
||||
sym::cfg_boolean_literals,
|
||||
|features: &Features| features.cfg_boolean_literals,
|
||||
)),
|
||||
cfg.span(),
|
||||
sess,
|
||||
features,
|
||||
);
|
||||
}
|
||||
return *b;
|
||||
}
|
||||
_ => {
|
||||
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: cfg.span(),
|
||||
reason: UnsupportedLiteralReason::CfgBoolean,
|
||||
is_bytestr: false,
|
||||
start_point_span: sess.source_map().start_point(cfg.span()),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
match &cfg.kind {
|
||||
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
|
||||
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||
let (min_version, span) = match &mis[..] {
|
||||
[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
|
||||
[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
|
||||
(sym, span)
|
||||
}
|
||||
[
|
||||
NestedMetaItem::Lit(MetaItemLit { span, .. })
|
||||
| NestedMetaItem::MetaItem(MetaItem { span, .. }),
|
||||
MetaItemInner::Lit(MetaItemLit { span, .. })
|
||||
| MetaItemInner::MetaItem(MetaItem { span, .. }),
|
||||
] => {
|
||||
dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
|
||||
return false;
|
||||
|
@ -645,7 +677,7 @@ pub fn eval_condition(
|
|||
}
|
||||
ast::MetaItemKind::List(mis) => {
|
||||
for mi in mis.iter() {
|
||||
if !mi.is_meta_item() {
|
||||
if mi.meta_item_or_bool().is_none() {
|
||||
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: mi.span(),
|
||||
reason: UnsupportedLiteralReason::Generic,
|
||||
|
@ -663,23 +695,19 @@ pub fn eval_condition(
|
|||
.iter()
|
||||
// We don't use any() here, because we want to evaluate all cfg condition
|
||||
// as eval_condition can (and does) extra checks
|
||||
.fold(false, |res, mi| {
|
||||
res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
||||
}),
|
||||
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
|
||||
sym::all => mis
|
||||
.iter()
|
||||
// We don't use all() here, because we want to evaluate all cfg condition
|
||||
// as eval_condition can (and does) extra checks
|
||||
.fold(true, |res, mi| {
|
||||
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
||||
}),
|
||||
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
|
||||
sym::not => {
|
||||
let [mi] = mis.as_slice() else {
|
||||
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
||||
return false;
|
||||
};
|
||||
|
||||
!eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
||||
!eval_condition(mi, sess, features, eval)
|
||||
}
|
||||
sym::target => {
|
||||
if let Some(features) = features
|
||||
|
@ -700,7 +728,12 @@ pub fn eval_condition(
|
|||
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
|
||||
}
|
||||
|
||||
res & eval_condition(&mi, sess, features, eval)
|
||||
res & eval_condition(
|
||||
&ast::MetaItemInner::MetaItem(mi),
|
||||
sess,
|
||||
features,
|
||||
eval,
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
|
@ -840,7 +873,7 @@ pub fn find_deprecation(
|
|||
|
||||
for meta in list {
|
||||
match meta {
|
||||
NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
|
||||
MetaItemInner::MetaItem(mi) => match mi.name_or_empty() {
|
||||
sym::since => {
|
||||
if !get(mi, &mut since) {
|
||||
continue 'outer;
|
||||
|
@ -879,7 +912,7 @@ pub fn find_deprecation(
|
|||
continue 'outer;
|
||||
}
|
||||
},
|
||||
NestedMetaItem::Lit(lit) => {
|
||||
MetaItemInner::Lit(lit) => {
|
||||
sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: lit.span,
|
||||
reason: UnsupportedLiteralReason::DeprecatedKvPair,
|
||||
|
@ -1244,7 +1277,7 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {
|
|||
let mut candidates = Vec::new();
|
||||
|
||||
for meta in metas {
|
||||
let NestedMetaItem::Lit(meta_lit) = meta else {
|
||||
let MetaItemInner::Lit(meta_lit) = meta else {
|
||||
return None;
|
||||
};
|
||||
candidates.push(meta_lit.symbol);
|
||||
|
|
|
@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
|
|||
let mut diag = Diag::new(dcx, level, match self.reason {
|
||||
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
|
||||
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
|
||||
UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean,
|
||||
UnsupportedLiteralReason::DeprecatedString => {
|
||||
fluent::attr_unsupported_literal_deprecated_string
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! This file provides API for compiler consumers.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::{Body, Promoted};
|
||||
|
@ -65,10 +63,10 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
|||
/// The mir bodies of promoteds.
|
||||
pub promoted: IndexVec<Promoted, Body<'tcx>>,
|
||||
/// The set of borrows occurring in `body` with data about them.
|
||||
pub borrow_set: Rc<BorrowSet<'tcx>>,
|
||||
pub borrow_set: BorrowSet<'tcx>,
|
||||
/// Context generated during borrowck, intended to be passed to
|
||||
/// [`calculate_borrows_out_of_scope_at_location`].
|
||||
pub region_inference_context: Rc<RegionInferenceContext<'tcx>>,
|
||||
pub region_inference_context: RegionInferenceContext<'tcx>,
|
||||
/// The table that maps Polonius points to locations in the table.
|
||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
|
@ -79,7 +77,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
|||
pub input_facts: Option<Box<PoloniusInput>>,
|
||||
/// Polonius output facts. Populated when using
|
||||
/// [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
pub output_facts: Option<Rc<PoloniusOutput>>,
|
||||
pub output_facts: Option<Box<PoloniusOutput>>,
|
||||
}
|
||||
|
||||
/// This function computes borrowck facts for the given body. The [`ConsumerOptions`]
|
||||
|
|
|
@ -708,9 +708,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// for the branching codepaths that aren't covered, to point at them.
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body = map.body_owned_by(self.mir_def_id());
|
||||
let mut visitor =
|
||||
ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
|
||||
let mut visitor = ConditionVisitor { tcx: self.infcx.tcx, spans, name, errors: vec![] };
|
||||
visitor.visit_body(&body);
|
||||
let spans = visitor.spans;
|
||||
|
||||
let mut show_assign_sugg = false;
|
||||
let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
|
||||
|
@ -4465,20 +4465,20 @@ impl<'hir> Visitor<'hir> for BreakFinder {
|
|||
|
||||
/// Given a set of spans representing statements initializing the relevant binding, visit all the
|
||||
/// function expressions looking for branching code paths that *do not* initialize the binding.
|
||||
struct ConditionVisitor<'b, 'tcx> {
|
||||
struct ConditionVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
spans: &'b [Span],
|
||||
name: &'b str,
|
||||
spans: Vec<Span>,
|
||||
name: String,
|
||||
errors: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
||||
impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||
match ex.kind {
|
||||
hir::ExprKind::If(cond, body, None) => {
|
||||
// `if` expressions with no `else` that initialize the binding might be missing an
|
||||
// `else` arm.
|
||||
if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() {
|
||||
if ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break() {
|
||||
self.errors.push((
|
||||
cond.span,
|
||||
format!(
|
||||
|
@ -4495,8 +4495,8 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
hir::ExprKind::If(cond, body, Some(other)) => {
|
||||
// `if` expressions where the binding is only initialized in one of the two arms
|
||||
// might be missing a binding initialization.
|
||||
let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break();
|
||||
let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break();
|
||||
let a = ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break();
|
||||
let b = ReferencedStatementsVisitor(&self.spans).visit_expr(other).is_break();
|
||||
match (a, b) {
|
||||
(true, true) | (false, false) => {}
|
||||
(true, false) => {
|
||||
|
@ -4536,7 +4536,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
// arms might be missing an initialization.
|
||||
let results: Vec<bool> = arms
|
||||
.iter()
|
||||
.map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break())
|
||||
.map(|arm| ReferencedStatementsVisitor(&self.spans).visit_arm(arm).is_break())
|
||||
.collect();
|
||||
if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
|
||||
for (arm, seen) in arms.iter().zip(results) {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
|
||||
|
@ -11,7 +10,7 @@ use crate::region_infer::{Cause, RegionInferenceContext};
|
|||
|
||||
pub(crate) fn find<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &Rc<RegionInferenceContext<'tcx>>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_vid: RegionVid,
|
||||
start_point: Location,
|
||||
|
@ -23,7 +22,7 @@ pub(crate) fn find<'tcx>(
|
|||
|
||||
struct UseFinder<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
regioncx: &'a Rc<RegionInferenceContext<'tcx>>,
|
||||
regioncx: &'a RegionInferenceContext<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_vid: RegionVid,
|
||||
start_point: Location,
|
||||
|
|
|
@ -706,7 +706,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
suggestions.push((
|
||||
pat_span,
|
||||
format!("consider removing the {to_remove}"),
|
||||
suggestion.to_string(),
|
||||
suggestion,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -830,20 +830,14 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
///
|
||||
/// [`OpaqueDef`]: hir::TyKind::OpaqueDef
|
||||
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
|
||||
let hir = self.infcx.tcx.hir();
|
||||
|
||||
let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
|
||||
let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else {
|
||||
span_bug!(
|
||||
hir_ty.span,
|
||||
"lowered return type of async fn is not OpaqueDef: {:?}",
|
||||
hir_ty
|
||||
);
|
||||
};
|
||||
let opaque_ty = hir.item(id);
|
||||
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||
bounds: [hir::GenericBound::Trait(trait_ref, _)],
|
||||
..
|
||||
}) = opaque_ty.kind
|
||||
if let hir::OpaqueTy { bounds: [hir::GenericBound::Trait(trait_ref, _)], .. } = opaque_ty
|
||||
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
||||
&& let Some(args) = segment.args
|
||||
&& let [constraint] = args.constraints
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
|
@ -20,7 +19,6 @@ use std::cell::RefCell;
|
|||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
|
@ -201,8 +199,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
.into_results_cursor(body);
|
||||
|
||||
let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
|
||||
let borrow_set =
|
||||
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data));
|
||||
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
|
||||
|
||||
// Compute non-lexical lifetimes.
|
||||
let nll::NllOutput {
|
||||
|
@ -246,8 +243,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
// usage significantly on some benchmarks.
|
||||
drop(flow_inits);
|
||||
|
||||
let regioncx = Rc::new(regioncx);
|
||||
|
||||
let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set)
|
||||
.into_engine(tcx, body)
|
||||
.pass_name("borrowck")
|
||||
|
@ -289,10 +284,10 @@ fn do_mir_borrowck<'tcx>(
|
|||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
uninitialized_error_reported: Default::default(),
|
||||
regioncx: regioncx.clone(),
|
||||
regioncx: ®ioncx,
|
||||
used_mut: Default::default(),
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
borrow_set: Rc::clone(&borrow_set),
|
||||
borrow_set: &borrow_set,
|
||||
upvars: &[],
|
||||
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
|
||||
region_names: RefCell::default(),
|
||||
|
@ -330,10 +325,10 @@ fn do_mir_borrowck<'tcx>(
|
|||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
uninitialized_error_reported: Default::default(),
|
||||
regioncx: Rc::clone(®ioncx),
|
||||
regioncx: ®ioncx,
|
||||
used_mut: Default::default(),
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
borrow_set: Rc::clone(&borrow_set),
|
||||
borrow_set: &borrow_set,
|
||||
upvars: tcx.closure_captures(def),
|
||||
local_names,
|
||||
region_names: RefCell::default(),
|
||||
|
@ -570,10 +565,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
|
||||
/// Region inference context. This contains the results from region inference and lets us e.g.
|
||||
/// find out which CFG points are contained in each borrow region.
|
||||
regioncx: Rc<RegionInferenceContext<'tcx>>,
|
||||
regioncx: &'a RegionInferenceContext<'tcx>,
|
||||
|
||||
/// The set of borrows extracted from the MIR
|
||||
borrow_set: Rc<BorrowSet<'tcx>>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
|
||||
/// Information about upvars not necessarily preserved in types or MIR
|
||||
upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
|
||||
|
@ -589,7 +584,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
next_region_name: RefCell<usize>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
|
||||
diags: diags::BorrowckDiags<'infcx, 'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
|
@ -743,6 +738,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||
}
|
||||
|
||||
TerminatorKind::InlineAsm {
|
||||
asm_macro: _,
|
||||
template: _,
|
||||
operands,
|
||||
options: _,
|
||||
|
@ -800,9 +796,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||
TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
|
||||
if self.movable_coroutine {
|
||||
// Look for any active borrows to locals
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &borrow_set[i];
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_local_borrow(borrow, span);
|
||||
}
|
||||
}
|
||||
|
@ -816,9 +811,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &borrow_set[i];
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
}
|
||||
}
|
||||
|
@ -1037,13 +1031,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
) -> bool {
|
||||
let mut error_reported = false;
|
||||
let borrow_set = Rc::clone(&self.borrow_set);
|
||||
|
||||
// Use polonius output if it has been enabled.
|
||||
let mut polonius_output;
|
||||
let borrows_in_scope = if let Some(polonius) = &self.polonius_output {
|
||||
let location = self.location_table.start_index(location);
|
||||
polonius_output = BitSet::new_empty(borrow_set.len());
|
||||
polonius_output = BitSet::new_empty(self.borrow_set.len());
|
||||
for &idx in polonius.errors_at(location) {
|
||||
polonius_output.insert(idx);
|
||||
}
|
||||
|
@ -1057,7 +1050,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
self.infcx.tcx,
|
||||
self.body,
|
||||
(sd, place_span.0),
|
||||
&borrow_set,
|
||||
self.borrow_set,
|
||||
|borrow_index| borrows_in_scope.contains(borrow_index),
|
||||
|this, borrow_index, borrow| match (rw, borrow.kind) {
|
||||
// Obviously an activation is compatible with its own
|
||||
|
@ -1580,9 +1573,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
// Two-phase borrow support: For each activation that is newly
|
||||
// generated at this statement, check if it interferes with
|
||||
// another borrow.
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
for &borrow_index in borrow_set.activations_at_location(location) {
|
||||
let borrow = &borrow_set[borrow_index];
|
||||
for &borrow_index in self.borrow_set.activations_at_location(location) {
|
||||
let borrow = &self.borrow_set[borrow_index];
|
||||
|
||||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
|
|
|
@ -42,7 +42,7 @@ pub(crate) struct NllOutput<'tcx> {
|
|||
pub regioncx: RegionInferenceContext<'tcx>,
|
||||
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
pub polonius_input: Option<Box<AllFacts>>,
|
||||
pub polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
pub polonius_output: Option<Box<PoloniusOutput>>,
|
||||
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
||||
pub nll_errors: RegionErrors<'tcx>,
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
|
||||
let universal_regions = Rc::new(universal_regions);
|
||||
|
||||
let elements = &Rc::new(DenseLocationMap::new(body));
|
||||
let elements = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
|
||||
|
@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
param_env,
|
||||
body,
|
||||
promoted,
|
||||
&universal_regions,
|
||||
universal_regions.clone(),
|
||||
location_table,
|
||||
borrow_set,
|
||||
&mut all_facts,
|
||||
flow_inits,
|
||||
move_data,
|
||||
elements,
|
||||
elements.clone(),
|
||||
upvars,
|
||||
);
|
||||
|
||||
|
@ -184,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
let algorithm = Algorithm::from_str(&algorithm).unwrap();
|
||||
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
|
||||
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
|
||||
Some(Rc::new(Output::compute(all_facts, algorithm, false)))
|
||||
Some(Box::new(Output::compute(all_facts, algorithm, false)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! we can prove overlap one way or another. Essentially, we treat `Overlap` as
|
||||
//! a monoid and report a conflict if the product ends up not being `Disjoint`.
|
||||
//!
|
||||
//! At each step, if we didn't run out of borrow or place, we know that our elements
|
||||
//! On each step, if we didn't run out of borrow or place, we know that our elements
|
||||
//! have the same type, and that they only overlap if they are the identical.
|
||||
//!
|
||||
//! For example, if we are comparing these:
|
||||
|
|
|
@ -169,6 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
TerminatorKind::InlineAsm {
|
||||
asm_macro: _,
|
||||
template: _,
|
||||
operands,
|
||||
options: _,
|
||||
|
|
|
@ -407,7 +407,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
type_tests: Vec<TypeTest<'tcx>>,
|
||||
liveness_constraints: LivenessValues,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
) -> Self {
|
||||
debug!("universal_regions: {:#?}", universal_regions);
|
||||
debug!("outlives constraints: {:#?}", outlives_constraints);
|
||||
|
@ -430,7 +430,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
let mut scc_values =
|
||||
RegionValues::new(elements, universal_regions.len(), &placeholder_indices);
|
||||
RegionValues::new(elements, universal_regions.len(), placeholder_indices);
|
||||
|
||||
for region in liveness_constraints.regions() {
|
||||
let scc = constraint_sccs.scc(region);
|
||||
|
@ -637,7 +637,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
|
||||
let mir_def_id = body.source.def_id();
|
||||
self.propagate_constraints();
|
||||
|
@ -663,7 +663,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
self.check_polonius_subset_errors(
|
||||
outlives_requirements.as_mut(),
|
||||
&mut errors_buffer,
|
||||
polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"),
|
||||
polonius_output
|
||||
.as_ref()
|
||||
.expect("Polonius output is unavailable despite `-Z polonius`"),
|
||||
);
|
||||
} else {
|
||||
self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
|
@ -1411,7 +1413,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
&self,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
polonius_output: Rc<PoloniusOutput>,
|
||||
polonius_output: &PoloniusOutput,
|
||||
) {
|
||||
debug!(
|
||||
"check_polonius_subset_errors: {} subset_errors",
|
||||
|
|
|
@ -329,8 +329,8 @@ fn check_opaque_type_well_formed<'tcx>(
|
|||
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
|
||||
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
|
||||
// on stable and we'd break that.
|
||||
let opaque_ty_hir = tcx.hir().expect_item(def_id);
|
||||
let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else {
|
||||
let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id);
|
||||
let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else {
|
||||
return Ok(definition_ty);
|
||||
};
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
|
|
@ -275,15 +275,16 @@ impl<N: Idx> RegionValues<N> {
|
|||
/// Each of the regions in num_region_variables will be initialized with an
|
||||
/// empty set of points and no causal information.
|
||||
pub(crate) fn new(
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
num_universal_regions: usize,
|
||||
placeholder_indices: &Rc<PlaceholderIndices>,
|
||||
placeholder_indices: Rc<PlaceholderIndices>,
|
||||
) -> Self {
|
||||
let num_points = elements.num_points();
|
||||
let num_placeholders = placeholder_indices.len();
|
||||
Self {
|
||||
elements: elements.clone(),
|
||||
points: SparseIntervalMatrix::new(elements.num_points()),
|
||||
placeholder_indices: placeholder_indices.clone(),
|
||||
elements,
|
||||
points: SparseIntervalMatrix::new(num_points),
|
||||
placeholder_indices,
|
||||
free_regions: SparseBitMatrix::new(num_universal_regions),
|
||||
placeholders: SparseBitMatrix::new(num_placeholders),
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::BorrowckInferCtxt;
|
|||
/// Replaces all free regions appearing in the MIR with fresh
|
||||
/// inference variables, returning the number of variables created.
|
||||
#[instrument(skip(infcx, body, promoted), level = "debug")]
|
||||
pub fn renumber_mir<'tcx>(
|
||||
pub(crate) fn renumber_mir<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &mut Body<'tcx>,
|
||||
promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
|
||||
|
|
|
@ -97,7 +97,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
/// that we computed for the closure. This has the effect of adding new outlives obligations
|
||||
/// to existing region variables in `closure_args`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn apply_closure_requirements(
|
||||
pub(crate) fn apply_closure_requirements(
|
||||
&mut self,
|
||||
closure_requirements: &ClosureRegionRequirements<'tcx>,
|
||||
closure_def_id: DefId,
|
||||
|
|
|
@ -54,7 +54,7 @@ pub(crate) fn create<'tcx>(
|
|||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
) -> CreateResult<'tcx> {
|
||||
UniversalRegionRelationsBuilder {
|
||||
|
@ -62,7 +62,7 @@ pub(crate) fn create<'tcx>(
|
|||
param_env,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions: universal_regions.clone(),
|
||||
universal_regions,
|
||||
region_bound_pairs: Default::default(),
|
||||
outlives: Default::default(),
|
||||
inverse_outlives: Default::default(),
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::mir::visit::{TyContext, Visitor};
|
||||
|
@ -33,7 +31,7 @@ mod trace;
|
|||
pub(super) fn generate<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: &DenseLocationMap,
|
||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::interval::IntervalSet;
|
||||
|
@ -40,7 +38,7 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
|
|||
pub(super) fn trace<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: &DenseLocationMap,
|
||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
relevant_live_locals: Vec<Local>,
|
||||
|
|
|
@ -121,13 +121,13 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
location_table: &LocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
upvars: &[&ty::CapturedPlace<'tcx>],
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||
|
@ -150,14 +150,14 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
infcx,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
universal_regions.clone(),
|
||||
&mut constraints,
|
||||
);
|
||||
|
||||
debug!(?normalized_inputs_and_output);
|
||||
|
||||
let mut borrowck_context = BorrowCheckContext {
|
||||
universal_regions,
|
||||
universal_regions: &universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
all_facts,
|
||||
|
@ -181,10 +181,10 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
verifier.visit_body(body);
|
||||
|
||||
checker.typeck_mir(body);
|
||||
checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output);
|
||||
checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output);
|
||||
checker.check_signature_annotation(body);
|
||||
|
||||
liveness::generate(&mut checker, body, elements, flow_inits, move_data);
|
||||
liveness::generate(&mut checker, body, &elements, flow_inits, move_data);
|
||||
|
||||
translate_outlives_facts(&mut checker);
|
||||
let opaque_type_values = infcx.take_opaque_types();
|
||||
|
|
|
@ -11,6 +11,7 @@ use rustc_middle::span_bug;
|
|||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
@ -362,7 +363,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
|
|||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
|
||||
) if a_def_id == b_def_id || infcx.next_trait_solver() => {
|
||||
infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| {
|
||||
super_combine_tys(&infcx.infcx, self, a, b).map(|_| ()).or_else(|err| {
|
||||
// This behavior is only there for the old solver, the new solver
|
||||
// shouldn't ever fail. Instead, it unconditionally emits an
|
||||
// alias-relate goal.
|
||||
|
@ -385,7 +386,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
|
|||
debug!(?a, ?b, ?self.ambient_variance);
|
||||
|
||||
// Will also handle unification of `IntVar` and `FloatVar`.
|
||||
self.type_checker.infcx.super_combine_tys(self, a, b)?;
|
||||
super_combine_tys(&self.type_checker.infcx.infcx, self, a, b)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -422,7 +423,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
|
|||
assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
|
||||
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
|
||||
|
||||
self.type_checker.infcx.super_combine_consts(self, a, b)
|
||||
super_combine_consts(&self.type_checker.infcx.infcx, self, a, b)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
|
|
|
@ -12,9 +12,9 @@ builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
|
|||
builtin_macros_asm_expected_comma = expected token: `,`
|
||||
.label = expected `,`
|
||||
|
||||
builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
|
||||
[true] options
|
||||
*[false] clobber_abi, options
|
||||
builtin_macros_asm_expected_other = expected operand, {$is_inline_asm ->
|
||||
[false] options
|
||||
*[true] clobber_abi, options
|
||||
}, or additional template string
|
||||
|
||||
builtin_macros_asm_expected_string_literal = expected string literal
|
||||
|
@ -51,6 +51,15 @@ builtin_macros_asm_sym_no_path = expected a path for argument to `sym`
|
|||
|
||||
builtin_macros_asm_underscore_input = _ cannot be used for input operands
|
||||
|
||||
builtin_macros_asm_unsupported_clobber_abi = `clobber_abi` cannot be used with `{$macro_name}!`
|
||||
|
||||
builtin_macros_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `{$macro_name}!`
|
||||
.label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
|
||||
|
||||
builtin_macros_asm_unsupported_option = the `{$symbol}` option cannot be used with `{$macro_name}!`
|
||||
.label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
|
||||
.suggestion = remove this option
|
||||
|
||||
builtin_macros_assert_missing_comma = unexpected string literal
|
||||
.suggestion = try adding a comma
|
||||
|
||||
|
@ -194,15 +203,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
|
|||
|
||||
builtin_macros_format_use_positional = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
|
||||
|
||||
builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
|
||||
.label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
|
||||
|
||||
builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
|
||||
.label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
|
||||
.suggestion = remove this option
|
||||
|
||||
builtin_macros_invalid_crate_attribute = invalid crate attribute
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
|
@ -235,6 +235,8 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
|
|||
.label = declared `#[non_exhaustive]` here
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters
|
||||
|
||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
|
|
|
@ -37,15 +37,23 @@ pub struct AsmArgs {
|
|||
/// - `Ok(true)` if the current token matches the keyword, and was expected
|
||||
/// - `Ok(false)` if the current token does not match the keyword
|
||||
/// - `Err(_)` if the current token matches the keyword, but was not expected
|
||||
fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
|
||||
if expect {
|
||||
fn eat_operand_keyword<'a>(
|
||||
p: &mut Parser<'a>,
|
||||
symbol: Symbol,
|
||||
asm_macro: AsmMacro,
|
||||
) -> PResult<'a, bool> {
|
||||
if matches!(asm_macro, AsmMacro::Asm) {
|
||||
Ok(p.eat_keyword(symbol))
|
||||
} else {
|
||||
let span = p.token.span;
|
||||
if p.eat_keyword_noexpect(symbol) {
|
||||
// in gets printed as `r#in` otherwise
|
||||
let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
|
||||
Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
|
||||
Err(p.dcx().create_err(errors::AsmUnsupportedOperand {
|
||||
span,
|
||||
symbol,
|
||||
macro_name: asm_macro.macro_name(),
|
||||
}))
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
|
@ -56,10 +64,10 @@ fn parse_args<'a>(
|
|||
ecx: &ExtCtxt<'a>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
is_global_asm: bool,
|
||||
asm_macro: AsmMacro,
|
||||
) -> PResult<'a, AsmArgs> {
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
parse_asm_args(&mut p, sp, is_global_asm)
|
||||
parse_asm_args(&mut p, sp, asm_macro)
|
||||
}
|
||||
|
||||
// Primarily public for rustfmt consumption.
|
||||
|
@ -67,7 +75,7 @@ fn parse_args<'a>(
|
|||
pub fn parse_asm_args<'a>(
|
||||
p: &mut Parser<'a>,
|
||||
sp: Span,
|
||||
is_global_asm: bool,
|
||||
asm_macro: AsmMacro,
|
||||
) -> PResult<'a, AsmArgs> {
|
||||
let dcx = p.dcx();
|
||||
|
||||
|
@ -110,7 +118,7 @@ pub fn parse_asm_args<'a>(
|
|||
|
||||
// Parse options
|
||||
if p.eat_keyword(sym::options) {
|
||||
parse_options(p, &mut args, is_global_asm)?;
|
||||
parse_options(p, &mut args, asm_macro)?;
|
||||
allow_templates = false;
|
||||
continue;
|
||||
}
|
||||
|
@ -129,7 +137,7 @@ pub fn parse_asm_args<'a>(
|
|||
};
|
||||
|
||||
let mut explicit_reg = false;
|
||||
let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
|
||||
let op = if eat_operand_keyword(p, kw::In, asm_macro)? {
|
||||
let reg = parse_reg(p, &mut explicit_reg)?;
|
||||
if p.eat_keyword(kw::Underscore) {
|
||||
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
|
||||
|
@ -137,15 +145,15 @@ pub fn parse_asm_args<'a>(
|
|||
}
|
||||
let expr = p.parse_expr()?;
|
||||
ast::InlineAsmOperand::In { reg, expr }
|
||||
} else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
|
||||
} else if eat_operand_keyword(p, sym::out, asm_macro)? {
|
||||
let reg = parse_reg(p, &mut explicit_reg)?;
|
||||
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
|
||||
ast::InlineAsmOperand::Out { reg, expr, late: false }
|
||||
} else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
|
||||
} else if eat_operand_keyword(p, sym::lateout, asm_macro)? {
|
||||
let reg = parse_reg(p, &mut explicit_reg)?;
|
||||
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
|
||||
ast::InlineAsmOperand::Out { reg, expr, late: true }
|
||||
} else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
|
||||
} else if eat_operand_keyword(p, sym::inout, asm_macro)? {
|
||||
let reg = parse_reg(p, &mut explicit_reg)?;
|
||||
if p.eat_keyword(kw::Underscore) {
|
||||
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
|
||||
|
@ -159,7 +167,7 @@ pub fn parse_asm_args<'a>(
|
|||
} else {
|
||||
ast::InlineAsmOperand::InOut { reg, expr, late: false }
|
||||
}
|
||||
} else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
|
||||
} else if eat_operand_keyword(p, sym::inlateout, asm_macro)? {
|
||||
let reg = parse_reg(p, &mut explicit_reg)?;
|
||||
if p.eat_keyword(kw::Underscore) {
|
||||
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
|
||||
|
@ -173,7 +181,7 @@ pub fn parse_asm_args<'a>(
|
|||
} else {
|
||||
ast::InlineAsmOperand::InOut { reg, expr, late: true }
|
||||
}
|
||||
} else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
|
||||
} else if eat_operand_keyword(p, sym::label, asm_macro)? {
|
||||
let block = p.parse_block()?;
|
||||
ast::InlineAsmOperand::Label { block }
|
||||
} else if p.eat_keyword(kw::Const) {
|
||||
|
@ -205,7 +213,7 @@ pub fn parse_asm_args<'a>(
|
|||
_ => {
|
||||
let err = dcx.create_err(errors::AsmExpectedOther {
|
||||
span: template.span,
|
||||
is_global_asm,
|
||||
is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
|
||||
});
|
||||
return Err(err);
|
||||
}
|
||||
|
@ -301,20 +309,25 @@ pub fn parse_asm_args<'a>(
|
|||
dcx.emit_err(errors::AsmMayUnwind { labels_sp });
|
||||
}
|
||||
|
||||
if args.clobber_abis.len() > 0 {
|
||||
if is_global_asm {
|
||||
let err = dcx.create_err(errors::GlobalAsmClobberAbi {
|
||||
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
|
||||
});
|
||||
if !args.clobber_abis.is_empty() {
|
||||
match asm_macro {
|
||||
AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
|
||||
let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
|
||||
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
|
||||
macro_name: asm_macro.macro_name(),
|
||||
});
|
||||
|
||||
// Bail out now since this is likely to confuse later stages
|
||||
return Err(err);
|
||||
}
|
||||
if !regclass_outputs.is_empty() {
|
||||
dcx.emit_err(errors::AsmClobberNoReg {
|
||||
spans: regclass_outputs,
|
||||
clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
|
||||
});
|
||||
// Bail out now since this is likely to confuse later stages
|
||||
return Err(err);
|
||||
}
|
||||
AsmMacro::Asm => {
|
||||
if !regclass_outputs.is_empty() {
|
||||
dcx.emit_err(errors::AsmClobberNoReg {
|
||||
spans: regclass_outputs,
|
||||
clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,10 +348,15 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
|
|||
///
|
||||
/// This function must be called immediately after the option token is parsed.
|
||||
/// Otherwise, the suggestion will be incorrect.
|
||||
fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
|
||||
fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) {
|
||||
// Tool-only output
|
||||
let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
|
||||
p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span });
|
||||
p.dcx().emit_err(errors::AsmUnsupportedOption {
|
||||
span,
|
||||
symbol,
|
||||
full_span,
|
||||
macro_name: asm_macro.macro_name(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Try to set the provided option in the provided `AsmArgs`.
|
||||
|
@ -349,12 +367,12 @@ fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
|
|||
fn try_set_option<'a>(
|
||||
p: &Parser<'a>,
|
||||
args: &mut AsmArgs,
|
||||
is_global_asm: bool,
|
||||
asm_macro: AsmMacro,
|
||||
symbol: Symbol,
|
||||
option: ast::InlineAsmOptions,
|
||||
) {
|
||||
if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
|
||||
err_unsupported_option(p, symbol, p.prev_token.span);
|
||||
if !asm_macro.is_supported_option(option) {
|
||||
err_unsupported_option(p, asm_macro, symbol, p.prev_token.span);
|
||||
} else if args.options.contains(option) {
|
||||
err_duplicate_option(p, symbol, p.prev_token.span);
|
||||
} else {
|
||||
|
@ -365,7 +383,7 @@ fn try_set_option<'a>(
|
|||
fn parse_options<'a>(
|
||||
p: &mut Parser<'a>,
|
||||
args: &mut AsmArgs,
|
||||
is_global_asm: bool,
|
||||
asm_macro: AsmMacro,
|
||||
) -> PResult<'a, ()> {
|
||||
let span_start = p.prev_token.span;
|
||||
|
||||
|
@ -386,15 +404,14 @@ fn parse_options<'a>(
|
|||
|
||||
'blk: {
|
||||
for (symbol, option) in OPTIONS {
|
||||
let kw_matched =
|
||||
if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
|
||||
p.eat_keyword(symbol)
|
||||
} else {
|
||||
p.eat_keyword_noexpect(symbol)
|
||||
};
|
||||
let kw_matched = if asm_macro.is_supported_option(option) {
|
||||
p.eat_keyword(symbol)
|
||||
} else {
|
||||
p.eat_keyword_noexpect(symbol)
|
||||
};
|
||||
|
||||
if kw_matched {
|
||||
try_set_option(p, args, is_global_asm, symbol, option);
|
||||
try_set_option(p, args, asm_macro, symbol, option);
|
||||
break 'blk;
|
||||
}
|
||||
}
|
||||
|
@ -483,7 +500,7 @@ fn parse_reg<'a>(
|
|||
|
||||
fn expand_preparsed_asm(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
asm_macro: ast::AsmMacro,
|
||||
asm_macro: AsmMacro,
|
||||
args: AsmArgs,
|
||||
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
|
||||
let mut template = vec![];
|
||||
|
@ -797,7 +814,7 @@ pub(super) fn expand_asm<'cx>(
|
|||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) {
|
||||
Ok(args) => {
|
||||
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
|
||||
return ExpandResult::Retry(());
|
||||
|
@ -826,29 +843,20 @@ pub(super) fn expand_naked_asm<'cx>(
|
|||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) {
|
||||
Ok(args) => {
|
||||
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
|
||||
else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
let expr = match mac {
|
||||
Ok(mut inline_asm) => {
|
||||
// for future compatibility, we always set the NORETURN option.
|
||||
//
|
||||
// When we turn `asm!` into `naked_asm!` with this implementation, we can drop
|
||||
// the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!`
|
||||
// starts disallowing the `noreturn` option in the future
|
||||
inline_asm.options |= ast::InlineAsmOptions::NORETURN;
|
||||
|
||||
P(ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||
span: sp,
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
})
|
||||
}
|
||||
Ok(inline_asm) => P(ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||
span: sp,
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
}),
|
||||
Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
|
||||
};
|
||||
MacEager::expr(expr)
|
||||
|
@ -865,7 +873,7 @@ pub(super) fn expand_global_asm<'cx>(
|
|||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) {
|
||||
Ok(args) => {
|
||||
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
|
||||
else {
|
||||
|
|
|
@ -6,7 +6,6 @@ use rustc_ast::token;
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
use rustc_parse::parser::attr::AllowLeadingUnsafe;
|
||||
use rustc_span::Span;
|
||||
use {rustc_ast as ast, rustc_attr as attr};
|
||||
|
||||
|
@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
|
|||
})
|
||||
}
|
||||
|
||||
fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
|
||||
fn parse_cfg<'a>(
|
||||
cx: &ExtCtxt<'a>,
|
||||
span: Span,
|
||||
tts: TokenStream,
|
||||
) -> PResult<'a, ast::MetaItemInner> {
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
|
||||
}
|
||||
|
||||
let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?;
|
||||
let cfg = p.parse_meta_item_inner()?;
|
||||
|
||||
let _ = p.eat(&token::Comma);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind};
|
||||
use rustc_expand::base::{
|
||||
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
|
||||
};
|
||||
|
@ -49,9 +49,9 @@ impl MultiItemModifier for Expander {
|
|||
let mut resolutions = match &meta_item.kind {
|
||||
MetaItemKind::List(list) => {
|
||||
list.iter()
|
||||
.filter_map(|nested_meta| match nested_meta {
|
||||
NestedMetaItem::MetaItem(meta) => Some(meta),
|
||||
NestedMetaItem::Lit(lit) => {
|
||||
.filter_map(|meta_item_inner| match meta_item_inner {
|
||||
MetaItemInner::MetaItem(meta) => Some(meta),
|
||||
MetaItemInner::Lit(lit) => {
|
||||
// Reject `#[derive("Debug")]`.
|
||||
report_unexpected_meta_item_lit(sess, lit);
|
||||
None
|
||||
|
|
|
@ -113,7 +113,7 @@ fn cs_clone_simple(
|
|||
// Already produced an assertion for this type.
|
||||
// Anonymous structs or unions must be eliminated as they cannot be
|
||||
// type parameters.
|
||||
} else if !field.ty.kind.is_anon_adt() {
|
||||
} else {
|
||||
// let _: AssertParamIsClone<FieldTy>;
|
||||
super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[
|
||||
sym::clone,
|
||||
|
|
|
@ -124,8 +124,6 @@ fn assert_ty_bounds(
|
|||
span: Span,
|
||||
assert_path: &[Symbol],
|
||||
) {
|
||||
// Deny anonymous structs or unions to avoid weird errors.
|
||||
assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters");
|
||||
// Generate statement `let _: assert_path<ty>;`.
|
||||
let span = cx.with_def_site_ctxt(span);
|
||||
let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
|
||||
|
|
|
@ -13,6 +13,8 @@ use rustc_span::symbol::{Ident, sym};
|
|||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::errors;
|
||||
|
||||
macro_rules! path {
|
||||
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
|
||||
}
|
||||
|
@ -25,6 +27,8 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
push: &mut dyn FnMut(Annotatable),
|
||||
_is_const: bool,
|
||||
) {
|
||||
item.visit_with(&mut DetectNonGenericPointeeAttr { cx });
|
||||
|
||||
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
|
||||
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
|
||||
{
|
||||
|
@ -308,7 +312,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
impl_generics.params.insert(pointee_param_idx + 1, extra_param);
|
||||
|
||||
// Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`.
|
||||
let gen_args = vec![GenericArg::Type(alt_self_type.clone())];
|
||||
let gen_args = vec![GenericArg::Type(alt_self_type)];
|
||||
add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone());
|
||||
add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args);
|
||||
}
|
||||
|
@ -396,3 +400,63 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DetectNonGenericPointeeAttr<'a, 'b> {
|
||||
cx: &'a ExtCtxt<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
|
||||
if attr.has_name(sym::pointee) {
|
||||
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'a rustc_ast::GenericParam) -> Self::Result {
|
||||
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
|
||||
|
||||
match ¶m.kind {
|
||||
GenericParamKind::Type { default } => {
|
||||
// The `default` may end up containing a block expression.
|
||||
// The problem is block expressions may define structs with generics.
|
||||
// A user may attach a #[pointee] attribute to one of these generics
|
||||
// We want to catch that. The simple solution is to just
|
||||
// always raise a `NonGenericPointee` error when this happens.
|
||||
//
|
||||
// This solution does reject valid rust programs but,
|
||||
// such a code would have to, in order:
|
||||
// - Define a smart pointer struct.
|
||||
// - Somewhere in this struct definition use a type with a const generic argument.
|
||||
// - Calculate this const generic in a expression block.
|
||||
// - Define a new smart pointer type in this block.
|
||||
// - Have this smart pointer type have more than 1 generic type.
|
||||
// In this case, the inner smart pointer derive would be complaining that it
|
||||
// needs a pointer attribute. Meanwhile, the outer macro would be complaining
|
||||
// that we attached a #[pointee] to a generic type argument while helpfully
|
||||
// informing the user that #[pointee] can only be attached to generic pointer arguments
|
||||
rustc_ast::visit::visit_opt!(error_on_pointee, visit_ty, default);
|
||||
}
|
||||
|
||||
GenericParamKind::Const { .. } | GenericParamKind::Lifetime => {
|
||||
rustc_ast::visit::walk_generic_param(&mut error_on_pointee, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &'a rustc_ast::Ty) -> Self::Result {
|
||||
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
|
||||
error_on_pointee.visit_ty(t)
|
||||
}
|
||||
}
|
||||
|
||||
struct AlwaysErrorOnGenericParam<'a, 'b> {
|
||||
cx: &'a ExtCtxt<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
|
||||
if attr.has_name(sym::pointee) {
|
||||
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -751,7 +751,7 @@ pub(crate) struct AsmExpectedOther {
|
|||
#[primary_span]
|
||||
#[label(builtin_macros_asm_expected_other)]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) is_global_asm: bool,
|
||||
pub(crate) is_inline_asm: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -799,13 +799,6 @@ pub(crate) struct AsmMayUnwind {
|
|||
pub(crate) labels_sp: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_global_asm_clobber_abi)]
|
||||
pub(crate) struct GlobalAsmClobberAbi {
|
||||
#[primary_span]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
}
|
||||
|
||||
pub(crate) struct AsmClobberNoReg {
|
||||
pub(crate) spans: Vec<Span>,
|
||||
pub(crate) clobbers: Vec<Span>,
|
||||
|
@ -841,23 +834,33 @@ pub(crate) struct AsmOptAlreadyprovided {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_global_asm_unsupported_option)]
|
||||
pub(crate) struct GlobalAsmUnsupportedOption {
|
||||
#[diag(builtin_macros_asm_unsupported_option)]
|
||||
pub(crate) struct AsmUnsupportedOption {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) symbol: Symbol,
|
||||
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
|
||||
pub(crate) full_span: Span,
|
||||
pub(crate) macro_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_global_asm_unsupported_operand)]
|
||||
pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
|
||||
#[diag(builtin_macros_asm_unsupported_operand)]
|
||||
pub(crate) struct AsmUnsupportedOperand<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) symbol: &'a str,
|
||||
pub(crate) macro_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_asm_unsupported_clobber_abi)]
|
||||
pub(crate) struct AsmUnsupportedClobberAbi {
|
||||
#[primary_span]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
pub(crate) macro_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -937,3 +940,10 @@ pub(crate) struct NakedFunctionTestingAttribute {
|
|||
#[label]
|
||||
pub testing_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_generic_pointee)]
|
||||
pub(crate) struct NonGenericPointee {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
@ -726,6 +726,12 @@ pub macro global_asm() {
|
|||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
pub macro naked_asm() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
pub static A_STATIC: u8 = 42;
|
||||
|
||||
#[lang = "panic_location"]
|
||||
|
|
|
@ -390,7 +390,7 @@ global_asm! {
|
|||
#[naked]
|
||||
extern "C" fn naked_test() {
|
||||
unsafe {
|
||||
asm!("ret", options(noreturn));
|
||||
naked_asm!("ret");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ fn main() {
|
|||
|
||||
foo(I64X2([0, 0]));
|
||||
|
||||
transmute_fat_pointer();
|
||||
transmute_wide_pointer();
|
||||
|
||||
rust_call_abi();
|
||||
|
||||
|
@ -192,7 +192,7 @@ type TwoPtrs = i64;
|
|||
#[cfg(target_pointer_width = "64")]
|
||||
type TwoPtrs = i128;
|
||||
|
||||
fn transmute_fat_pointer() -> TwoPtrs {
|
||||
fn transmute_wide_pointer() -> TwoPtrs {
|
||||
unsafe { transmute::<_, TwoPtrs>("true !") }
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use rustc_ast::InlineAsmOptions;
|
|||
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::InlineAsmMacro;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
|
@ -57,6 +58,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
|
||||
match &mir.basic_blocks[START_BLOCK].terminator().kind {
|
||||
TerminatorKind::InlineAsm {
|
||||
asm_macro: InlineAsmMacro::NakedAsm,
|
||||
template,
|
||||
operands,
|
||||
options,
|
||||
|
@ -498,6 +500,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
"tail calls are not yet supported in `rustc_codegen_cranelift` backend"
|
||||
),
|
||||
TerminatorKind::InlineAsm {
|
||||
asm_macro: _,
|
||||
template,
|
||||
operands,
|
||||
options,
|
||||
|
@ -713,17 +716,17 @@ fn codegen_stmt<'tcx>(
|
|||
let from_ty = operand.layout().ty;
|
||||
let to_ty = fx.monomorphize(to_ty);
|
||||
|
||||
fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
ty.builtin_deref(true)
|
||||
.is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty))
|
||||
}
|
||||
|
||||
if is_fat_ptr(fx, from_ty) {
|
||||
if is_fat_ptr(fx, to_ty) {
|
||||
// fat-ptr -> fat-ptr
|
||||
if is_wide_ptr(fx, from_ty) {
|
||||
if is_wide_ptr(fx, to_ty) {
|
||||
// wide-ptr -> wide-ptr
|
||||
lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
|
||||
} else {
|
||||
// fat-ptr -> thin-ptr
|
||||
// wide-ptr -> thin-ptr
|
||||
let (ptr, _extra) = operand.load_scalar_pair(fx);
|
||||
lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ fn clif_pair_type_from_ty<'tcx>(
|
|||
})
|
||||
}
|
||||
|
||||
/// Is a pointer to this type a fat ptr?
|
||||
/// Is a pointer to this type a wide ptr?
|
||||
pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
if ty.is_sized(tcx, ParamEnv::reveal_all()) {
|
||||
return false;
|
||||
|
|
|
@ -139,7 +139,7 @@ impl DebugContext {
|
|||
|
||||
pointer_type_id
|
||||
} else {
|
||||
// FIXME implement debuginfo for fat pointers
|
||||
// FIXME implement debuginfo for wide pointers
|
||||
self.placeholder_for_type(tcx, type_dbg, ptr_type)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
//! Adapted from <https://github.com/rust-lang/rust/blob/31c0645b9d2539f47eecb096142474b29dc542f7/compiler/rustc_codegen_ssa/src/mir/place.rs>
|
||||
//! (<https://github.com/rust-lang/rust/pull/104535>)
|
||||
|
||||
use rustc_target::abi::{Int, TagEncoding, Variants};
|
||||
use rustc_abi::Primitive::Int;
|
||||
use rustc_abi::{TagEncoding, Variants};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
|
|
|
@ -328,6 +328,9 @@ fn codegen_float_intrinsic_call<'tcx>(
|
|||
sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64),
|
||||
sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32),
|
||||
sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64),
|
||||
// FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation
|
||||
sym::fmuladdf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f32
|
||||
sym::fmuladdf64 => ("fma", 3, fx.tcx.types.f64, types::F64), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f64
|
||||
sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32),
|
||||
sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64),
|
||||
sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32),
|
||||
|
@ -381,7 +384,7 @@ fn codegen_float_intrinsic_call<'tcx>(
|
|||
|
||||
let layout = fx.layout_of(ty);
|
||||
let res = match intrinsic {
|
||||
sym::fmaf32 | sym::fmaf64 => {
|
||||
sym::fmaf32 | sym::fmaf64 | sym::fmuladdf32 | sym::fmuladdf64 => {
|
||||
CValue::by_val(fx.bcx.ins().fma(args[0], args[1], args[2]), layout)
|
||||
}
|
||||
sym::copysignf32 | sym::copysignf64 => {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
extern crate jobserver;
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
extern crate rustc_abi;
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_codegen_ssa;
|
||||
extern crate rustc_data_structures;
|
||||
|
|
|
@ -8,9 +8,6 @@ codegen_gcc_invalid_minimum_alignment =
|
|||
codegen_gcc_lto_not_supported =
|
||||
LTO is not supported. You may get a linker error.
|
||||
|
||||
codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together
|
||||
.help = add the missing features in a `target_feature` attribute
|
||||
|
||||
codegen_gcc_unwinding_inline_asm =
|
||||
GCC backend does not support unwinding from inline asm
|
||||
|
||||
|
|
|
@ -7,11 +7,9 @@ use rustc_attr::InstructionSetAttr;
|
|||
#[cfg(feature = "master")]
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::context::CodegenCx;
|
||||
use crate::errors::TiedTargetFeatures;
|
||||
use crate::gcc_util::{check_tied_features, to_gcc_features};
|
||||
use crate::gcc_util::to_gcc_features;
|
||||
|
||||
/// Get GCC attribute for the provided inline heuristic.
|
||||
#[cfg(feature = "master")]
|
||||
|
@ -72,26 +70,10 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let function_features = codegen_fn_attrs
|
||||
let mut function_features = codegen_fn_attrs
|
||||
.target_features
|
||||
.iter()
|
||||
.map(|features| features.name.as_str())
|
||||
.collect::<Vec<&str>>();
|
||||
|
||||
if let Some(features) = check_tied_features(
|
||||
cx.tcx.sess,
|
||||
&function_features.iter().map(|features| (*features, true)).collect(),
|
||||
) {
|
||||
let span = cx
|
||||
.tcx
|
||||
.get_attr(instance.def_id(), sym::target_feature)
|
||||
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
|
||||
cx.tcx.dcx().create_err(TiedTargetFeatures { features: features.join(", "), span }).emit();
|
||||
return;
|
||||
}
|
||||
|
||||
let mut function_features = function_features
|
||||
.iter()
|
||||
.flat_map(|feat| to_gcc_features(cx.tcx.sess, feat).into_iter())
|
||||
.chain(codegen_fn_attrs.instruction_set.iter().map(|x| match *x {
|
||||
InstructionSetAttr::ArmA32 => "-thumb-mode", // TODO(antoyo): support removing feature.
|
||||
|
|
|
@ -7,6 +7,8 @@ use gccjit::{
|
|||
BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type,
|
||||
UnaryOp,
|
||||
};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout, WrappingRange};
|
||||
use rustc_apfloat::{Float, Round, Status, ieee};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
use rustc_codegen_ssa::common::{
|
||||
|
@ -28,7 +30,6 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange};
|
||||
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
|
||||
|
||||
use crate::common::{SignType, TypeReflection, type_is_pointer};
|
||||
|
@ -998,12 +999,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
) {
|
||||
let vr = scalar.valid_range(bx);
|
||||
match scalar.primitive() {
|
||||
abi::Int(..) => {
|
||||
abi::Primitive::Int(..) => {
|
||||
if !scalar.is_always_valid(bx) {
|
||||
bx.range_metadata(load, vr);
|
||||
}
|
||||
}
|
||||
abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
|
||||
abi::Primitive::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
|
||||
bx.nonnull_metadata(load);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use gccjit::{LValue, RValue, ToRValue, Type};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::HasDataLayout;
|
||||
use rustc_abi::Primitive::Pointer;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
|
||||
};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_target::abi::{self, HasDataLayout, Pointer};
|
||||
|
||||
use crate::consts::const_alloc_to_gcc;
|
||||
use crate::context::CodegenCx;
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
|
||||
#[note]
|
||||
|
@ -45,15 +42,6 @@ pub(crate) struct InvalidMinimumAlignment {
|
|||
pub err: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_tied_target_features)]
|
||||
#[help]
|
||||
pub(crate) struct TiedTargetFeatures {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub features: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_copy_bitcode)]
|
||||
pub(crate) struct CopyBitcode {
|
||||
|
@ -78,27 +66,3 @@ pub(crate) struct LtoDylib;
|
|||
pub(crate) struct LtoBitcodeFromRlib {
|
||||
pub gcc_err: String,
|
||||
}
|
||||
|
||||
pub(crate) struct TargetFeatureDisableOrEnable<'a> {
|
||||
pub features: &'a [&'a str],
|
||||
pub span: Option<Span>,
|
||||
pub missing_features: Option<MissingFeatures>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(codegen_gcc_missing_features)]
|
||||
pub(crate) struct MissingFeatures;
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
||||
let mut diag = Diag::new(dcx, level, fluent::codegen_gcc_target_feature_disable_or_enable);
|
||||
if let Some(span) = self.span {
|
||||
diag.span(span);
|
||||
};
|
||||
if let Some(missing_features) = self.missing_features {
|
||||
diag.subdiagnostic(missing_features);
|
||||
}
|
||||
diag.arg("features", self.features.join(", "));
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
#[cfg(feature = "master")]
|
||||
use gccjit::Context;
|
||||
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
|
||||
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::errors::{
|
||||
PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
|
||||
UnknownCTargetFeaturePrefix,
|
||||
};
|
||||
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
|
||||
|
||||
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
|
@ -185,23 +184,6 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
|
|||
}
|
||||
}
|
||||
|
||||
// Given a map from target_features to whether they are enabled or disabled,
|
||||
// ensure only valid combinations are allowed.
|
||||
pub fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
) -> Option<&'static [&'static str]> {
|
||||
for tied in sess.target.tied_target_features() {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
let enabled = features.get(tied_iter.next().unwrap());
|
||||
if tied_iter.any(|feature| enabled != features.get(feature)) {
|
||||
return Some(tied);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn arch_to_gcc(name: &str) -> &str {
|
||||
match name {
|
||||
"M68020" => "68020",
|
||||
|
|
|
@ -66,6 +66,9 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
|
|||
sym::log2f64 => "log2",
|
||||
sym::fmaf32 => "fmaf",
|
||||
sym::fmaf64 => "fma",
|
||||
// FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation
|
||||
sym::fmuladdf32 => "fmaf", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f32
|
||||
sym::fmuladdf64 => "fma", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f64
|
||||
sym::fabsf32 => "fabsf",
|
||||
sym::fabsf64 => "fabs",
|
||||
sym::minnumf32 => "fminf",
|
||||
|
|
|
@ -478,7 +478,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
|
||||
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
|
||||
});
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
|
||||
span,
|
||||
name,
|
||||
ty: in_elem
|
||||
|
@ -493,7 +493,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
|
||||
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
|
||||
});
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
|
||||
span,
|
||||
name,
|
||||
ty: out_elem
|
||||
|
|
|
@ -32,6 +32,7 @@ extern crate tempfile;
|
|||
extern crate tracing;
|
||||
|
||||
// The rustc crates we need
|
||||
extern crate rustc_abi;
|
||||
extern crate rustc_apfloat;
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_attr;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use gccjit::{Struct, Type};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::Primitive::*;
|
||||
use rustc_abi::{Abi, FieldsShape, Integer, PointeeInfo, Size, Variants};
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods,
|
||||
};
|
||||
|
@ -8,11 +11,8 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
|
||||
use rustc_target::abi::TyAbiInterface;
|
||||
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
|
||||
use rustc_target::abi::{
|
||||
self, Abi, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
|
||||
Variants,
|
||||
};
|
||||
|
||||
use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
|
||||
use crate::context::CodegenCx;
|
||||
|
@ -207,7 +207,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
// layout.
|
||||
if let Abi::Scalar(ref scalar) = self.abi {
|
||||
// Use a different cache for scalars because pointers to DSTs
|
||||
// can be either fat or thin (data pointers of fat pointers).
|
||||
// can be either wide or thin (data pointers of wide pointers).
|
||||
if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
|
||||
return ty;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ libc = "0.2"
|
|||
measureme = "11"
|
||||
object = { version = "0.36.3", default-features = false, features = ["std", "read"] }
|
||||
rustc-demangle = "0.1.21"
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
|
||||
|
|
|
@ -33,9 +33,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_missing_features =
|
||||
add the missing features in a `target_feature` attribute
|
||||
|
||||
codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found
|
||||
codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
|
||||
|
||||
|
@ -63,9 +60,6 @@ codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}
|
|||
codegen_llvm_symbol_already_defined =
|
||||
symbol `{$symbol_name}` is already defined
|
||||
|
||||
codegen_llvm_target_feature_disable_or_enable =
|
||||
the target features {$features} must all be either enabled or disabled together
|
||||
|
||||
codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
|
||||
codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
use std::cmp;
|
||||
|
||||
use libc::c_uint;
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::Primitive::Int;
|
||||
use rustc_abi::{HasDataLayout, Size};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
||||
use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
|
||||
pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA};
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_session::config;
|
||||
pub(crate) use rustc_target::abi::call::*;
|
||||
use rustc_target::abi::{self, HasDataLayout, Int, Size};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
pub(crate) use rustc_target::spec::abi::Abi;
|
||||
use smallvec::SmallVec;
|
||||
|
|
|
@ -154,7 +154,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
// We prefer the latter because it matches the behavior of
|
||||
// Clang.
|
||||
if late && matches!(reg, InlineAsmRegOrRegClass::Reg(_)) {
|
||||
constraints.push(reg_to_llvm(reg, Some(&in_value.layout)).to_string());
|
||||
constraints.push(reg_to_llvm(reg, Some(&in_value.layout)));
|
||||
} else {
|
||||
constraints.push(format!("{}", op_idx[&idx]));
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::context::CodegenCx;
|
||||
use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable};
|
||||
use crate::errors::SanitizerMemtagRequiresMte;
|
||||
use crate::llvm::AttributePlace::Function;
|
||||
use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
|
||||
use crate::value::Value;
|
||||
|
@ -502,26 +501,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
|||
let function_features =
|
||||
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
|
||||
|
||||
if let Some(f) = llvm_util::check_tied_features(
|
||||
cx.tcx.sess,
|
||||
&function_features.iter().map(|f| (*f, true)).collect(),
|
||||
) {
|
||||
let span = cx
|
||||
.tcx
|
||||
.get_attrs(instance.def_id(), sym::target_feature)
|
||||
.next()
|
||||
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
|
||||
cx.tcx
|
||||
.dcx()
|
||||
.create_err(TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
span: Some(span),
|
||||
missing_features: Some(MissingFeatures),
|
||||
})
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
let function_features = function_features
|
||||
.iter()
|
||||
// Convert to LLVMFeatures and filter out unavailable ones
|
||||
|
|
|
@ -3,6 +3,8 @@ use std::ops::Deref;
|
|||
use std::{iter, ptr};
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::{Align, Size, WrappingRange};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
|
||||
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
||||
|
@ -20,7 +22,6 @@ use rustc_sanitizers::{cfi, kcfi};
|
|||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::abi::{self, Align, Size, WrappingRange};
|
||||
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
|
||||
use smallvec::SmallVec;
|
||||
use tracing::{debug, instrument};
|
||||
|
@ -505,12 +506,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
match scalar.primitive() {
|
||||
abi::Int(..) => {
|
||||
abi::Primitive::Int(..) => {
|
||||
if !scalar.is_always_valid(bx) {
|
||||
bx.range_metadata(load, scalar.valid_range(bx));
|
||||
}
|
||||
}
|
||||
abi::Pointer(_) => {
|
||||
abi::Primitive::Pointer(_) => {
|
||||
if !scalar.valid_range(bx).contains(0) {
|
||||
bx.nonnull_metadata(load);
|
||||
}
|
||||
|
@ -521,7 +522,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
abi::Float(_) => {}
|
||||
abi::Primitive::Float(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1679,16 +1680,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
bitmap_bytes: &'ll Value,
|
||||
bitmap_bits: &'ll Value,
|
||||
) {
|
||||
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes);
|
||||
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits);
|
||||
|
||||
assert!(
|
||||
crate::llvm_util::get_version() >= (19, 0, 0),
|
||||
"MCDC intrinsics require LLVM 19 or later"
|
||||
);
|
||||
|
||||
let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) };
|
||||
let llty = self.cx.type_func(
|
||||
&[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()],
|
||||
self.cx.type_void(),
|
||||
);
|
||||
let args = &[fn_name, hash, bitmap_bytes];
|
||||
let args = &[fn_name, hash, bitmap_bits];
|
||||
let args = self.check_call("call", llty, llfn, args);
|
||||
|
||||
unsafe {
|
||||
|
@ -1708,28 +1714,25 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
bitmap_bytes: &'ll Value,
|
||||
bitmap_index: &'ll Value,
|
||||
mcdc_temp: &'ll Value,
|
||||
) {
|
||||
debug!(
|
||||
"mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})",
|
||||
fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp
|
||||
"mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})",
|
||||
fn_name, hash, bitmap_index, mcdc_temp
|
||||
);
|
||||
assert!(
|
||||
crate::llvm_util::get_version() >= (19, 0, 0),
|
||||
"MCDC intrinsics require LLVM 19 or later"
|
||||
);
|
||||
|
||||
let llfn =
|
||||
unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) };
|
||||
let llty = self.cx.type_func(
|
||||
&[
|
||||
self.cx.type_ptr(),
|
||||
self.cx.type_i64(),
|
||||
self.cx.type_i32(),
|
||||
self.cx.type_i32(),
|
||||
self.cx.type_ptr(),
|
||||
],
|
||||
&[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()],
|
||||
self.cx.type_void(),
|
||||
);
|
||||
let args = &[fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp];
|
||||
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
|
||||
let args = self.check_call("call", llty, llfn, args);
|
||||
unsafe {
|
||||
let _ = llvm::LLVMRustBuildCall(
|
||||
|
@ -1745,41 +1748,15 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
|
||||
}
|
||||
|
||||
pub(crate) fn mcdc_condbitmap_update(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
cond_loc: &'ll Value,
|
||||
mcdc_temp: &'ll Value,
|
||||
bool_value: &'ll Value,
|
||||
) {
|
||||
debug!(
|
||||
"mcdc_condbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})",
|
||||
fn_name, hash, cond_loc, mcdc_temp, bool_value
|
||||
pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) {
|
||||
debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp);
|
||||
assert!(
|
||||
crate::llvm_util::get_version() >= (19, 0, 0),
|
||||
"MCDC intrinsics require LLVM 19 or later"
|
||||
);
|
||||
let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(self.cx().llmod) };
|
||||
let llty = self.cx.type_func(
|
||||
&[
|
||||
self.cx.type_ptr(),
|
||||
self.cx.type_i64(),
|
||||
self.cx.type_i32(),
|
||||
self.cx.type_ptr(),
|
||||
self.cx.type_i1(),
|
||||
],
|
||||
self.cx.type_void(),
|
||||
);
|
||||
let args = &[fn_name, hash, cond_loc, mcdc_temp, bool_value];
|
||||
self.check_call("call", llty, llfn, args);
|
||||
unsafe {
|
||||
let _ = llvm::LLVMRustBuildCall(
|
||||
self.llbuilder,
|
||||
llty,
|
||||
llfn,
|
||||
args.as_ptr() as *const &llvm::Value,
|
||||
args.len() as c_uint,
|
||||
[].as_ptr(),
|
||||
0 as c_uint,
|
||||
);
|
||||
}
|
||||
let align = self.tcx.data_layout.i32_align.abi;
|
||||
let current_tv_index = self.load(self.cx.type_i32(), mcdc_temp, align);
|
||||
let new_tv_index = self.add(current_tv_index, cond_index);
|
||||
self.store(new_tv_index, mcdc_temp, align);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
//! Code that is useful in various codegen modules.
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::Primitive::Pointer;
|
||||
use rustc_abi::{AddressSpace, HasDataLayout};
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_codegen_ssa::common::TypeKind;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
@ -9,7 +13,6 @@ use rustc_middle::bug;
|
|||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::cstore::DllImport;
|
||||
use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::consts::const_alloc_to_llvm;
|
||||
|
@ -144,6 +147,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value {
|
||||
debug_assert!(
|
||||
self.type_kind(t) == TypeKind::Integer,
|
||||
"only allows integer types in const_int"
|
||||
);
|
||||
unsafe { llvm::LLVMConstInt(t, i as u64, True) }
|
||||
}
|
||||
|
||||
|
@ -174,10 +181,18 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
fn const_uint(&self, t: &'ll Type, i: u64) -> &'ll Value {
|
||||
debug_assert!(
|
||||
self.type_kind(t) == TypeKind::Integer,
|
||||
"only allows integer types in const_uint"
|
||||
);
|
||||
unsafe { llvm::LLVMConstInt(t, i, False) }
|
||||
}
|
||||
|
||||
fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value {
|
||||
debug_assert!(
|
||||
self.type_kind(t) == TypeKind::Integer,
|
||||
"only allows integer types in const_uint_big"
|
||||
);
|
||||
unsafe {
|
||||
let words = [u as u64, (u >> 64) as u64];
|
||||
llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr())
|
||||
|
|
|
@ -19,7 +19,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, PAuthKey, PacRet,
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet,
|
||||
};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
@ -378,6 +378,18 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
}
|
||||
}
|
||||
|
||||
match sess.opts.unstable_opts.function_return {
|
||||
FunctionReturn::Keep => {}
|
||||
FunctionReturn::ThunkExtern => unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"function_return_thunk_extern".as_ptr(),
|
||||
1,
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support())
|
||||
{
|
||||
// Set up the small-data optimization limit for architectures that use
|
||||
|
@ -872,6 +884,11 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.fma.f128", fn(t_f128, t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.fmuladd.f16", fn(t_f16, t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.fmuladd.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.fmuladd.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.fmuladd.f128", fn(t_f128, t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.fabs.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
|
||||
|
@ -1175,10 +1192,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
span: Span,
|
||||
fn_abi_request: FnAbiRequest<'tcx>,
|
||||
) -> ! {
|
||||
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
|
||||
self.tcx.dcx().emit_fatal(Spanned { span, node: err })
|
||||
} else {
|
||||
match fn_abi_request {
|
||||
match err {
|
||||
FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => {
|
||||
self.tcx.dcx().emit_fatal(Spanned { span, node: err });
|
||||
}
|
||||
_ => match fn_abi_request {
|
||||
FnAbiRequest::OfFnPtr { sig, extra_args } => {
|
||||
span_bug!(span, "`fn_abi_of_fn_ptr({sig}, {extra_args:?})` failed: {err:?}",);
|
||||
}
|
||||
|
@ -1188,7 +1206,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
"`fn_abi_of_instance({instance}, {extra_args:?})` failed: {err:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ enum RegionKind {
|
|||
}
|
||||
|
||||
mod mcdc {
|
||||
use rustc_middle::mir::coverage::{ConditionInfo, DecisionInfo};
|
||||
use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo};
|
||||
|
||||
/// Must match the layout of `LLVMRustMCDCDecisionParameters`.
|
||||
#[repr(C)]
|
||||
|
@ -167,12 +167,13 @@ mod mcdc {
|
|||
|
||||
impl From<ConditionInfo> for BranchParameters {
|
||||
fn from(value: ConditionInfo) -> Self {
|
||||
let to_llvm_cond_id = |cond_id: Option<ConditionId>| {
|
||||
cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1)
|
||||
};
|
||||
let ConditionInfo { condition_id, true_next_id, false_next_id } = value;
|
||||
Self {
|
||||
condition_id: value.condition_id.as_u32() as LLVMConditionId,
|
||||
condition_ids: [
|
||||
value.false_next_id.as_u32() as LLVMConditionId,
|
||||
value.true_next_id.as_u32() as LLVMConditionId,
|
||||
],
|
||||
condition_id: to_llvm_cond_id(Some(condition_id)),
|
||||
condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,29 +14,20 @@ use crate::coverageinfo::ffi::CounterMappingRegion;
|
|||
use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
|
||||
use crate::{coverageinfo, llvm};
|
||||
|
||||
/// Generates and exports the Coverage Map.
|
||||
/// Generates and exports the coverage map, which is embedded in special
|
||||
/// linker sections in the final binary.
|
||||
///
|
||||
/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
|
||||
/// 6 and 7 (encoded as 5 and 6 respectively), as described at
|
||||
/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/18.0-2024-02-13/llvm/docs/CoverageMappingFormat.rst).
|
||||
/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
|
||||
/// distributed in the `llvm-tools-preview` rustup component.
|
||||
///
|
||||
/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
|
||||
/// the same version. Clang's implementation of Coverage Map generation was referenced when
|
||||
/// implementing this Rust version, and though the format documentation is very explicit and
|
||||
/// detailed, some undocumented details in Clang's implementation (that may or may not be important)
|
||||
/// were also replicated for Rust's Coverage Map.
|
||||
/// Those sections are then read and understood by LLVM's `llvm-cov` tool,
|
||||
/// which is distributed in the `llvm-tools` rustup component.
|
||||
pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||
let tcx = cx.tcx;
|
||||
|
||||
// Ensure that LLVM is using a version of the coverage mapping format that
|
||||
// agrees with our Rust-side code. Expected versions (encoded as n-1) are:
|
||||
// - `CovMapVersion::Version6` (5) used by LLVM 13-17
|
||||
// - `CovMapVersion::Version7` (6) used by LLVM 18
|
||||
// - `CovMapVersion::Version7` (6) used by LLVM 18-19
|
||||
let covmap_version = {
|
||||
let llvm_covmap_version = coverageinfo::mapping_version();
|
||||
let expected_versions = 5..=6;
|
||||
let expected_versions = 6..=6;
|
||||
assert!(
|
||||
expected_versions.contains(&llvm_covmap_version),
|
||||
"Coverage mapping version exposed by `llvm-wrapper` is out of sync; \
|
||||
|
|
|
@ -98,14 +98,14 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
};
|
||||
|
||||
// If there are no MC/DC bitmaps to set up, return immediately.
|
||||
if function_coverage_info.mcdc_bitmap_bytes == 0 {
|
||||
if function_coverage_info.mcdc_bitmap_bits == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let fn_name = self.get_pgo_func_name_var(instance);
|
||||
let hash = self.const_u64(function_coverage_info.function_source_hash);
|
||||
let bitmap_bytes = self.const_u32(function_coverage_info.mcdc_bitmap_bytes);
|
||||
self.mcdc_parameters(fn_name, hash, bitmap_bytes);
|
||||
let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
|
||||
self.mcdc_parameters(fn_name, hash, bitmap_bits);
|
||||
|
||||
// Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps.
|
||||
let mut cond_bitmaps = vec![];
|
||||
|
@ -185,35 +185,28 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
CoverageKind::ExpressionUsed { id } => {
|
||||
func_coverage.mark_expression_id_seen(id);
|
||||
}
|
||||
CoverageKind::CondBitmapUpdate { id, value, decision_depth } => {
|
||||
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
|
||||
drop(coverage_map);
|
||||
assert_ne!(
|
||||
id.as_u32(),
|
||||
0,
|
||||
"ConditionId of evaluated conditions should never be zero"
|
||||
);
|
||||
let cond_bitmap = coverage_context
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
.expect("mcdc cond bitmap should have been allocated for updating");
|
||||
let cond_loc = bx.const_i32(id.as_u32() as i32 - 1);
|
||||
let bool_value = bx.const_bool(value);
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
bx.mcdc_condbitmap_update(fn_name, hash, cond_loc, cond_bitmap, bool_value);
|
||||
let cond_index = bx.const_i32(index as i32);
|
||||
bx.mcdc_condbitmap_update(cond_index, cond_bitmap);
|
||||
}
|
||||
CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
|
||||
drop(coverage_map);
|
||||
let cond_bitmap = coverage_context
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
.expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
|
||||
let bitmap_bytes = function_coverage_info.mcdc_bitmap_bytes;
|
||||
assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range");
|
||||
assert!(
|
||||
bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits,
|
||||
"bitmap index of the decision out of range"
|
||||
);
|
||||
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
let bitmap_bytes = bx.const_u32(bitmap_bytes);
|
||||
let bitmap_index = bx.const_u32(bitmap_idx);
|
||||
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_bytes, bitmap_index, cond_bitmap);
|
||||
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ use super::utils::{
|
|||
};
|
||||
use crate::common::CodegenCx;
|
||||
use crate::debuginfo::metadata::type_map::build_type_with_children;
|
||||
use crate::debuginfo::utils::{FatPtrKind, fat_pointer_kind};
|
||||
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
|
||||
use crate::llvm::debuginfo::{
|
||||
DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
|
||||
DebugNameTableKind,
|
||||
|
@ -161,7 +161,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
unique_type_id: UniqueTypeId<'tcx>,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
// The debuginfo generated by this function is only valid if `ptr_type` is really just
|
||||
// a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
|
||||
// a (wide) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
|
||||
assert_eq!(
|
||||
cx.size_and_align_of(ptr_type),
|
||||
cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
|
||||
|
@ -174,7 +174,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
let data_layout = &cx.tcx.data_layout;
|
||||
let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
|
||||
|
||||
match fat_pointer_kind(cx, pointee_type) {
|
||||
match wide_pointer_kind(cx, pointee_type) {
|
||||
None => {
|
||||
// This is a thin pointer. Create a regular pointer type and give it the correct name.
|
||||
assert_eq!(
|
||||
|
@ -197,7 +197,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
|
||||
DINodeCreationResult { di_node, already_stored_in_typemap: false }
|
||||
}
|
||||
Some(fat_pointer_kind) => {
|
||||
Some(wide_pointer_kind) => {
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
type_map::stub(
|
||||
|
@ -210,7 +210,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
DIFlags::FlagZero,
|
||||
),
|
||||
|cx, owner| {
|
||||
// FIXME: If this fat pointer is a `Box` then we don't want to use its
|
||||
// FIXME: If this wide pointer is a `Box` then we don't want to use its
|
||||
// type layout and instead use the layout of the raw pointer inside
|
||||
// of it.
|
||||
// The proper way to handle this is to not treat Box as a pointer
|
||||
|
@ -227,16 +227,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
};
|
||||
|
||||
let layout = cx.layout_of(layout_type);
|
||||
let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
|
||||
let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
|
||||
let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR);
|
||||
let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA);
|
||||
|
||||
let (addr_field_name, extra_field_name) = match fat_pointer_kind {
|
||||
FatPtrKind::Dyn => ("pointer", "vtable"),
|
||||
FatPtrKind::Slice => ("data_ptr", "length"),
|
||||
let (addr_field_name, extra_field_name) = match wide_pointer_kind {
|
||||
WidePtrKind::Dyn => ("pointer", "vtable"),
|
||||
WidePtrKind::Slice => ("data_ptr", "length"),
|
||||
};
|
||||
|
||||
assert_eq!(abi::FAT_PTR_ADDR, 0);
|
||||
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
||||
assert_eq!(abi::WIDE_PTR_ADDR, 0);
|
||||
assert_eq!(abi::WIDE_PTR_EXTRA, 1);
|
||||
|
||||
// The data pointer type is a regular, thin pointer, regardless of whether this
|
||||
// is a slice or a trait object.
|
||||
|
@ -258,7 +258,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
owner,
|
||||
addr_field_name,
|
||||
(addr_field.size, addr_field.align.abi),
|
||||
layout.fields.offset(abi::FAT_PTR_ADDR),
|
||||
layout.fields.offset(abi::WIDE_PTR_ADDR),
|
||||
DIFlags::FlagZero,
|
||||
data_ptr_type_di_node,
|
||||
),
|
||||
|
@ -267,7 +267,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
owner,
|
||||
extra_field_name,
|
||||
(extra_field.size, extra_field.align.abi),
|
||||
layout.fields.offset(abi::FAT_PTR_EXTRA),
|
||||
layout.fields.offset(abi::WIDE_PTR_EXTRA),
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, extra_field.ty),
|
||||
),
|
||||
|
@ -391,7 +391,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
|
|||
///
|
||||
/// NOTE: We currently emit just emit the debuginfo for the element type here
|
||||
/// (i.e. `T` for slices and `u8` for `str`), so that we end up with
|
||||
/// `*const T` for the `data_ptr` field of the corresponding fat-pointer
|
||||
/// `*const T` for the `data_ptr` field of the corresponding wide-pointer
|
||||
/// debuginfo of `&[T]`.
|
||||
///
|
||||
/// It would be preferable and more accurate if we emitted a DIArray of T
|
||||
|
|
|
@ -49,23 +49,23 @@ pub(crate) fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) enum FatPtrKind {
|
||||
pub(crate) enum WidePtrKind {
|
||||
Slice,
|
||||
Dyn,
|
||||
}
|
||||
|
||||
/// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
|
||||
/// if the second field of the fat pointer is a length or a vtable-pointer.
|
||||
/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
|
||||
/// if the second field of the wide pointer is a length or a vtable-pointer.
|
||||
/// If `pointee_ty` does not require a wide pointer (because it is Sized) then
|
||||
/// the function returns `None`.
|
||||
pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
|
||||
pub(crate) fn wide_pointer_kind<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
) -> Option<FatPtrKind> {
|
||||
) -> Option<WidePtrKind> {
|
||||
let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
|
||||
let layout = cx.layout_of(pointee_tail_ty);
|
||||
trace!(
|
||||
"fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
|
||||
"wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
|
||||
pointee_tail_ty,
|
||||
layout,
|
||||
layout.is_unsized()
|
||||
|
@ -76,8 +76,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
|
|||
}
|
||||
|
||||
match *pointee_tail_ty.kind() {
|
||||
ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
|
||||
ty::Dynamic(..) => Some(FatPtrKind::Dyn),
|
||||
ty::Str | ty::Slice(_) => Some(WidePtrKind::Slice),
|
||||
ty::Dynamic(..) => Some(WidePtrKind::Dyn),
|
||||
ty::Foreign(_) => {
|
||||
// Assert that pointers to foreign types really are thin:
|
||||
assert_eq!(
|
||||
|
@ -90,7 +90,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
|
|||
// For all other pointee types we should already have returned None
|
||||
// at the beginning of the function.
|
||||
panic!(
|
||||
"fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
|
||||
"wide_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,10 +84,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
unnamed: llvm::UnnamedAddr,
|
||||
fn_type: &'ll Type,
|
||||
) -> &'ll Value {
|
||||
// Declare C ABI functions with the visibility used by C by default.
|
||||
let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
|
||||
|
||||
declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
|
||||
// Visibility should always be default for declarations, otherwise the linker may report an
|
||||
// error.
|
||||
declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type)
|
||||
}
|
||||
|
||||
/// Declare an entry Function
|
||||
|
|
|
@ -80,30 +80,6 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TargetFeatureDisableOrEnable<'a> {
|
||||
pub features: &'a [&'a str],
|
||||
pub span: Option<Span>,
|
||||
pub missing_features: Option<MissingFeatures>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(codegen_llvm_missing_features)]
|
||||
pub(crate) struct MissingFeatures;
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
||||
let mut diag = Diag::new(dcx, level, fluent::codegen_llvm_target_feature_disable_or_enable);
|
||||
if let Some(span) = self.span {
|
||||
diag.span(span);
|
||||
};
|
||||
if let Some(missing_features) = self.missing_features {
|
||||
diag.subdiagnostic(missing_features);
|
||||
}
|
||||
diag.arg("features", self.features.join(", "));
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_lto_disallowed)]
|
||||
pub(crate) struct LtoDisallowed;
|
||||
|
|
|
@ -86,6 +86,11 @@ fn get_simple_intrinsic<'ll>(
|
|||
sym::fmaf64 => "llvm.fma.f64",
|
||||
sym::fmaf128 => "llvm.fma.f128",
|
||||
|
||||
sym::fmuladdf16 => "llvm.fmuladd.f16",
|
||||
sym::fmuladdf32 => "llvm.fmuladd.f32",
|
||||
sym::fmuladdf64 => "llvm.fmuladd.f64",
|
||||
sym::fmuladdf128 => "llvm.fmuladd.f128",
|
||||
|
||||
sym::fabsf16 => "llvm.fabs.f16",
|
||||
sym::fabsf32 => "llvm.fabs.f32",
|
||||
sym::fabsf64 => "llvm.fabs.f64",
|
||||
|
@ -2185,7 +2190,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
|
||||
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
|
||||
});
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
|
||||
span,
|
||||
name,
|
||||
ty: in_elem
|
||||
|
@ -2200,7 +2205,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
|
||||
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
|
||||
});
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
|
||||
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
|
||||
span,
|
||||
name,
|
||||
ty: out_elem
|
||||
|
|
|
@ -1614,7 +1614,6 @@ unsafe extern "C" {
|
|||
pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value;
|
||||
pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value;
|
||||
pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value;
|
||||
pub fn LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(M: &Module) -> &Value;
|
||||
|
||||
pub fn LLVMRustBuildCall<'a>(
|
||||
B: &Builder<'a>,
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::{ptr, slice, str};
|
|||
|
||||
use libc::c_int;
|
||||
use rustc_codegen_ssa::base::wants_wasm_eh;
|
||||
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
|
@ -19,8 +20,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU
|
|||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
|
||||
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, UnknownCTargetFeature,
|
||||
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
};
|
||||
use crate::llvm;
|
||||
|
||||
|
@ -247,7 +248,9 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
|||
("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")),
|
||||
("aarch64", "paca") => Some(LLVMFeature::new("pauth")),
|
||||
("aarch64", "pacg") => Some(LLVMFeature::new("pauth")),
|
||||
("aarch64", "sve-b16b16") => Some(LLVMFeature::new("b16b16")),
|
||||
// Before LLVM 20 those two features were packaged together as b16b16
|
||||
("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
|
||||
("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
|
||||
("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")),
|
||||
// Rust ties fp and neon together.
|
||||
("aarch64", "neon") => {
|
||||
|
@ -276,25 +279,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
|||
}
|
||||
}
|
||||
|
||||
/// Given a map from target_features to whether they are enabled or disabled,
|
||||
/// ensure only valid combinations are allowed.
|
||||
pub(crate) fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
) -> Option<&'static [&'static str]> {
|
||||
if !features.is_empty() {
|
||||
for tied in sess.target.tied_target_features() {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
let enabled = features.get(tied_iter.next().unwrap());
|
||||
if tied_iter.any(|f| enabled != features.get(f)) {
|
||||
return Some(tied);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Used to generate cfg variables and apply features
|
||||
/// Must express features in the way Rust understands them
|
||||
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
|
@ -685,7 +669,7 @@ pub(crate) fn global_llvm_features(
|
|||
features.extend(feats);
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
|
||||
sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
span: None,
|
||||
missing_features: None,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use rustc_abi::Primitive::{Float, Int, Pointer};
|
||||
use rustc_abi::{Abi, Align, FieldsShape, Scalar, Size, Variants};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
|
||||
use rustc_target::abi::{Abi, Align, FieldsShape, Float, Int, Pointer, Scalar, Size, Variants};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::common::*;
|
||||
|
@ -199,7 +200,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
|||
// layout.
|
||||
if let Abi::Scalar(scalar) = self.abi {
|
||||
// Use a different cache for scalars because pointers to DSTs
|
||||
// can be either fat or thin (data pointers of fat pointers).
|
||||
// can be either wide or thin (data pointers of wide pointers).
|
||||
if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) {
|
||||
return llty;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ itertools = "0.12"
|
|||
jobserver = "0.1.28"
|
||||
pathdiff = "0.2.0"
|
||||
regex = "1.4"
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -82,7 +82,7 @@ codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphizati
|
|||
|
||||
codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
|
||||
codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
|
||||
|
||||
|
@ -183,6 +183,8 @@ codegen_ssa_metadata_object_file_write = error writing metadata object file: {$e
|
|||
|
||||
codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
|
||||
|
||||
codegen_ssa_missing_features = add the missing features in a `target_feature` attribute
|
||||
|
||||
codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
|
||||
|
||||
codegen_ssa_missing_query_depgraph =
|
||||
|
@ -238,6 +240,9 @@ codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` fa
|
|||
|
||||
codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
|
||||
|
||||
codegen_ssa_target_feature_disable_or_enable =
|
||||
the target features {$features} must all be either enabled or disabled together
|
||||
|
||||
codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
|
||||
.label = cannot be applied to safe trait method
|
||||
.label_def = not an `unsafe` function
|
||||
|
|
|
@ -1087,7 +1087,9 @@ fn link_natively(
|
|||
let strip = sess.opts.cg.strip;
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
let stripcmd = "/usr/bin/strip";
|
||||
// Use system `strip` when running on host macOS.
|
||||
// <https://github.com/rust-lang/rust/pull/130781>
|
||||
let stripcmd = if cfg!(target_os = "macos") { "/usr/bin/strip" } else { "strip" };
|
||||
match (strip, crate_type) {
|
||||
(Strip::Debuginfo, _) => {
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S"))
|
||||
|
|
|
@ -404,12 +404,14 @@ impl<'a> GccLinker<'a> {
|
|||
fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if self.sess.target.is_like_osx {
|
||||
if !self.is_ld {
|
||||
if self.is_cc() {
|
||||
// `-dynamiclib` makes `cc` pass `-dylib` to the linker.
|
||||
self.cc_arg("-dynamiclib");
|
||||
} else {
|
||||
self.link_arg("-dylib");
|
||||
// Clang also sets `-dynamic`, but that's implied by `-dylib`, so unnecessary.
|
||||
}
|
||||
|
||||
self.link_arg("-dylib");
|
||||
|
||||
// Note that the `osx_rpath_install_name` option here is a hack
|
||||
// purely to support bootstrap right now, we should get a more
|
||||
// principled solution at some point to force the compiler to pass
|
||||
|
|
|
@ -11,7 +11,6 @@ use rustc_ast::attr;
|
|||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::emitter::Emitter;
|
||||
use rustc_errors::translation::Translate;
|
||||
use rustc_errors::{
|
||||
|
@ -1889,7 +1888,7 @@ impl SharedEmitter {
|
|||
}
|
||||
|
||||
impl Translate for SharedEmitter {
|
||||
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
|
||||
fn fluent_bundle(&self) -> Option<&FluentBundle> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -1924,7 +1923,7 @@ impl Emitter for SharedEmitter {
|
|||
);
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
|
||||
fn source_map(&self) -> Option<&SourceMap> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -2165,8 +2164,14 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
|
|||
&& tcx.sess.opts.cg.prefer_dynamic)
|
||||
);
|
||||
|
||||
// We need to generate _imp__ symbol if we are generating an rlib or we include one
|
||||
// indirectly from ThinLTO. In theory these are not needed as ThinLTO could resolve
|
||||
// these, but it currently does not do so.
|
||||
let can_have_static_objects =
|
||||
tcx.sess.lto() == Lto::Thin || tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib);
|
||||
|
||||
tcx.sess.target.is_like_windows &&
|
||||
tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
|
||||
can_have_static_objects &&
|
||||
// ThinLTO can't handle this workaround in all cases, so we don't
|
||||
// emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
|
||||
// dynamic linking when linker plugin LTO is enabled.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_ast::{MetaItemKind, NestedMetaItem, ast, attr};
|
||||
use rustc_ast::{MetaItemInner, MetaItemKind, ast, attr};
|
||||
use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
|
@ -13,13 +14,13 @@ use rustc_middle::middle::codegen_fn_attrs::{
|
|||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self as ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{Session, lint};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_target::spec::{SanitizerSet, abi};
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::{self, MissingFeatures, TargetFeatureDisableOrEnable};
|
||||
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature};
|
||||
|
||||
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
|
||||
|
@ -357,7 +358,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
sym::instruction_set => {
|
||||
codegen_fn_attrs.instruction_set =
|
||||
attr.meta_item_list().and_then(|l| match &l[..] {
|
||||
[NestedMetaItem::MetaItem(set)] => {
|
||||
[MetaItemInner::MetaItem(set)] => {
|
||||
let segments =
|
||||
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match segments.as_slice() {
|
||||
|
@ -662,9 +663,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(features) = check_tied_features(
|
||||
tcx.sess,
|
||||
&codegen_fn_attrs
|
||||
.target_features
|
||||
.iter()
|
||||
.map(|features| (features.name.as_str(), true))
|
||||
.collect(),
|
||||
) {
|
||||
let span = tcx
|
||||
.get_attrs(did, sym::target_feature)
|
||||
.next()
|
||||
.map_or_else(|| tcx.def_span(did), |a| a.span);
|
||||
tcx.dcx()
|
||||
.create_err(TargetFeatureDisableOrEnable {
|
||||
features,
|
||||
span: Some(span),
|
||||
missing_features: Some(MissingFeatures),
|
||||
})
|
||||
.emit();
|
||||
}
|
||||
|
||||
codegen_fn_attrs
|
||||
}
|
||||
|
||||
/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
|
||||
/// combinations are allowed.
|
||||
pub fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
) -> Option<&'static [&'static str]> {
|
||||
if !features.is_empty() {
|
||||
for tied in sess.target.tied_target_features() {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
let enabled = features.get(tied_iter.next().unwrap());
|
||||
if tied_iter.any(|f| enabled != features.get(f)) {
|
||||
return Some(tied);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
|
||||
/// applied to the method prototype.
|
||||
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_errors::codes::*;
|
|||
use rustc_errors::{
|
||||
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
|
||||
};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::LayoutError;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
@ -916,8 +916,8 @@ pub enum InvalidMonomorphization<'tcx> {
|
|||
ret_ty: Ty<'tcx>,
|
||||
},
|
||||
|
||||
#[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)]
|
||||
CastFatPointer {
|
||||
#[diag(codegen_ssa_invalid_monomorphization_cast_wide_pointer, code = E0511)]
|
||||
CastWidePointer {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
|
@ -1068,3 +1068,27 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
|
|||
pub lib_name: &'a str,
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
pub struct TargetFeatureDisableOrEnable<'a> {
|
||||
pub features: &'a [&'a str],
|
||||
pub span: Option<Span>,
|
||||
pub missing_features: Option<MissingFeatures>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(codegen_ssa_missing_features)]
|
||||
pub struct MissingFeatures;
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
||||
let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable);
|
||||
if let Some(span) = self.span {
|
||||
diag.span(span);
|
||||
};
|
||||
if let Some(missing_features) = self.missing_features {
|
||||
diag.subdiagnostic(missing_features);
|
||||
}
|
||||
diag.arg("features", self.features.join(", "));
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ pub struct NativeLib {
|
|||
pub kind: NativeLibKind,
|
||||
pub name: Symbol,
|
||||
pub filename: Option<Symbol>,
|
||||
pub cfg: Option<ast::MetaItem>,
|
||||
pub cfg: Option<ast::MetaItemInner>,
|
||||
pub verbatim: bool,
|
||||
pub dll_imports: Vec<cstore::DllImport>,
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ use std::cmp;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason};
|
||||
use rustc_middle::mir::{
|
||||
self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason,
|
||||
};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
|
@ -1133,6 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
&mut self,
|
||||
helper: TerminatorCodegenHelper<'tcx>,
|
||||
bx: &mut Bx,
|
||||
asm_macro: InlineAsmMacro,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
template: &[ast::InlineAsmTemplatePiece],
|
||||
operands: &[mir::InlineAsmOperand<'tcx>],
|
||||
|
@ -1203,11 +1206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
&operands,
|
||||
options,
|
||||
line_spans,
|
||||
if options.contains(InlineAsmOptions::NORETURN) {
|
||||
None
|
||||
} else {
|
||||
targets.get(0).copied()
|
||||
},
|
||||
if asm_macro.diverges(options) { None } else { targets.get(0).copied() },
|
||||
unwind,
|
||||
instance,
|
||||
mergeable_succ,
|
||||
|
@ -1381,6 +1380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
mir::TerminatorKind::InlineAsm {
|
||||
asm_macro,
|
||||
template,
|
||||
ref operands,
|
||||
options,
|
||||
|
@ -1390,6 +1390,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
} => self.codegen_asm_terminator(
|
||||
helper,
|
||||
bx,
|
||||
asm_macro,
|
||||
terminator,
|
||||
template,
|
||||
operands,
|
||||
|
|
|
@ -133,9 +133,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
enum LocalRef<'tcx, V> {
|
||||
Place(PlaceRef<'tcx, V>),
|
||||
/// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place).
|
||||
/// `*p` is the fat pointer that references the actual unsized place.
|
||||
/// `*p` is the wide pointer that references the actual unsized place.
|
||||
/// Every time it is initialized, we have to reallocate the place
|
||||
/// and update the fat pointer. That's the reason why it is indirect.
|
||||
/// and update the wide pointer. That's the reason why it is indirect.
|
||||
UnsizedPlace(PlaceRef<'tcx, V>),
|
||||
/// The backend [`OperandValue`] has already been generated.
|
||||
Operand(OperandRef<'tcx, V>),
|
||||
|
@ -429,7 +429,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// Unsized indirect qrguments
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
// As the storage for the indirect argument lives during
|
||||
// the whole function call, we just copy the fat pointer.
|
||||
// the whole function call, we just copy the wide pointer.
|
||||
let llarg = bx.get_param(llarg_idx);
|
||||
llarg_idx += 1;
|
||||
let llextra = bx.get_param(llarg_idx);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue