New upstream version 1.55.0+dfsg1

This commit is contained in:
Ximin Luo 2021-10-08 13:53:48 +01:00
parent 17df50a58d
commit 136023e0d2
3897 changed files with 86672 additions and 54539 deletions

540
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -34,11 +34,13 @@ members = [
"src/tools/unicode-table-generator", "src/tools/unicode-table-generator",
"src/tools/expand-yaml-anchors", "src/tools/expand-yaml-anchors",
"src/tools/jsondocck", "src/tools/jsondocck",
"src/tools/html-checker",
] ]
exclude = [ exclude = [
"build", "build",
"compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_cranelift",
"src/test/rustdoc-gui",
# HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`. # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
"obj", "obj",
# The `x` binary is a thin wrapper that calls `x.py`, which initializes # The `x` binary is a thin wrapper that calls `x.py`, which initializes

View File

@ -21,7 +21,7 @@ Read ["Installation"] from [The Book].
The Rust build system uses a Python script called `x.py` to build the compiler, The Rust build system uses a Python script called `x.py` to build the compiler,
which manages the bootstrapping process. It lives in the root of the project. which manages the bootstrapping process. It lives in the root of the project.
The `x.py` command can be run directly on most systems in the following format: The `x.py` command can be run directly on most systems in the following format:
```sh ```sh
./x.py <subcommand> [flags] ./x.py <subcommand> [flags]
@ -272,15 +272,14 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and
## Trademark ## Trademark
The Rust programming language is an open source, community project governed [The Rust Foundation][rust-foundation] owns and protects the Rust and Cargo
by a core team. It is also sponsored by the Mozilla Foundation (“Mozilla”), trademarks and logos (the “Rust Trademarks”).
which owns and protects the Rust and Cargo trademarks and logos
(the “Rust Trademarks”).
If you want to use these names or brands, please read the [media guide][media-guide]. If you want to use these names or brands, please read the [media guide][media-guide].
Third-party logos may be subject to third-party copyrights and trademarks. See Third-party logos may be subject to third-party copyrights and trademarks. See
[Licenses][policies-licenses] for details. [Licenses][policies-licenses] for details.
[rust-foundation]: https://foundation.rust-lang.org/
[media-guide]: https://www.rust-lang.org/policies/media-guide [media-guide]: https://www.rust-lang.org/policies/media-guide
[policies-licenses]: https://www.rust-lang.org/policies/licenses [policies-licenses]: https://www.rust-lang.org/policies/licenses

View File

@ -1,21 +1,150 @@
Version 1.55.0 (2021-09-09)
============================
Language
--------
- [You can now write open "from" range patterns (`X..`), which will start at `X` and
will end at the maximum value of the integer.][83918]
- [You can now explicitly import the prelude of different editions
through `std::prelude` (e.g. `use std::prelude::rust_2021::*;`).][86294]
Compiler
--------
- [Added tier 3\* support for `powerpc64le-unknown-freebsd`.][83572]
\* Refer to Rust's [platform support page][platform-support-doc] for more
information on Rust's tiered platform support.
Libraries
---------
- [Updated std's float parsing to use the Eisel-Lemire algorithm.][86761]
These improvements should in general provide faster string parsing of floats,
no longer reject certain valid floating point values, and reduce
the produced code size for non-stripped artifacts.
- [`string::Drain` now implements `AsRef<str>` and `AsRef<[u8]>`.][86858]
Stabilised APIs
---------------
- [`Bound::cloned`]
- [`Drain::as_str`]
- [`IntoInnerError::into_error`]
- [`IntoInnerError::into_parts`]
- [`MaybeUninit::assume_init_mut`]
- [`MaybeUninit::assume_init_ref`]
- [`MaybeUninit::write`]
- [`array::map`]
- [`ops::ControlFlow`]
- [`x86::_bittest`]
- [`x86::_bittestandcomplement`]
- [`x86::_bittestandreset`]
- [`x86::_bittestandset`]
- [`x86_64::_bittest64`]
- [`x86_64::_bittestandcomplement64`]
- [`x86_64::_bittestandreset64`]
- [`x86_64::_bittestandset64`]
The following previously stable functions are now `const`.
- [`str::from_utf8_unchecked`]
- [`mem::transmute`]
Cargo
-----
- [Cargo will now deduplicate compiler diagnostics to the terminal when invoking
rustc in parallel such as when using `cargo test`.][cargo/9675]
- [The package definition in `cargo metadata` now includes the `"default_run"`
field from the manifest.][cargo/9550]
- [Added `cargo d` as an alias for `cargo doc`.][cargo/9680]
- [Added `{lib}` as formatting option for `cargo tree` to print the `"lib_name"`
of packages.][cargo/9663]
Rustdoc
-------
- [Added "Go to item on exact match" search option.][85876]
- [The "Implementors" section on traits no longer shows redundant
method definitions.][85970]
- [Trait implementations are toggled open by default.][86260] This should make the
implementations more searchable by tools like `CTRL+F` in your browser.
- [Intra-doc links should now correctly resolve associated items (e.g. methods)
through type aliases.][86334]
- [Traits which are marked with `#[doc(hidden)]` will no longer appear in the
"Trait Implementations" section.][86513]
Compatibility Notes
-------------------
- [std functions that return an `io::Error` will no longer use the
`ErrorKind::Other` variant.][85746] This is to better reflect that these
kinds of errors could be categorised [into newer more specific `ErrorKind`
variants][79965], and that they do not represent a user error.
- [Using environment variable names with `process::Command` on Windows now
behaves as expected.][85270] Previously using envionment variables with
`Command` would cause them to be ASCII-uppercased.
- [Rustdoc will now warn on using rustdoc lints that aren't prefixed
with `rustdoc::`][86849]
[86849]: https://github.com/rust-lang/rust/pull/86849
[86513]: https://github.com/rust-lang/rust/pull/86513
[86334]: https://github.com/rust-lang/rust/pull/86334
[86260]: https://github.com/rust-lang/rust/pull/86260
[85970]: https://github.com/rust-lang/rust/pull/85970
[85876]: https://github.com/rust-lang/rust/pull/85876
[83572]: https://github.com/rust-lang/rust/pull/83572
[86294]: https://github.com/rust-lang/rust/pull/86294
[86858]: https://github.com/rust-lang/rust/pull/86858
[86761]: https://github.com/rust-lang/rust/pull/86761
[85769]: https://github.com/rust-lang/rust/pull/85769
[85746]: https://github.com/rust-lang/rust/pull/85746
[85305]: https://github.com/rust-lang/rust/pull/85305
[85270]: https://github.com/rust-lang/rust/pull/85270
[84111]: https://github.com/rust-lang/rust/pull/84111
[83918]: https://github.com/rust-lang/rust/pull/83918
[79965]: https://github.com/rust-lang/rust/pull/79965
[87370]: https://github.com/rust-lang/rust/pull/87370
[87298]: https://github.com/rust-lang/rust/pull/87298
[cargo/9663]: https://github.com/rust-lang/cargo/pull/9663
[cargo/9675]: https://github.com/rust-lang/cargo/pull/9675
[cargo/9550]: https://github.com/rust-lang/cargo/pull/9550
[cargo/9680]: https://github.com/rust-lang/cargo/pull/9680
[cargo/9663]: https://github.com/rust-lang/cargo/pull/9663
[`array::map`]: https://doc.rust-lang.org/stable/std/primitive.array.html#method.map
[`Bound::cloned`]: https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.cloned
[`Drain::as_str`]: https://doc.rust-lang.org/stable/std/string/struct.Drain.html#method.as_str
[`IntoInnerError::into_error`]: https://doc.rust-lang.org/stable/std/io/struct.IntoInnerError.html#method.into_error
[`IntoInnerError::into_parts`]: https://doc.rust-lang.org/stable/std/io/struct.IntoInnerError.html#method.into_parts
[`MaybeUninit::assume_init_mut`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_mut
[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref
[`MaybeUninit::write`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.write
[`Seek::rewind`]: https://doc.rust-lang.org/stable/std/io/trait.Seek.html#method.rewind
[`mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html
[`ops::ControlFlow`]: https://doc.rust-lang.org/stable/std/ops/enum.ControlFlow.html
[`str::from_utf8_unchecked`]: https://doc.rust-lang.org/stable/std/str/fn.from_utf8_unchecked.html
[`x86::_bittest`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittest.html
[`x86::_bittestandcomplement`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittestandcomplement.html
[`x86::_bittestandreset`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittestandreset.html
[`x86::_bittestandset`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittestandset.html
[`x86_64::_bittest64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittest64.html
[`x86_64::_bittestandcomplement64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittestandcomplement64.html
[`x86_64::_bittestandreset64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittestandreset64.html
[`x86_64::_bittestandset64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittestandset64.html
Version 1.54.0 (2021-07-29) Version 1.54.0 (2021-07-29)
============================ ============================
Language Language
----------------------- -----------------------
- [You can now use macros for values in built-in attribute macros.][83366] - [You can now use macros for values in some built-in attributes.][83366]
While a seemingly minor addition on its own, this enables a lot of This primarily allows you to call macros within the `#[doc]` attribute. For
powerful functionality when combined correctly. Most notably you can example, to include external documentation in your crate, you can now write
now include external documentation in your crate by writing the following. the following:
```rust ```rust
#![doc = include_str!("README.md")] #![doc = include_str!("README.md")]
``` ```
You can also use this to include auto-generated modules:
```rust
#[path = concat!(env!("OUT_DIR"), "/generated.rs")]
mod generated;
```
- [You can now cast between unsized slice types (and types which contain - [You can now cast between unsized slice types (and types which contain
unsized slices) in `const fn`.][85078] unsized slices) in `const fn`.][85078]
@ -37,6 +166,7 @@ Compiler
- [Improved debugger output for enums on Windows MSVC platforms.][85292] - [Improved debugger output for enums on Windows MSVC platforms.][85292]
- [Added tier 3\* support for `bpfel-unknown-none` - [Added tier 3\* support for `bpfel-unknown-none`
and `bpfeb-unknown-none`.][79608] and `bpfeb-unknown-none`.][79608]
- [`-Zmutable-noalias=yes`][82834] is enabled by default when using LLVM 12 or above.
\* Refer to Rust's [platform support page][platform-support-doc] for more \* Refer to Rust's [platform support page][platform-support-doc] for more
information on Rust's tiered platform support. information on Rust's tiered platform support.
@ -106,6 +236,7 @@ Compatibility Notes
[83366]: https://github.com/rust-lang/rust/pull/83366 [83366]: https://github.com/rust-lang/rust/pull/83366
[83278]: https://github.com/rust-lang/rust/pull/83278 [83278]: https://github.com/rust-lang/rust/pull/83278
[85292]: https://github.com/rust-lang/rust/pull/85292 [85292]: https://github.com/rust-lang/rust/pull/85292
[82834]: https://github.com/rust-lang/rust/pull/82834
[cargo/9520]: https://github.com/rust-lang/cargo/pull/9520 [cargo/9520]: https://github.com/rust-lang/cargo/pull/9520
[cargo/9499]: https://github.com/rust-lang/cargo/pull/9499 [cargo/9499]: https://github.com/rust-lang/cargo/pull/9499
[cargo/9488]: https://github.com/rust-lang/cargo/pull/9488 [cargo/9488]: https://github.com/rust-lang/cargo/pull/9488
@ -168,7 +299,7 @@ Libraries
- [`leading_zeros`, and `trailing_zeros` are now available on all - [`leading_zeros`, and `trailing_zeros` are now available on all
`NonZero` integer types.][84082] `NonZero` integer types.][84082]
- [`{f32, f64}::from_str` now parse and print special values - [`{f32, f64}::from_str` now parse and print special values
(`NaN`, `-0`) according to IEEE RFC 754.][78618] (`NaN`, `-0`) according to IEEE 754.][78618]
- [You can now index into slices using `(Bound<usize>, Bound<usize>)`.][77704] - [You can now index into slices using `(Bound<usize>, Bound<usize>)`.][77704]
- [Add the `BITS` associated constant to all numeric types.][82565] - [Add the `BITS` associated constant to all numeric types.][82565]

View File

@ -552,7 +552,7 @@ fn fma() {
assert!(f1.is_negative() && f1.is_zero()); assert!(f1.is_negative() && f1.is_zero());
} }
// Test x87 extended precision case from http://llvm.org/PR20728. // Test x87 extended precision case from https://llvm.org/PR20728.
{ {
let mut m1 = X87DoubleExtended::from_u128(1).value; let mut m1 = X87DoubleExtended::from_u128(1).value;
let m2 = X87DoubleExtended::from_u128(1).value; let m2 = X87DoubleExtended::from_u128(1).value;
@ -1939,7 +1939,7 @@ fn add() {
(m_smallest_normalized, m_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal), (m_smallest_normalized, m_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal),
]; ];
for &(x, y, e_result, e_status, e_category) in &special_cases[..] { for (x, y, e_result, e_status, e_category) in special_cases {
let status; let status;
let result = unpack!(status=, x + y); let result = unpack!(status=, x + y);
assert_eq!(status, e_status); assert_eq!(status, e_status);
@ -2262,7 +2262,7 @@ fn subtract() {
(m_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero), (m_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
]; ];
for &(x, y, e_result, e_status, e_category) in &special_cases[..] { for (x, y, e_result, e_status, e_category) in special_cases {
let status; let status;
let result = unpack!(status=, x - y); let result = unpack!(status=, x - y);
assert_eq!(status, e_status); assert_eq!(status, e_status);
@ -2538,7 +2538,7 @@ fn multiply() {
(m_smallest_normalized, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero), (m_smallest_normalized, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
]; ];
for &(x, y, e_result, e_status, e_category) in &special_cases[..] { for (x, y, e_result, e_status, e_category) in special_cases {
let status; let status;
let result = unpack!(status=, x * y); let result = unpack!(status=, x * y);
assert_eq!(status, e_status); assert_eq!(status, e_status);
@ -2814,7 +2814,7 @@ fn divide() {
(m_smallest_normalized, m_smallest_normalized, "0x1p+0", Status::OK, Category::Normal), (m_smallest_normalized, m_smallest_normalized, "0x1p+0", Status::OK, Category::Normal),
]; ];
for &(x, y, e_result, e_status, e_category) in &special_cases[..] { for (x, y, e_result, e_status, e_category) in special_cases {
let status; let status;
let result = unpack!(status=, x / y); let result = unpack!(status=, x / y);
assert_eq!(status, e_status); assert_eq!(status, e_status);

View File

@ -64,7 +64,7 @@ fn ppc_double_double_add_special() {
(0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven), (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
]; ];
for &(op1, op2, expected, round) in &data { for (op1, op2, expected, round) in data {
{ {
let mut a1 = DoubleDouble::from_bits(op1); let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
@ -135,7 +135,7 @@ fn ppc_double_double_add() {
), ),
]; ];
for &(op1, op2, expected, round) in &data { for (op1, op2, expected, round) in data {
{ {
let mut a1 = DoubleDouble::from_bits(op1); let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
@ -172,7 +172,7 @@ fn ppc_double_double_subtract() {
), ),
]; ];
for &(op1, op2, expected, round) in &data { for (op1, op2, expected, round) in data {
let mut a1 = DoubleDouble::from_bits(op1); let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
a1 = a1.sub_r(a2, round).value; a1 = a1.sub_r(a2, round).value;
@ -204,7 +204,7 @@ fn ppc_double_double_multiply_special() {
(0, 0x3ff0000000000000, Category::Zero, Round::NearestTiesToEven), (0, 0x3ff0000000000000, Category::Zero, Round::NearestTiesToEven),
]; ];
for &(op1, op2, expected, round) in &data { for (op1, op2, expected, round) in data {
{ {
let mut a1 = DoubleDouble::from_bits(op1); let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
@ -290,7 +290,7 @@ fn ppc_double_double_multiply() {
), ),
]; ];
for &(op1, op2, expected, round) in &data { for (op1, op2, expected, round) in data {
{ {
let mut a1 = DoubleDouble::from_bits(op1); let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
@ -322,7 +322,7 @@ fn ppc_double_double_divide() {
), ),
]; ];
for &(op1, op2, expected, round) in &data { for (op1, op2, expected, round) in data {
let mut a1 = DoubleDouble::from_bits(op1); let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
a1 = a1.div_r(a2, round).value; a1 = a1.div_r(a2, round).value;
@ -348,7 +348,7 @@ fn ppc_double_double_remainder() {
), ),
]; ];
for &(op1, op2, expected) in &data { for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1); let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
let result = a1.ieee_rem(a2).value; let result = a1.ieee_rem(a2).value;
@ -376,7 +376,7 @@ fn ppc_double_double_mod() {
), ),
]; ];
for &(op1, op2, expected) in &data { for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1); let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
let r = (a1 % a2).value; let r = (a1 % a2).value;
@ -426,7 +426,7 @@ fn ppc_double_double_compare() {
(0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)), (0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)),
]; ];
for &(op1, op2, expected) in &data { for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1); let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,); assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,);
@ -448,7 +448,7 @@ fn ppc_double_double_bitwise_eq() {
(0x7ff0000000000000, 0x7ff0000000000000, true), (0x7ff0000000000000, 0x7ff0000000000000, true),
]; ];
for &(op1, op2, expected) in &data { for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1); let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2); let a2 = DoubleDouble::from_bits(op2);
assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2); assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);

View File

@ -677,7 +677,9 @@ pub enum BindingMode {
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum RangeEnd { pub enum RangeEnd {
/// `..=` or `...`
Included(RangeSyntax), Included(RangeSyntax),
/// `..`
Excluded, Excluded,
} }
@ -689,6 +691,7 @@ pub enum RangeSyntax {
DotDotEq, DotDotEq,
} }
/// All the different flavors of pattern that Rust recognizes.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum PatKind { pub enum PatKind {
/// Represents a wildcard pattern (`_`). /// Represents a wildcard pattern (`_`).
@ -729,7 +732,7 @@ pub enum PatKind {
/// A literal. /// A literal.
Lit(P<Expr>), Lit(P<Expr>),
/// A range pattern (e.g., `1...2`, `1..=2` or `1..2`). /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>), Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),
/// A slice pattern `[a, b, c]`. /// A slice pattern `[a, b, c]`.
@ -1017,7 +1020,7 @@ pub struct Local {
/// ``` /// ```
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct Arm { pub struct Arm {
pub attrs: Vec<Attribute>, pub attrs: AttrVec,
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }` /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
pub pat: P<Pat>, pub pat: P<Pat>,
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }` /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
@ -1935,6 +1938,7 @@ bitflags::bitflags! {
const NORETURN = 1 << 4; const NORETURN = 1 << 4;
const NOSTACK = 1 << 5; const NOSTACK = 1 << 5;
const ATT_SYNTAX = 1 << 6; const ATT_SYNTAX = 1 << 6;
const RAW = 1 << 7;
} }
} }
@ -2293,7 +2297,7 @@ pub struct EnumDef {
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct Variant { pub struct Variant {
/// Attributes of the variant. /// Attributes of the variant.
pub attrs: Vec<Attribute>, pub attrs: AttrVec,
/// Id of the variant (not the constructor, see `VariantData::ctor_id()`). /// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
pub id: NodeId, pub id: NodeId,
/// Span /// Span
@ -2474,7 +2478,7 @@ impl VisibilityKind {
/// E.g., `bar: usize` as in `struct Foo { bar: usize }`. /// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct FieldDef { pub struct FieldDef {
pub attrs: Vec<Attribute>, pub attrs: AttrVec,
pub id: NodeId, pub id: NodeId,
pub span: Span, pub span: Span,
pub vis: Visibility, pub vis: Visibility,

View File

@ -1,3 +1,4 @@
#[derive(Debug)]
pub enum EntryPointType { pub enum EntryPointType {
None, None,
MainNamed, MainNamed,

View File

@ -1,6 +1,6 @@
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
#[derive(Clone, Copy)] #[derive(Clone, Debug, Copy, HashStable_Generic)]
pub enum AllocatorKind { pub enum AllocatorKind {
Global, Global,
Default, Default,

View File

@ -10,7 +10,6 @@
)] )]
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![cfg_attr(bootstrap, feature(const_fn_unsize))]
#![feature(const_fn_transmute)] #![feature(const_fn_transmute)]
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(iter_zip)] #![feature(iter_zip)]

View File

@ -420,7 +420,7 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> { pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm; let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
visit_attrs(attrs, vis); visit_thin_attrs(attrs, vis);
vis.visit_id(id); vis.visit_id(id);
vis.visit_pat(pat); vis.visit_pat(pat);
visit_opt(guard, |guard| vis.visit_expr(guard)); visit_opt(guard, |guard| vis.visit_expr(guard));
@ -504,7 +504,7 @@ pub fn noop_flat_map_variant<T: MutVisitor>(
let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
visitor.visit_ident(ident); visitor.visit_ident(ident);
visitor.visit_vis(vis); visitor.visit_vis(vis);
visit_attrs(attrs, visitor); visit_thin_attrs(attrs, visitor);
visitor.visit_id(id); visitor.visit_id(id);
visitor.visit_variant_data(data); visitor.visit_variant_data(data);
visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr)); visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
@ -918,7 +918,7 @@ pub fn noop_flat_map_field_def<T: MutVisitor>(
visitor.visit_vis(vis); visitor.visit_vis(vis);
visitor.visit_id(id); visitor.visit_id(id);
visitor.visit_ty(ty); visitor.visit_ty(ty);
visit_attrs(attrs, visitor); visit_thin_attrs(attrs, visitor);
smallvec![fd] smallvec![fd]
} }
@ -1347,12 +1347,6 @@ pub fn noop_visit_expr<T: MutVisitor>(
} }
ExprKind::Paren(expr) => { ExprKind::Paren(expr) => {
vis.visit_expr(expr); vis.visit_expr(expr);
// Nodes that are equal modulo `Paren` sugar no-ops should have the same IDs.
*id = expr.id;
vis.visit_span(span);
visit_thin_attrs(attrs, vis);
return;
} }
ExprKind::Yield(expr) => { ExprKind::Yield(expr) => {
visit_opt(expr, |expr| vis.visit_expr(expr)); visit_opt(expr, |expr| vis.visit_expr(expr));

View File

@ -1,4 +1,4 @@
use rustc_span::ExpnId; use rustc_span::LocalExpnId;
use std::fmt; use std::fmt;
rustc_index::newtype_index! { rustc_index::newtype_index! {
@ -24,12 +24,12 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0);
pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
impl NodeId { impl NodeId {
pub fn placeholder_from_expn_id(expn_id: ExpnId) -> Self { pub fn placeholder_from_expn_id(expn_id: LocalExpnId) -> Self {
NodeId::from_u32(expn_id.as_u32()) NodeId::from_u32(expn_id.as_u32())
} }
pub fn placeholder_to_expn_id(self) -> ExpnId { pub fn placeholder_to_expn_id(self) -> LocalExpnId {
ExpnId::from_u32(self.as_u32()) LocalExpnId::from_u32(self.as_u32())
} }
} }

View File

@ -1,9 +1,9 @@
use super::*; use super::*;
use rustc_span::with_default_session_globals; use rustc_span::create_default_session_globals_then;
#[test] #[test]
fn test_block_doc_comment_1() { fn test_block_doc_comment_1() {
with_default_session_globals(|| { create_default_session_globals_then(|| {
let comment = "\n * Test \n ** Test\n * Test\n"; let comment = "\n * Test \n ** Test\n * Test\n";
let stripped = beautify_doc_string(Symbol::intern(comment)); let stripped = beautify_doc_string(Symbol::intern(comment));
assert_eq!(stripped.as_str(), " Test \n* Test\n Test"); assert_eq!(stripped.as_str(), " Test \n* Test\n Test");
@ -12,7 +12,7 @@ fn test_block_doc_comment_1() {
#[test] #[test]
fn test_block_doc_comment_2() { fn test_block_doc_comment_2() {
with_default_session_globals(|| { create_default_session_globals_then(|| {
let comment = "\n * Test\n * Test\n"; let comment = "\n * Test\n * Test\n";
let stripped = beautify_doc_string(Symbol::intern(comment)); let stripped = beautify_doc_string(Symbol::intern(comment));
assert_eq!(stripped.as_str(), " Test\n Test"); assert_eq!(stripped.as_str(), " Test\n Test");
@ -21,7 +21,7 @@ fn test_block_doc_comment_2() {
#[test] #[test]
fn test_block_doc_comment_3() { fn test_block_doc_comment_3() {
with_default_session_globals(|| { create_default_session_globals_then(|| {
let comment = "\n let a: *i32;\n *a = 5;\n"; let comment = "\n let a: *i32;\n *a = 5;\n";
let stripped = beautify_doc_string(Symbol::intern(comment)); let stripped = beautify_doc_string(Symbol::intern(comment));
assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;"); assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
@ -30,7 +30,7 @@ fn test_block_doc_comment_3() {
#[test] #[test]
fn test_line_doc_comment() { fn test_line_doc_comment() {
with_default_session_globals(|| { create_default_session_globals_then(|| {
let stripped = beautify_doc_string(Symbol::intern(" test")); let stripped = beautify_doc_string(Symbol::intern(" test"));
assert_eq!(stripped.as_str(), " test"); assert_eq!(stripped.as_str(), " test");
let stripped = beautify_doc_string(Symbol::intern("! test")); let stripped = beautify_doc_string(Symbol::intern("! test"));

View File

@ -199,6 +199,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
); );
// Some register classes can only be used as clobbers. This
// means that we disallow passing a value in/out of the asm and
// require that the operand name an explicit register, not a
// register class.
if reg_class.is_clobber_only(asm_arch.unwrap())
&& !(is_clobber && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
{
let msg = format!(
"register class `{}` can only be used as a clobber, \
not as an input or output",
reg_class.name()
);
sess.struct_span_err(op_sp, &msg).emit();
continue;
}
if !is_clobber { if !is_clobber {
// Validate register classes against currently enabled target // Validate register classes against currently enabled target
// features. We check that at least one type is available for // features. We check that at least one type is available for

View File

@ -1067,6 +1067,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
eq_sign_span: Span, eq_sign_span: Span,
assignments: &mut Vec<hir::Stmt<'hir>>, assignments: &mut Vec<hir::Stmt<'hir>>,
) -> &'hir hir::Pat<'hir> { ) -> &'hir hir::Pat<'hir> {
self.arena.alloc(self.destructure_assign_mut(lhs, eq_sign_span, assignments))
}
fn destructure_assign_mut(
&mut self,
lhs: &Expr,
eq_sign_span: Span,
assignments: &mut Vec<hir::Stmt<'hir>>,
) -> hir::Pat<'hir> {
match &lhs.kind { match &lhs.kind {
// Underscore pattern. // Underscore pattern.
ExprKind::Underscore => { ExprKind::Underscore => {
@ -1080,7 +1089,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (before, after) = pats.split_at(i); let (before, after) = pats.split_at(i);
hir::PatKind::Slice( hir::PatKind::Slice(
before, before,
Some(self.pat_without_dbm(span, hir::PatKind::Wild)), Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))),
after, after,
) )
} else { } else {
@ -1165,14 +1174,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
let tuple_pat = hir::PatKind::Tuple(&[], Some(0)); let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
return self.pat_without_dbm(lhs.span, tuple_pat); return self.pat_without_dbm(lhs.span, tuple_pat);
} else { } else {
return self.destructure_assign(e, eq_sign_span, assignments); return self.destructure_assign_mut(e, eq_sign_span, assignments);
} }
} }
_ => {} _ => {}
} }
// Treat all other cases as normal lvalue. // Treat all other cases as normal lvalue.
let ident = Ident::new(sym::lhs, lhs.span); let ident = Ident::new(sym::lhs, lhs.span);
let (pat, binding) = self.pat_ident(lhs.span, ident); let (pat, binding) = self.pat_ident_mut(lhs.span, ident);
let ident = self.expr_ident(lhs.span, ident, binding); let ident = self.expr_ident(lhs.span, ident, binding);
let assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, eq_sign_span); let assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, eq_sign_span);
let expr = self.expr(lhs.span, assign, ThinVec::new()); let expr = self.expr(lhs.span, assign, ThinVec::new());
@ -1191,7 +1200,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ctx: &str, ctx: &str,
eq_sign_span: Span, eq_sign_span: Span,
assignments: &mut Vec<hir::Stmt<'hir>>, assignments: &mut Vec<hir::Stmt<'hir>>,
) -> (&'hir [&'hir hir::Pat<'hir>], Option<(usize, Span)>) { ) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) {
let mut rest = None; let mut rest = None;
let elements = let elements =
self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| { self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {
@ -1204,7 +1213,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} }
None None
} else { } else {
Some(self.destructure_assign(e, eq_sign_span, assignments)) Some(self.destructure_assign_mut(e, eq_sign_span, assignments))
} }
})); }));
(elements, rest) (elements, rest)
@ -1559,13 +1568,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// Desugar `ExprKind::Try` from: `<expr>?` into: /// Desugar `ExprKind::Try` from: `<expr>?` into:
/// ```rust /// ```rust
/// match Try::into_result(<expr>) { /// match Try::branch(<expr>) {
/// Ok(val) => #[allow(unreachable_code)] val, /// ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,
/// Err(err) => #[allow(unreachable_code)] /// ControlFlow::Break(residual) =>
/// // If there is an enclosing `try {...}`: /// #[allow(unreachable_code)]
/// break 'catch_target Try::from_error(From::from(err)), /// // If there is an enclosing `try {...}`:
/// // Otherwise: /// break 'catch_target Try::from_residual(residual),
/// return Try::from_error(From::from(err)), /// // Otherwise:
/// return Try::from_residual(residual),
/// } /// }
/// ``` /// ```
fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> { fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> {

View File

@ -343,9 +343,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
// opaque type Foo1: Trait // opaque type Foo1: Trait
let ty = self.lower_ty( let ty = self.lower_ty(
ty, ty,
ImplTraitContext::OtherOpaqueTy { ImplTraitContext::TypeAliasesOpaqueTy {
capturable_lifetimes: &mut FxHashSet::default(), capturable_lifetimes: &mut FxHashSet::default(),
origin: hir::OpaqueTyOrigin::TyAlias,
}, },
); );
let generics = self.lower_generics(gen, ImplTraitContext::disallowed()); let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
@ -484,17 +483,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span, span: Span,
body: Option<&Expr>, body: Option<&Expr>,
) -> (&'hir hir::Ty<'hir>, hir::BodyId) { ) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
let mut capturable_lifetimes; let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Binding));
let itctx = if self.sess.features_untracked().impl_trait_in_bindings {
capturable_lifetimes = FxHashSet::default();
ImplTraitContext::OtherOpaqueTy {
capturable_lifetimes: &mut capturable_lifetimes,
origin: hir::OpaqueTyOrigin::Misc,
}
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
};
let ty = self.lower_ty(ty, itctx);
(ty, self.lower_const_body(span, body)) (ty, self.lower_const_body(span, body))
} }
@ -926,9 +915,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
Some(ty) => { Some(ty) => {
let ty = self.lower_ty( let ty = self.lower_ty(
ty, ty,
ImplTraitContext::OtherOpaqueTy { ImplTraitContext::TypeAliasesOpaqueTy {
capturable_lifetimes: &mut FxHashSet::default(), capturable_lifetimes: &mut FxHashSet::default(),
origin: hir::OpaqueTyOrigin::TyAlias,
}, },
); );
hir::ImplItemKind::TyAlias(ty) hir::ImplItemKind::TyAlias(ty)
@ -1385,50 +1373,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
itctx: ImplTraitContext<'_, 'hir>, itctx: ImplTraitContext<'_, 'hir>,
) -> GenericsCtor<'hir> { ) -> GenericsCtor<'hir> {
// Collect `?Trait` bounds in where clause and move them to parameter definitions. // Collect `?Trait` bounds in where clause and move them to parameter definitions.
// FIXME: this could probably be done with less rightward drift. It also looks like two
// control paths where `report_error` is called are the only paths that advance to after the
// match statement, so the error reporting could probably just be moved there.
let mut add_bounds: NodeMap<Vec<_>> = Default::default(); let mut add_bounds: NodeMap<Vec<_>> = Default::default();
for pred in &generics.where_clause.predicates { for pred in &generics.where_clause.predicates {
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred { if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
'next_bound: for bound in &bound_pred.bounds { 'next_bound: for bound in &bound_pred.bounds {
if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound { if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound {
let report_error = |this: &mut Self| {
this.diagnostic().span_err(
bound_pred.bounded_ty.span,
"`?Trait` bounds are only permitted at the \
point where a type parameter is declared",
);
};
// Check if the where clause type is a plain type parameter. // Check if the where clause type is a plain type parameter.
match bound_pred.bounded_ty.kind { match self
TyKind::Path(None, ref path) .resolver
if path.segments.len() == 1 .get_partial_res(bound_pred.bounded_ty.id)
&& bound_pred.bound_generic_params.is_empty() => .map(|d| (d.base_res(), d.unresolved_segments()))
{
Some((Res::Def(DefKind::TyParam, def_id), 0))
if bound_pred.bound_generic_params.is_empty() =>
{ {
if let Some(Res::Def(DefKind::TyParam, def_id)) = self for param in &generics.params {
.resolver if def_id == self.resolver.local_def_id(param.id).to_def_id() {
.get_partial_res(bound_pred.bounded_ty.id) add_bounds.entry(param.id).or_default().push(bound.clone());
.map(|d| d.base_res()) continue 'next_bound;
{
if let Some(def_id) = def_id.as_local() {
for param in &generics.params {
if let GenericParamKind::Type { .. } = param.kind {
if def_id == self.resolver.local_def_id(param.id) {
add_bounds
.entry(param.id)
.or_default()
.push(bound.clone());
continue 'next_bound;
}
}
}
} }
} }
report_error(self)
} }
_ => report_error(self), _ => {}
} }
self.diagnostic().span_err(
bound_pred.bounded_ty.span,
"`?Trait` bounds are only permitted at the \
point where a type parameter is declared",
);
} }
} }
} }

View File

@ -48,7 +48,7 @@ use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability}; use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_ID}; use rustc_hir::def_id::{DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_ID};
use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::intravisit; use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_hir::{ConstArg, GenericArg, ParamName};
@ -59,7 +59,7 @@ use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId; use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
@ -204,6 +204,8 @@ pub trait ResolverAstLowering {
fn local_def_id(&self, node: NodeId) -> LocalDefId; fn local_def_id(&self, node: NodeId) -> LocalDefId;
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
fn create_def( fn create_def(
&mut self, &mut self,
parent: LocalDefId, parent: LocalDefId,
@ -214,6 +216,32 @@ pub trait ResolverAstLowering {
) -> LocalDefId; ) -> LocalDefId;
} }
struct LoweringHasher<'a> {
source_map: CachingSourceMapView<'a>,
resolver: &'a dyn ResolverAstLowering,
}
impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> {
#[inline]
fn hash_spans(&self) -> bool {
true
}
#[inline]
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
self.resolver.def_path_hash(def_id)
}
#[inline]
fn span_data_to_lines_and_cols(
&mut self,
span: &rustc_span::SpanData,
) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
{
self.source_map.span_data_to_lines_and_cols(span)
}
}
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has. /// and if so, what meaning it has.
#[derive(Debug)] #[derive(Debug)]
@ -236,8 +264,8 @@ enum ImplTraitContext<'b, 'a> {
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
origin: hir::OpaqueTyOrigin, origin: hir::OpaqueTyOrigin,
}, },
/// Impl trait in type aliases, consts and statics. /// Impl trait in type aliases.
OtherOpaqueTy { TypeAliasesOpaqueTy {
/// Set of lifetimes that this opaque type can capture, if it uses /// Set of lifetimes that this opaque type can capture, if it uses
/// them. This includes lifetimes bound since we entered this context. /// them. This includes lifetimes bound since we entered this context.
/// For example: /// For example:
@ -252,8 +280,6 @@ enum ImplTraitContext<'b, 'a> {
// FIXME(impl_trait): but `required_region_bounds` will ICE later // FIXME(impl_trait): but `required_region_bounds` will ICE later
// anyway. // anyway.
capturable_lifetimes: &'b mut FxHashSet<hir::LifetimeName>, capturable_lifetimes: &'b mut FxHashSet<hir::LifetimeName>,
/// Origin: Either OpaqueTyOrigin::Misc or OpaqueTyOrigin::Binding,
origin: hir::OpaqueTyOrigin,
}, },
/// `impl Trait` is not accepted in this position. /// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition), Disallowed(ImplTraitPosition),
@ -282,8 +308,8 @@ impl<'a> ImplTraitContext<'_, 'a> {
ReturnPositionOpaqueTy { fn_def_id, origin } => { ReturnPositionOpaqueTy { fn_def_id, origin } => {
ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin } ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin }
} }
OtherOpaqueTy { capturable_lifetimes, origin } => { TypeAliasesOpaqueTy { capturable_lifetimes } => {
OtherOpaqueTy { capturable_lifetimes, origin: *origin } TypeAliasesOpaqueTy { capturable_lifetimes }
} }
Disallowed(pos) => Disallowed(*pos), Disallowed(pos) => Disallowed(*pos),
} }
@ -296,7 +322,7 @@ pub fn lower_crate<'a, 'hir>(
resolver: &'a mut dyn ResolverAstLowering, resolver: &'a mut dyn ResolverAstLowering,
nt_to_tokenstream: NtToTokenstream, nt_to_tokenstream: NtToTokenstream,
arena: &'hir Arena<'hir>, arena: &'hir Arena<'hir>,
) -> hir::Crate<'hir> { ) -> &'hir hir::Crate<'hir> {
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
LoweringContext { LoweringContext {
@ -331,7 +357,7 @@ pub fn lower_crate<'a, 'hir>(
lifetimes_to_define: Vec::new(), lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false, is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(), in_scope_lifetimes: Vec::new(),
allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()), allow_try_trait: Some([sym::try_trait_v2][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()), allow_gen_future: Some([sym::gen_future][..].into()),
} }
.lower_crate(krate) .lower_crate(krate)
@ -403,7 +429,7 @@ enum AnonymousLifetimeMode {
} }
impl<'a, 'hir> LoweringContext<'a, 'hir> { impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_crate(mut self, c: &Crate) -> hir::Crate<'hir> { fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
/// Full-crate AST visitor that inserts into a fresh /// Full-crate AST visitor that inserts into a fresh
/// `LoweringContext` any information that may be /// `LoweringContext` any information that may be
/// needed from arbitrary locations in the crate, /// needed from arbitrary locations in the crate,
@ -417,7 +443,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) { fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) {
match tree.kind { match tree.kind {
UseTreeKind::Simple(_, id1, id2) => { UseTreeKind::Simple(_, id1, id2) => {
for &id in &[id1, id2] { for id in [id1, id2] {
self.lctx.allocate_hir_id_counter(id); self.lctx.allocate_hir_id_counter(id);
} }
} }
@ -530,7 +556,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
hir::Crate { let krate = hir::Crate {
item: module, item: module,
exported_macros: self.arena.alloc_from_iter(self.exported_macros), exported_macros: self.arena.alloc_from_iter(self.exported_macros),
non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs), non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs),
@ -545,7 +571,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
proc_macros, proc_macros,
trait_map, trait_map,
attrs: self.attrs, attrs: self.attrs,
} };
self.arena.alloc(krate)
} }
fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId { fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
@ -564,6 +591,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lowered lowered
} }
fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
LoweringHasher {
source_map: CachingSourceMapView::new(self.sess.source_map()),
resolver: self.resolver,
}
}
fn lower_node_id_generic( fn lower_node_id_generic(
&mut self, &mut self,
ast_node_id: NodeId, ast_node_id: NodeId,
@ -683,7 +717,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span, span: Span,
allow_internal_unstable: Option<Lrc<[Symbol]>>, allow_internal_unstable: Option<Lrc<[Symbol]>>,
) -> Span { ) -> Span {
span.mark_with_reason(allow_internal_unstable, reason, self.sess.edition()) span.mark_with_reason(
allow_internal_unstable,
reason,
self.sess.edition(),
self.create_stable_hashing_context(),
)
} }
fn with_anonymous_lifetime_mode<R>( fn with_anonymous_lifetime_mode<R>(
@ -1085,7 +1124,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// //
// fn foo() -> impl Iterator<Item = impl Debug> // fn foo() -> impl Iterator<Item = impl Debug>
ImplTraitContext::ReturnPositionOpaqueTy { .. } ImplTraitContext::ReturnPositionOpaqueTy { .. }
| ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx), | ImplTraitContext::TypeAliasesOpaqueTy { .. } => (true, itctx),
// We are in the argument position, but within a dyn type: // We are in the argument position, but within a dyn type:
// //
@ -1109,9 +1148,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
capturable_lifetimes = FxHashSet::default(); capturable_lifetimes = FxHashSet::default();
( (
true, true,
ImplTraitContext::OtherOpaqueTy { ImplTraitContext::TypeAliasesOpaqueTy {
capturable_lifetimes: &mut capturable_lifetimes, capturable_lifetimes: &mut capturable_lifetimes,
origin: hir::OpaqueTyOrigin::Misc,
}, },
) )
} }
@ -1375,18 +1413,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
None, None,
|this| this.lower_param_bounds(bounds, itctx), |this| this.lower_param_bounds(bounds, itctx),
), ),
ImplTraitContext::OtherOpaqueTy { ref capturable_lifetimes, origin } => { ImplTraitContext::TypeAliasesOpaqueTy { ref capturable_lifetimes } => {
// Reset capturable lifetimes, any nested impl trait // Reset capturable lifetimes, any nested impl trait
// types will inherit lifetimes from this opaque type, // types will inherit lifetimes from this opaque type,
// so don't need to capture them again. // so don't need to capture them again.
let nested_itctx = ImplTraitContext::OtherOpaqueTy { let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy {
capturable_lifetimes: &mut FxHashSet::default(), capturable_lifetimes: &mut FxHashSet::default(),
origin,
}; };
self.lower_opaque_impl_trait( self.lower_opaque_impl_trait(
span, span,
None, None,
origin, hir::OpaqueTyOrigin::TyAlias,
def_node_id, def_node_id,
Some(capturable_lifetimes), Some(capturable_lifetimes),
|this| this.lower_param_bounds(bounds, nested_itctx), |this| this.lower_param_bounds(bounds, nested_itctx),
@ -1423,25 +1460,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}), }),
)) ))
} }
ImplTraitContext::Disallowed(pos) => { ImplTraitContext::Disallowed(_) => {
let allowed_in = if self.sess.features_untracked().impl_trait_in_bindings {
"bindings or function and inherent method return types"
} else {
"function and inherent method return types"
};
let mut err = struct_span_err!( let mut err = struct_span_err!(
self.sess, self.sess,
t.span, t.span,
E0562, E0562,
"`impl Trait` not allowed outside of {}", "`impl Trait` not allowed outside of {}",
allowed_in, "function and method return types",
); );
if pos == ImplTraitPosition::Binding && self.sess.is_nightly_build() {
err.help(
"add `#![feature(impl_trait_in_bindings)]` to the crate \
attributes to enable",
);
}
err.emit(); err.emit();
hir::TyKind::Err hir::TyKind::Err
} }
@ -1726,21 +1752,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
fn lower_local(&mut self, l: &Local) -> hir::Local<'hir> { fn lower_local(&mut self, l: &Local) -> hir::Local<'hir> {
let ty = l.ty.as_ref().map(|t| { let ty = l
let mut capturable_lifetimes; .ty
self.lower_ty( .as_ref()
t, .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
if self.sess.features_untracked().impl_trait_in_bindings {
capturable_lifetimes = FxHashSet::default();
ImplTraitContext::OtherOpaqueTy {
capturable_lifetimes: &mut capturable_lifetimes,
origin: hir::OpaqueTyOrigin::Binding,
}
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
},
)
});
let init = l.init.as_ref().map(|e| self.lower_expr(e)); let init = l.init.as_ref().map(|e| self.lower_expr(e));
let hir_id = self.lower_node_id(l.id); let hir_id = self.lower_node_id(l.id);
self.lower_attrs(hir_id, &l.attrs); self.lower_attrs(hir_id, &l.attrs);
@ -2291,13 +2306,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)), )),
_ => None, _ => None,
}); });
if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx { if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
itctx
{
capturable_lifetimes.extend(lt_def_names.clone()); capturable_lifetimes.extend(lt_def_names.clone());
} }
let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow()); let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx { if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
itctx
{
for param in lt_def_names { for param in lt_def_names {
capturable_lifetimes.remove(&param); capturable_lifetimes.remove(&param);
} }
@ -2536,21 +2555,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated) self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated)
} }
fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) {
self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::Unannotated)
}
fn pat_ident_binding_mode( fn pat_ident_binding_mode(
&mut self, &mut self,
span: Span, span: Span,
ident: Ident, ident: Ident,
bm: hir::BindingAnnotation, bm: hir::BindingAnnotation,
) -> (&'hir hir::Pat<'hir>, hir::HirId) { ) -> (&'hir hir::Pat<'hir>, hir::HirId) {
let (pat, hir_id) = self.pat_ident_binding_mode_mut(span, ident, bm);
(self.arena.alloc(pat), hir_id)
}
fn pat_ident_binding_mode_mut(
&mut self,
span: Span,
ident: Ident,
bm: hir::BindingAnnotation,
) -> (hir::Pat<'hir>, hir::HirId) {
let hir_id = self.next_id(); let hir_id = self.next_id();
( (
self.arena.alloc(hir::Pat { hir::Pat {
hir_id, hir_id,
kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None), kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
span, span,
default_binding_modes: true, default_binding_modes: true,
}), },
hir_id, hir_id,
) )
} }
@ -2568,13 +2601,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}) })
} }
fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> { fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
self.arena.alloc(hir::Pat { hir::Pat { hir_id: self.next_id(), kind, span, default_binding_modes: false }
hir_id: self.next_id(),
kind,
span,
default_binding_modes: false,
})
} }
fn ty_path( fn ty_path(

View File

@ -10,7 +10,11 @@ use rustc_span::symbol::Ident;
use rustc_span::{source_map::Spanned, Span}; use rustc_span::{source_map::Spanned, Span};
impl<'a, 'hir> LoweringContext<'a, 'hir> { impl<'a, 'hir> LoweringContext<'a, 'hir> {
crate fn lower_pat(&mut self, mut pattern: &Pat) -> &'hir hir::Pat<'hir> { crate fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
self.arena.alloc(self.lower_pat_mut(pattern))
}
crate fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
// loop here to avoid recursion // loop here to avoid recursion
let node = loop { let node = loop {
@ -34,7 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
PatKind::Or(ref pats) => { PatKind::Or(ref pats) => {
break hir::PatKind::Or( break hir::PatKind::Or(
self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))), self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))),
); );
} }
PatKind::Path(ref qself, ref path) => { PatKind::Path(ref qself, ref path) => {
@ -101,7 +105,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self, &mut self,
pats: &[P<Pat>], pats: &[P<Pat>],
ctx: &str, ctx: &str,
) -> (&'hir [&'hir hir::Pat<'hir>], Option<usize>) { ) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
let mut elems = Vec::with_capacity(pats.len()); let mut elems = Vec::with_capacity(pats.len());
let mut rest = None; let mut rest = None;
@ -140,7 +144,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
// It was not a sub-tuple pattern so lower it normally. // It was not a sub-tuple pattern so lower it normally.
elems.push(self.lower_pat(pat)); elems.push(self.lower_pat_mut(pat));
} }
for (_, pat) in iter { for (_, pat) in iter {
@ -149,7 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// ...but there was one again, so error. // ...but there was one again, so error.
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx); self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
} else { } else {
elems.push(self.lower_pat(pat)); elems.push(self.lower_pat_mut(pat));
} }
} }
@ -189,11 +193,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Record, lower it to `$binding_mode $ident @ _`, and stop here. // Record, lower it to `$binding_mode $ident @ _`, and stop here.
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
prev_rest_span = Some(sub.span); prev_rest_span = Some(sub.span);
slice = Some(lower_rest_sub(self, pat, bm, ident, sub)); slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub)));
break; break;
} }
// It was not a subslice pattern so lower it normally. // It was not a subslice pattern so lower it normally.
_ => before.push(self.lower_pat(pat)), _ => before.push(self.lower_pat_mut(pat)),
} }
} }
@ -214,7 +218,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice"); self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
} else { } else {
// Lower the pattern normally. // Lower the pattern normally.
after.push(self.lower_pat(pat)); after.push(self.lower_pat_mut(pat));
} }
} }
@ -268,17 +272,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
self.pat_with_node_id_of(p, hir::PatKind::Wild) self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild))
} }
/// Construct a `Pat` with the `HirId` of `p.id` lowered. /// Construct a `Pat` with the `HirId` of `p.id` lowered.
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> { fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
self.arena.alloc(hir::Pat { hir::Pat {
hir_id: self.lower_node_id(p.id), hir_id: self.lower_node_id(p.id),
kind, kind,
span: p.span, span: p.span,
default_binding_modes: true, default_binding_modes: true,
}) }
} }
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.

View File

@ -336,6 +336,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
insertion_sp, insertion_sp,
suggestion, suggestion,
); );
err.note("assuming a `'static` lifetime...");
err.emit(); err.emit();
} }
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => { AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {

View File

@ -652,7 +652,7 @@ impl<'a> AstValidator<'a> {
self.err_handler() self.err_handler()
.struct_span_err( .struct_span_err(
*span, *span,
"only foreign or `unsafe extern \"C\" functions may be C-variadic", "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
) )
.emit(); .emit();
} }
@ -889,35 +889,32 @@ fn validate_generic_param_order(
) { ) {
let mut max_param: Option<ParamKindOrd> = None; let mut max_param: Option<ParamKindOrd> = None;
let mut out_of_order = FxHashMap::default(); let mut out_of_order = FxHashMap::default();
let mut param_idents = vec![]; let mut param_idents = Vec::with_capacity(generics.len());
for param in generics { for (idx, param) in generics.iter().enumerate() {
let ident = Some(param.ident.to_string()); let ident = param.ident;
let (kind, bounds, span) = (&param.kind, Some(&*param.bounds), param.ident.span); let (kind, bounds, span) = (&param.kind, &param.bounds, ident.span);
let (ord_kind, ident) = match &param.kind { let (ord_kind, ident) = match &param.kind {
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident), GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident), GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => { GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
let ty = pprust::ty_to_string(ty); let ty = pprust::ty_to_string(ty);
let unordered = sess.features_untracked().unordered_const_ty_params(); let unordered = sess.features_untracked().unordered_const_ty_params();
(ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty))) (ParamKindOrd::Const { unordered }, format!("const {}: {}", ident, ty))
} }
}; };
if let Some(ident) = ident { param_idents.push((kind, ord_kind, bounds, idx, ident));
param_idents.push((kind, ord_kind, bounds, param_idents.len(), ident));
}
let max_param = &mut max_param;
match max_param { match max_param {
Some(max_param) if *max_param > ord_kind => { Some(max_param) if max_param > ord_kind => {
let entry = out_of_order.entry(ord_kind).or_insert((*max_param, vec![])); let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
entry.1.push(span); entry.1.push(span);
} }
Some(_) | None => *max_param = Some(ord_kind), Some(_) | None => max_param = Some(ord_kind),
}; };
} }
let mut ordered_params = "<".to_string();
if !out_of_order.is_empty() { if !out_of_order.is_empty() {
let mut ordered_params = "<".to_string();
param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i)); param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
let mut first = true; let mut first = true;
for (kind, _, bounds, _, ident) in param_idents { for (kind, _, bounds, _, ident) in param_idents {
@ -925,12 +922,12 @@ fn validate_generic_param_order(
ordered_params += ", "; ordered_params += ", ";
} }
ordered_params += &ident; ordered_params += &ident;
if let Some(bounds) = bounds {
if !bounds.is_empty() { if !bounds.is_empty() {
ordered_params += ": "; ordered_params += ": ";
ordered_params += &pprust::bounds_to_string(&bounds); ordered_params += &pprust::bounds_to_string(&bounds);
}
} }
match kind { match kind {
GenericParamKind::Type { default: Some(default) } => { GenericParamKind::Type { default: Some(default) } => {
ordered_params += " = "; ordered_params += " = ";
@ -946,32 +943,32 @@ fn validate_generic_param_order(
} }
first = false; first = false;
} }
}
ordered_params += ">";
for (param_ord, (max_param, spans)) in &out_of_order { ordered_params += ">";
let mut err =
handler.struct_span_err( for (param_ord, (max_param, spans)) in &out_of_order {
let mut err = handler.struct_span_err(
spans.clone(), spans.clone(),
&format!( &format!(
"{} parameters must be declared prior to {} parameters", "{} parameters must be declared prior to {} parameters",
param_ord, max_param, param_ord, max_param,
), ),
); );
err.span_suggestion( err.span_suggestion(
span, span,
&format!( &format!(
"reorder the parameters: lifetimes, {}", "reorder the parameters: lifetimes, {}",
if sess.features_untracked().unordered_const_ty_params() { if sess.features_untracked().unordered_const_ty_params() {
"then consts and types" "then consts and types"
} else { } else {
"then types, then consts" "then types, then consts"
} }
), ),
ordered_params.clone(), ordered_params.clone(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
err.emit(); err.emit();
}
} }
} }

View File

@ -565,6 +565,22 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_pat(&mut self, pattern: &'a ast::Pat) { fn visit_pat(&mut self, pattern: &'a ast::Pat) {
match &pattern.kind { match &pattern.kind {
PatKind::Slice(pats) => {
for pat in pats {
let inner_pat = match &pat.kind {
PatKind::Ident(.., Some(pat)) => pat,
_ => pat,
};
if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind {
gate_feature_post!(
&self,
half_open_range_patterns,
pat.span,
"`X..` patterns in slices are experimental"
);
}
}
}
PatKind::Box(..) => { PatKind::Box(..) => {
gate_feature_post!( gate_feature_post!(
&self, &self,
@ -573,7 +589,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"box pattern syntax is experimental" "box pattern syntax is experimental"
); );
} }
PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
gate_feature_post!( gate_feature_post!(
&self, &self,
exclusive_range_pattern, exclusive_range_pattern,

View File

@ -136,11 +136,11 @@ pub fn print_crate<'a>(
s.s.eof() s.s.eof()
} }
// This makes printed token streams look slightly nicer, /// This makes printed token streams look slightly nicer,
// and also addresses some specific regressions described in #63896 and #73345. /// and also addresses some specific regressions described in #63896 and #73345.
fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
if let TokenTree::Token(token) = prev { if let TokenTree::Token(token) = prev {
if matches!(token.kind, token::Dot) { if matches!(token.kind, token::Dot | token::Dollar) {
return false; return false;
} }
if let token::DocComment(comment_kind, ..) = token.kind { if let token::DocComment(comment_kind, ..) = token.kind {
@ -1954,7 +1954,6 @@ impl<'a> State<'a> {
self.word_space(":"); self.word_space(":");
} }
self.head("loop"); self.head("loop");
self.s.space();
self.print_block_with_attrs(blk, attrs); self.print_block_with_attrs(blk, attrs);
} }
ast::ExprKind::Match(ref expr, ref arms) => { ast::ExprKind::Match(ref expr, ref arms) => {
@ -2284,6 +2283,9 @@ impl<'a> State<'a> {
if opts.contains(InlineAsmOptions::ATT_SYNTAX) { if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
options.push("att_syntax"); options.push("att_syntax");
} }
if opts.contains(InlineAsmOptions::RAW) {
options.push("raw");
}
s.commasep(Inconsistent, &options, |s, &opt| { s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt); s.word(opt);
}); });

View File

@ -1,8 +1,8 @@
use super::*; use super::*;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_span::create_default_session_globals_then;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::with_default_session_globals;
fn fun_to_string( fn fun_to_string(
decl: &ast::FnDecl, decl: &ast::FnDecl,
@ -24,7 +24,7 @@ fn variant_to_string(var: &ast::Variant) -> String {
#[test] #[test]
fn test_fun_to_string() { fn test_fun_to_string() {
with_default_session_globals(|| { create_default_session_globals_then(|| {
let abba_ident = Ident::from_str("abba"); let abba_ident = Ident::from_str("abba");
let decl = let decl =
@ -39,7 +39,7 @@ fn test_fun_to_string() {
#[test] #[test]
fn test_variant_to_string() { fn test_variant_to_string() {
with_default_session_globals(|| { create_default_session_globals_then(|| {
let ident = Ident::from_str("principal_skinner"); let ident = Ident::from_str("principal_skinner");
let var = ast::Variant { let var = ast::Variant {
@ -49,7 +49,7 @@ fn test_variant_to_string() {
kind: ast::VisibilityKind::Inherited, kind: ast::VisibilityKind::Inherited,
tokens: None, tokens: None,
}, },
attrs: Vec::new(), attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
disr_expr: None, disr_expr: None,

View File

@ -862,18 +862,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
if let Some(items) = attr.meta_item_list() { if let Some(items) = attr.meta_item_list() {
sess.mark_attr_used(attr); sess.mark_attr_used(attr);
for item in items { for item in items {
if !item.is_meta_item() {
handle_errors(
&sess.parse_sess,
item.span(),
AttrError::UnsupportedLiteral(
"meta item in `repr` must be an identifier",
false,
),
);
continue;
}
let mut recognised = false; let mut recognised = false;
if item.is_word() { if item.is_word() {
let hint = match item.name_or_empty() { let hint = match item.name_or_empty() {
@ -882,6 +870,23 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
sym::simd => Some(ReprSimd), sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent), sym::transparent => Some(ReprTransparent),
sym::no_niche => Some(ReprNoNiche), sym::no_niche => Some(ReprNoNiche),
sym::align => {
let mut err = struct_span_err!(
diagnostic,
item.span(),
E0589,
"invalid `repr(align)` attribute: `align` needs an argument"
);
err.span_suggestion(
item.span(),
"supply an argument here",
"align(...)".to_string(),
Applicability::HasPlaceholders,
);
err.emit();
recognised = true;
None
}
name => int_type_of_word(name).map(ReprInt), name => int_type_of_word(name).map(ReprInt),
}; };
@ -890,23 +895,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
acc.push(h); acc.push(h);
} }
} else if let Some((name, value)) = item.name_value_literal() { } else if let Some((name, value)) = item.name_value_literal() {
let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> {
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
if literal.is_power_of_two() {
// rustc_middle::ty::layout::Align restricts align to <= 2^29
if *literal <= 1 << 29 {
Ok(*literal as u32)
} else {
Err("larger than 2^29")
}
} else {
Err("not a power of two")
}
} else {
Err("not an unsuffixed integer")
}
};
let mut literal_error = None; let mut literal_error = None;
if name == sym::align { if name == sym::align {
recognised = true; recognised = true;
@ -920,33 +908,47 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
Ok(literal) => acc.push(ReprPacked(literal)), Ok(literal) => acc.push(ReprPacked(literal)),
Err(message) => literal_error = Some(message), Err(message) => literal_error = Some(message),
}; };
} else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
|| int_type_of_word(name).is_some()
{
recognised = true;
struct_span_err!(
diagnostic,
item.span(),
E0552,
"invalid representation hint: `{}` does not take a parenthesized argument list",
name.to_ident_string(),
).emit();
} }
if let Some(literal_error) = literal_error { if let Some(literal_error) = literal_error {
struct_span_err!( struct_span_err!(
diagnostic, diagnostic,
item.span(), item.span(),
E0589, E0589,
"invalid `repr(align)` attribute: {}", "invalid `repr({})` attribute: {}",
name.to_ident_string(),
literal_error literal_error
) )
.emit(); .emit();
} }
} else if let Some(meta_item) = item.meta_item() { } else if let Some(meta_item) = item.meta_item() {
if meta_item.has_name(sym::align) { if let MetaItemKind::NameValue(ref value) = meta_item.kind {
if let MetaItemKind::NameValue(ref value) = meta_item.kind { if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
let name = meta_item.name_or_empty().to_ident_string();
recognised = true; recognised = true;
let mut err = struct_span_err!( let mut err = struct_span_err!(
diagnostic, diagnostic,
item.span(), item.span(),
E0693, E0693,
"incorrect `repr(align)` attribute format" "incorrect `repr({})` attribute format",
name,
); );
match value.kind { match value.kind {
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
err.span_suggestion( err.span_suggestion(
item.span(), item.span(),
"use parentheses instead", "use parentheses instead",
format!("align({})", int), format!("{}({})", name, int),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
@ -954,25 +956,76 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
err.span_suggestion( err.span_suggestion(
item.span(), item.span(),
"use parentheses instead", "use parentheses instead",
format!("align({})", s), format!("{}({})", name, s),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
_ => {} _ => {}
} }
err.emit(); err.emit();
} else {
if matches!(
meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent | sym::no_niche
) || int_type_of_word(meta_item.name_or_empty()).is_some()
{
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"invalid representation hint: `{}` does not take a value",
meta_item.name_or_empty().to_ident_string(),
)
.emit();
}
}
} else if let MetaItemKind::List(_) = meta_item.kind {
if meta_item.has_name(sym::align) {
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0693,
"incorrect `repr(align)` attribute format: \
`align` takes exactly one argument in parentheses"
)
.emit();
} else if meta_item.has_name(sym::packed) {
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"incorrect `repr(packed)` attribute format: \
`packed` takes exactly one parenthesized argument, \
or no parentheses at all"
)
.emit();
} else if matches!(
meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent | sym::no_niche
) || int_type_of_word(meta_item.name_or_empty()).is_some()
{
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"invalid representation hint: `{}` does not take a parenthesized argument list",
meta_item.name_or_empty().to_ident_string(),
).emit();
} }
} }
} }
if !recognised { if !recognised {
// Not a word we recognize // Not a word we recognize. This will be caught and reported by
struct_span_err!( // the `check_mod_attrs` pass, but this pass doesn't always run
diagnostic, // (e.g. if we only pretty-print the source), so we have to gate
item.span(), // the `delay_span_bug` call as follows:
E0552, if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
"unrecognized representation hint" diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
) }
.emit();
} }
} }
} }
@ -1080,3 +1133,16 @@ fn allow_unstable<'a>(
name name
}) })
} }
pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
if literal.is_power_of_two() {
// rustc_middle::ty::layout::Align restricts align to <= 2^29
if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") }
} else {
Err("not a power of two")
}
} else {
Err("not an unsuffixed integer")
}
}

View File

@ -356,6 +356,8 @@ fn parse_options<'a>(
try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK); try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
} else if p.eat_keyword(sym::att_syntax) { } else if p.eat_keyword(sym::att_syntax) {
try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
} else if p.eat_keyword(kw::Raw) {
try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
} else { } else {
return p.unexpected(); return p.unexpected();
} }
@ -453,7 +455,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
ecx.parse_sess().buffer_lint( ecx.parse_sess().buffer_lint(
lint::builtin::BAD_ASM_STYLE, lint::builtin::BAD_ASM_STYLE,
find_span(".intel_syntax"), find_span(".intel_syntax"),
ecx.resolver.lint_node_id(ecx.current_expansion.id), ecx.current_expansion.lint_node_id,
"avoid using `.intel_syntax`, Intel syntax is the default", "avoid using `.intel_syntax`, Intel syntax is the default",
); );
} }
@ -461,12 +463,20 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
ecx.parse_sess().buffer_lint( ecx.parse_sess().buffer_lint(
lint::builtin::BAD_ASM_STYLE, lint::builtin::BAD_ASM_STYLE,
find_span(".att_syntax"), find_span(".att_syntax"),
ecx.resolver.lint_node_id(ecx.current_expansion.id), ecx.current_expansion.lint_node_id,
"avoid using `.att_syntax`, prefer using `options(att_syntax)` instead", "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
); );
} }
} }
// Don't treat raw asm as a format string.
if args.options.contains(ast::InlineAsmOptions::RAW) {
template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string()));
let template_num_lines = 1 + template_str.matches('\n').count();
line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
continue;
}
let mut parser = parse::Parser::new( let mut parser = parse::Parser::new(
template_str, template_str,
str_style, str_style,

View File

@ -24,61 +24,60 @@ crate fn expand(
annotatable: Annotatable, annotatable: Annotatable,
) -> Vec<Annotatable> { ) -> Vec<Annotatable> {
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval); check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
cfg_eval(ecx, annotatable) vec![cfg_eval(ecx, annotatable)]
} }
crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Vec<Annotatable> { crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable {
let mut visitor = CfgEval { CfgEval {
cfg: &mut StripUnconfigured { cfg: &mut StripUnconfigured {
sess: ecx.sess, sess: ecx.sess,
features: ecx.ecfg.features, features: ecx.ecfg.features,
config_tokens: true, config_tokens: true,
}, },
}; }
let annotatable = visitor.configure_annotatable(annotatable); .configure_annotatable(annotatable)
vec![annotatable] // Since the item itself has already been configured by the `InvocationCollector`,
// we know that fold result vector will contain exactly one element.
.unwrap()
} }
struct CfgEval<'a, 'b> { struct CfgEval<'a, 'b> {
cfg: &'a mut StripUnconfigured<'b>, cfg: &'a mut StripUnconfigured<'b>,
} }
fn flat_map_annotatable(vis: &mut impl MutVisitor, annotatable: Annotatable) -> Annotatable { fn flat_map_annotatable(
// Since the item itself has already been configured by the InvocationCollector, vis: &mut impl MutVisitor,
// we know that fold result vector will contain exactly one element annotatable: Annotatable,
) -> Option<Annotatable> {
match annotatable { match annotatable {
Annotatable::Item(item) => Annotatable::Item(vis.flat_map_item(item).pop().unwrap()), Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item),
Annotatable::TraitItem(item) => { Annotatable::TraitItem(item) => {
Annotatable::TraitItem(vis.flat_map_trait_item(item).pop().unwrap()) vis.flat_map_trait_item(item).pop().map(Annotatable::TraitItem)
} }
Annotatable::ImplItem(item) => { Annotatable::ImplItem(item) => {
Annotatable::ImplItem(vis.flat_map_impl_item(item).pop().unwrap()) vis.flat_map_impl_item(item).pop().map(Annotatable::ImplItem)
} }
Annotatable::ForeignItem(item) => { Annotatable::ForeignItem(item) => {
Annotatable::ForeignItem(vis.flat_map_foreign_item(item).pop().unwrap()) vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
} }
Annotatable::Stmt(stmt) => { Annotatable::Stmt(stmt) => {
Annotatable::Stmt(stmt.map(|stmt| vis.flat_map_stmt(stmt).pop().unwrap())) vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt)
} }
Annotatable::Expr(mut expr) => Annotatable::Expr({ Annotatable::Expr(mut expr) => {
vis.visit_expr(&mut expr); vis.visit_expr(&mut expr);
expr Some(Annotatable::Expr(expr))
}), }
Annotatable::Arm(arm) => Annotatable::Arm(vis.flat_map_arm(arm).pop().unwrap()), Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm),
Annotatable::ExprField(field) => { Annotatable::ExprField(field) => {
Annotatable::ExprField(vis.flat_map_expr_field(field).pop().unwrap()) vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField)
}
Annotatable::PatField(fp) => {
Annotatable::PatField(vis.flat_map_pat_field(fp).pop().unwrap())
} }
Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField),
Annotatable::GenericParam(param) => { Annotatable::GenericParam(param) => {
Annotatable::GenericParam(vis.flat_map_generic_param(param).pop().unwrap()) vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam)
} }
Annotatable::Param(param) => Annotatable::Param(vis.flat_map_param(param).pop().unwrap()), Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
Annotatable::FieldDef(sf) => { Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
Annotatable::FieldDef(vis.flat_map_field_def(sf).pop().unwrap()) Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
}
Annotatable::Variant(v) => Annotatable::Variant(vis.flat_map_variant(v).pop().unwrap()),
} }
} }
@ -123,11 +122,11 @@ impl CfgEval<'_, '_> {
self.cfg.configure(node) self.cfg.configure(node)
} }
pub fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Annotatable { fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
// Tokenizing and re-parsing the `Annotatable` can have a significant // Tokenizing and re-parsing the `Annotatable` can have a significant
// performance impact, so try to avoid it if possible // performance impact, so try to avoid it if possible
if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) { if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) {
return annotatable; return Some(annotatable);
} }
// The majority of parsed attribute targets will never need to have early cfg-expansion // The majority of parsed attribute targets will never need to have early cfg-expansion

View File

@ -26,6 +26,8 @@ impl MultiItemModifier for Expander {
return ExpandResult::Ready(vec![item]); return ExpandResult::Ready(vec![item]);
} }
let item = cfg_eval(ecx, item);
let result = let result =
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
let template = let template =
@ -54,12 +56,12 @@ impl MultiItemModifier for Expander {
report_path_args(sess, &meta); report_path_args(sess, &meta);
meta.path meta.path
}) })
.map(|path| (path, None)) .map(|path| (path, item.clone(), None))
.collect() .collect()
}); });
match result { match result {
Ok(()) => ExpandResult::Ready(cfg_eval(ecx, item)), Ok(()) => ExpandResult::Ready(vec![item]),
Err(Indeterminate) => ExpandResult::Retry(item), Err(Indeterminate) => ExpandResult::Retry(item),
} }
} }
@ -82,8 +84,10 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
sess, sess,
span, span,
E0774, E0774,
"`derive` may only be applied to structs, enums and unions", "`derive` may only be applied to `struct`s, `enum`s and `union`s",
) )
.span_label(span, "not applicable here")
.span_label(item.span(), "not a `struct`, `enum` or `union`")
.emit(); .emit();
} }
bad_target bad_target
@ -97,6 +101,7 @@ fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) {
_ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(), _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
}; };
struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",) struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",)
.span_label(lit.span, "not a trait")
.help(&help_msg) .help(&help_msg)
.emit(); .emit();
} }

View File

@ -36,8 +36,9 @@ pub fn expand_deriving_clone(
Annotatable::Item(ref annitem) => match annitem.kind { Annotatable::Item(ref annitem) => match annitem.kind {
ItemKind::Struct(_, Generics { ref params, .. }) ItemKind::Struct(_, Generics { ref params, .. })
| ItemKind::Enum(_, Generics { ref params, .. }) => { | ItemKind::Enum(_, Generics { ref params, .. }) => {
let container_id = cx.current_expansion.id.expn_data().parent; let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
if cx.resolver.has_derive_copy(container_id) let has_derive_copy = cx.resolver.has_derive_copy(container_id);
if has_derive_copy
&& !params && !params
.iter() .iter()
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
@ -148,11 +149,7 @@ fn cs_clone_shallow(
} }
_ => cx.span_bug( _ => cx.span_bug(
trait_span, trait_span,
&format!( &format!("unexpected substructure in shallow `derive({})`", name),
"unexpected substructure in \
shallow `derive({})`",
name
),
), ),
} }
} }

View File

@ -124,12 +124,7 @@ pub fn expand_deriving_rustc_encodable(
explicit_self: borrowed_explicit_self(), explicit_self: borrowed_explicit_self(),
args: vec![( args: vec![(
Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)), Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
// FIXME: we could use `sym::s` here, but making `s` a static sym::s,
// symbol changes the symbol index ordering in a way that makes
// ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
// fail. The linting code should be fixed so that its output
// does not depend on the symbol index ordering.
Symbol::intern("s"),
)], )],
ret_ty: Literal(Path::new_( ret_ty: Literal(Path::new_(
pathvec_std!(result::Result), pathvec_std!(result::Result),

View File

@ -410,7 +410,7 @@ impl<'a> TraitDef<'a> {
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
_ => unreachable!(), _ => unreachable!(),
}; };
let container_id = cx.current_expansion.id.expn_data().parent; let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id);
let use_temporaries = is_packed && always_copy; let use_temporaries = is_packed && always_copy;

View File

@ -72,13 +72,9 @@ impl Path {
) -> ast::Path { ) -> ast::Path {
let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
let lt = mk_lifetimes(cx, span, &self.lifetime); let lt = mk_lifetimes(cx, span, &self.lifetime);
let tys: Vec<P<ast::Ty>> = let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); let params =
let params = lt lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect();
.into_iter()
.map(GenericArg::Lifetime)
.chain(tys.into_iter().map(GenericArg::Type))
.collect();
match self.kind { match self.kind {
PathKind::Global => cx.path_all(span, true, idents, params), PathKind::Global => cx.path_all(span, true, idents, params),

View File

@ -939,6 +939,7 @@ pub fn expand_preparsed_format_args(
let msg = "format argument must be a string literal"; let msg = "format argument must be a string literal";
let fmt_sp = efmt.span; let fmt_sp = efmt.span;
let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_));
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) { let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
Ok(mut fmt) if append_newline => { Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
@ -989,7 +990,19 @@ pub fn expand_preparsed_format_args(
if !parser.errors.is_empty() { if !parser.errors.is_empty() {
let err = parser.errors.remove(0); let err = parser.errors.remove(0);
let sp = fmt_span.from_inner(err.span); let sp = if efmt_kind_is_lit {
fmt_span.from_inner(err.span)
} else {
// The format string could be another macro invocation, e.g.:
// format!(concat!("abc", "{}"), 4);
// However, `err.span` is an inner span relative to the *result* of
// the macro invocation, which is why we would get a nonsensical
// result calling `fmt_span.from_inner(err.span)` as above, and
// might even end up inside a multibyte character (issue #86085).
// Therefore, we conservatively report the error for the entire
// argument span here.
fmt_span
};
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description)); let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description));
e.span_label(sp, err.label + " in format string"); e.span_label(sp, err.label + " in format string");
if let Some(note) = err.note { if let Some(note) = err.note {

View File

@ -19,7 +19,6 @@ use crate::deriving::*;
use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
use rustc_expand::proc_macro::BangProcMacro; use rustc_expand::proc_macro::BangProcMacro;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
mod asm; mod asm;
@ -113,8 +112,5 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
} }
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
register( register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
sym::quote,
SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client, krate: LOCAL_CRATE })),
);
} }

View File

@ -5,7 +5,7 @@ use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor}; use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, NodeId}; use rustc_ast::{self as ast, NodeId};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::hygiene::AstPass; use rustc_span::hygiene::AstPass;
@ -109,86 +109,17 @@ impl<'a> CollectProcMacros<'a> {
} }
fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) { fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
// Once we've located the `#[proc_macro_derive]` attribute, verify let (trait_name, proc_attrs) =
// that it's of the form `#[proc_macro_derive(Foo)]` or match parse_macro_name_and_helper_attrs(self.handler, attr, "derive") {
// `#[proc_macro_derive(Foo, attributes(A, ..))]` Some(name_and_attrs) => name_and_attrs,
let list = match attr.meta_item_list() { None => return,
Some(list) => list, };
None => return,
};
if list.len() != 1 && list.len() != 2 {
self.handler.span_err(attr.span, "attribute must have either one or two arguments");
return;
}
let trait_attr = match list[0].meta_item() {
Some(meta_item) => meta_item,
_ => {
self.handler.span_err(list[0].span(), "not a meta item");
return;
}
};
let trait_ident = match trait_attr.ident() {
Some(trait_ident) if trait_attr.is_word() => trait_ident,
_ => {
self.handler.span_err(trait_attr.span, "must only be one word");
return;
}
};
if !trait_ident.name.can_be_raw() {
self.handler.span_err(
trait_attr.span,
&format!("`{}` cannot be a name of derive macro", trait_ident),
);
}
let attributes_attr = list.get(1);
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
if !attr.has_name(sym::attributes) {
self.handler.span_err(attr.span(), "second argument must be `attributes`")
}
attr.meta_item_list()
.unwrap_or_else(|| {
self.handler
.span_err(attr.span(), "attribute must be of form: `attributes(foo, bar)`");
&[]
})
.iter()
.filter_map(|attr| {
let attr = match attr.meta_item() {
Some(meta_item) => meta_item,
_ => {
self.handler.span_err(attr.span(), "not a meta item");
return None;
}
};
let ident = match attr.ident() {
Some(ident) if attr.is_word() => ident,
_ => {
self.handler.span_err(attr.span, "must only be one word");
return None;
}
};
if !ident.name.can_be_raw() {
self.handler.span_err(
attr.span,
&format!("`{}` cannot be a name of derive helper attribute", ident),
);
}
Some(ident.name)
})
.collect()
} else {
Vec::new()
};
if self.in_root && item.vis.kind.is_pub() { if self.in_root && item.vis.kind.is_pub() {
self.macros.push(ProcMacro::Derive(ProcMacroDerive { self.macros.push(ProcMacro::Derive(ProcMacroDerive {
id: item.id, id: item.id,
span: item.span, span: item.span,
trait_name: trait_ident.name, trait_name,
function_name: item.ident, function_name: item.ident,
attrs: proc_attrs, attrs: proc_attrs,
})); }));
@ -373,7 +304,7 @@ fn mk_decls(
&[sym::rustc_attrs, sym::proc_macro_internals], &[sym::rustc_attrs, sym::proc_macro_internals],
None, None,
); );
let span = DUMMY_SP.with_def_site_ctxt(expn_id); let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
let proc_macro = Ident::new(sym::proc_macro, span); let proc_macro = Ident::new(sym::proc_macro, span);
let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None)); let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None));

View File

@ -159,7 +159,7 @@ pub fn expand_include<'cx>(
} }
} }
Box::new(ExpandResult { p, node_id: cx.resolver.lint_node_id(cx.current_expansion.id) }) Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
} }
// include_str! : read the given file, insert it as a literal string expr // include_str! : read the given file, insert it as a literal string expr

View File

@ -34,8 +34,8 @@ pub fn inject(
&[sym::prelude_import], &[sym::prelude_import],
None, None,
); );
let span = DUMMY_SP.with_def_site_ctxt(expn_id); let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id());
let ecfg = ExpansionConfig::default("std_lib_injection".to_string()); let ecfg = ExpansionConfig::default("std_lib_injection".to_string());
let cx = ExtCtxt::new(sess, ecfg, resolver, None); let cx = ExtCtxt::new(sess, ecfg, resolver, None);

View File

@ -126,7 +126,8 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
for test in &mut tests { for test in &mut tests {
// See the comment on `mk_main` for why we're using // See the comment on `mk_main` for why we're using
// `apply_mark` directly. // `apply_mark` directly.
test.ident.span = test.ident.span.apply_mark(expn_id, Transparency::Opaque); test.ident.span =
test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
} }
self.cx.test_cases.extend(tests); self.cx.test_cases.extend(tests);
} }
@ -223,7 +224,7 @@ fn generate_test_harness(
&[sym::test, sym::rustc_attrs], &[sym::test, sym::rustc_attrs],
None, None,
); );
let def_site = DUMMY_SP.with_def_site_ctxt(expn_id); let def_site = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
// Remove the entry points // Remove the entry points
let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site }; let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site };

View File

@ -14,7 +14,7 @@ task:
- . $HOME/.cargo/env - . $HOME/.cargo/env
- git config --global user.email "user@example.com" - git config --global user.email "user@example.com"
- git config --global user.name "User" - git config --global user.name "User"
- ./prepare.sh - ./y.rs prepare
test_script: test_script:
- . $HOME/.cargo/env - . $HOME/.cargo/env
- # Enable backtraces for easier debugging - # Enable backtraces for easier debugging

View File

@ -19,6 +19,9 @@ jobs:
- os: ubuntu-latest - os: ubuntu-latest
env: env:
TARGET_TRIPLE: x86_64-pc-windows-gnu TARGET_TRIPLE: x86_64-pc-windows-gnu
- os: ubuntu-latest
env:
TARGET_TRIPLE: aarch64-unknown-linux-gnu
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -49,11 +52,19 @@ jobs:
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
rustup target add x86_64-pc-windows-gnu rustup target add x86_64-pc-windows-gnu
- name: Install AArch64 toolchain and qemu
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user
- name: Prepare dependencies - name: Prepare dependencies
run: | run: |
git config --global user.email "user@example.com" git config --global user.email "user@example.com"
git config --global user.name "User" git config --global user.name "User"
./prepare.sh ./y.rs prepare
- name: Build
run: ./y.rs build --sysroot none
- name: Test - name: Test
env: env:
@ -87,3 +98,63 @@ jobs:
with: with:
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
path: cg_clif.tar.xz path: cg_clif.tar.xz
build_windows:
runs-on: windows-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v2
#- name: Cache cargo installed crates
# uses: actions/cache@v2
# with:
# path: ~/.cargo/bin
# key: ${{ runner.os }}-cargo-installed-crates
#- name: Cache cargo registry and index
# uses: actions/cache@v2
# with:
# path: |
# ~/.cargo/registry
# ~/.cargo/git
# key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
#- name: Cache cargo target dir
# uses: actions/cache@v2
# with:
# path: target
# key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Prepare dependencies
run: |
git config --global user.email "user@example.com"
git config --global user.name "User"
git config --global core.autocrlf false
rustup set default-host x86_64-pc-windows-gnu
rustc y.rs -o y.exe -g
./y.exe prepare
- name: Build
#name: Test
run: |
# Enable backtraces for easier debugging
#export RUST_BACKTRACE=1
# Reduce amount of benchmark runs as they are slow
#export COMPILE_RUNS=2
#export RUN_RUNS=2
# Enable extra checks
#export CG_CLIF_ENABLE_VERIFIER=1
./y.exe build
#- name: Package prebuilt cg_clif
# run: tar cvfJ cg_clif.tar.xz build
#- name: Upload prebuilt cg_clif
# uses: actions/upload-artifact@v2
# with:
# name: cg_clif-${{ runner.os }}
# path: cg_clif.tar.xz

View File

@ -34,7 +34,7 @@ jobs:
run: | run: |
git config --global user.email "user@example.com" git config --global user.email "user@example.com"
git config --global user.name "User" git config --global user.name "User"
./prepare.sh ./y.rs prepare
- name: Test - name: Test
run: | run: |
@ -72,7 +72,7 @@ jobs:
run: | run: |
git config --global user.email "user@example.com" git config --global user.email "user@example.com"
git config --global user.name "User" git config --global user.name "User"
./prepare.sh ./y.rs prepare
- name: Test - name: Test
run: | run: |

View File

@ -1,7 +1,9 @@
{ {
// source for rustc_* is not included in the rust-src component; disable the errors about this // source for rustc_* is not included in the rust-src component; disable the errors about this
"rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
"rust-analyzer.assist.importMergeBehavior": "last", "rust-analyzer.assist.importGranularity": "module",
"rust-analyzer.assist.importEnforceGranularity": true,
"rust-analyzer.assist.importPrefix": "crate",
"rust-analyzer.cargo.runBuildScripts": true, "rust-analyzer.cargo.runBuildScripts": true,
"rust-analyzer.linkedProjects": [ "rust-analyzer.linkedProjects": [
"./Cargo.toml", "./Cargo.toml",
@ -49,6 +51,23 @@
"cfg": [], "cfg": [],
}, },
] ]
},
{
"roots": ["./y.rs"],
"crates": [
{
"root_module": "./y.rs",
"edition": "2018",
"deps": [{ "crate": 1, "name": "std" }],
"cfg": [],
},
{
"root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
"edition": "2018",
"deps": [],
"cfg": [],
},
]
} }
] ]
} }

View File

@ -33,16 +33,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "cranelift-bforest" name = "cranelift-bforest"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
] ]
[[package]] [[package]]
name = "cranelift-codegen" name = "cranelift-codegen"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"cranelift-bforest", "cranelift-bforest",
"cranelift-codegen-meta", "cranelift-codegen-meta",
@ -57,8 +57,8 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-meta" name = "cranelift-codegen-meta"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-entity", "cranelift-entity",
@ -66,18 +66,18 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-shared" name = "cranelift-codegen-shared"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
[[package]] [[package]]
name = "cranelift-entity" name = "cranelift-entity"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
[[package]] [[package]]
name = "cranelift-frontend" name = "cranelift-frontend"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"log", "log",
@ -87,8 +87,8 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-jit" name = "cranelift-jit"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@ -104,8 +104,8 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-module" name = "cranelift-module"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@ -115,17 +115,18 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-native" name = "cranelift-native"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"libc",
"target-lexicon", "target-lexicon",
] ]
[[package]] [[package]]
name = "cranelift-object" name = "cranelift-object"
version = "0.74.0" version = "0.75.0"
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@ -171,9 +172,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.86" version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -204,13 +205,20 @@ dependencies = [
] ]
[[package]] [[package]]
name = "object" name = "memchr"
version = "0.24.0" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "object"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"indexmap", "indexmap",
"memchr",
] ]
[[package]] [[package]]

View File

@ -9,7 +9,7 @@ crate-type = ["dylib"]
[dependencies] [dependencies]
# These have to be in sync with each other # These have to be in sync with each other
cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind"] } cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind", "all-arch"] }
cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
@ -17,7 +17,7 @@ cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", bran
cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
target-lexicon = "0.12.0" target-lexicon = "0.12.0"
gimli = { version = "0.24.0", default-features = false, features = ["write"]} gimli = { version = "0.24.0", default-features = false, features = ["write"]}
object = { version = "0.24.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } object = { version = "0.25.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.0.2" indexmap = "1.0.2"

View File

@ -10,8 +10,8 @@ If not please open an issue.
```bash ```bash
$ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git $ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git
$ cd rustc_codegen_cranelift $ cd rustc_codegen_cranelift
$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking $ ./y.rs prepare # download and patch sysroot src and install hyperfine for benchmarking
$ ./build.sh $ ./y.rs build
``` ```
To run the test suite replace the last command with: To run the test suite replace the last command with:
@ -20,7 +20,7 @@ To run the test suite replace the last command with:
$ ./test.sh $ ./test.sh
``` ```
This will implicitly build cg_clif too. Both `build.sh` and `test.sh` accept a `--debug` argument to This will implicitly build cg_clif too. Both `y.rs build` and `test.sh` accept a `--debug` argument to
build in debug mode. build in debug mode.
Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section
@ -32,12 +32,12 @@ of workflow runs. Unfortunately due to GHA restrictions you need to be logged in
rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `build.sh` or `test.sh`). Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`y.rs prepare` and `y.rs build` or `test.sh`).
In the directory with your project (where you can do the usual `cargo build`), run: In the directory with your project (where you can do the usual `cargo build`), run:
```bash ```bash
$ $cg_clif_dir/build/cargo.sh build $ $cg_clif_dir/build/cargo build
``` ```
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.

View File

@ -1,89 +0,0 @@
#!/usr/bin/env bash
set -e
# Settings
export CHANNEL="release"
build_sysroot="clif"
target_dir='build'
while [[ $# != 0 ]]; do
case $1 in
"--debug")
export CHANNEL="debug"
;;
"--sysroot")
build_sysroot=$2
shift
;;
"--target-dir")
target_dir=$2
shift
;;
*)
echo "Unknown flag '$1'"
echo "Usage: ./build.sh [--debug] [--sysroot none|clif|llvm] [--target-dir DIR]"
exit 1
;;
esac
shift
done
# Build cg_clif
unset CARGO_TARGET_DIR
unamestr=$(uname)
if [[ "$unamestr" == 'Linux' || "$unamestr" == "FreeBSD" ]]; then
export RUSTFLAGS='-Clink-arg=-Wl,-rpath=$ORIGIN/../lib '$RUSTFLAGS
elif [[ "$unamestr" == 'Darwin' ]]; then
export RUSTFLAGS='-Csplit-debuginfo=unpacked -Clink-arg=-Wl,-rpath,@loader_path/../lib -Zosx-rpath-install-name '$RUSTFLAGS
dylib_ext='dylib'
else
echo "Unsupported os $unamestr"
exit 1
fi
if [[ "$CHANNEL" == "release" ]]; then
cargo build --release
else
cargo build
fi
source scripts/ext_config.sh
rm -rf "$target_dir"
mkdir "$target_dir"
mkdir "$target_dir"/bin "$target_dir"/lib
ln target/$CHANNEL/cg_clif{,_build_sysroot} "$target_dir"/bin
ln target/$CHANNEL/*rustc_codegen_cranelift* "$target_dir"/lib
ln rust-toolchain scripts/config.sh scripts/cargo.sh "$target_dir"
mkdir -p "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/"
mkdir -p "$target_dir/lib/rustlib/$HOST_TRIPLE/lib/"
if [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
cp $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib/*.o "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/"
fi
case "$build_sysroot" in
"none")
;;
"llvm")
cp -r $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib "$target_dir/lib/rustlib/$TARGET_TRIPLE/"
if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
cp -r $(rustc --print sysroot)/lib/rustlib/$HOST_TRIPLE/lib "$target_dir/lib/rustlib/$HOST_TRIPLE/"
fi
;;
"clif")
echo "[BUILD] sysroot"
dir=$(pwd)
cd "$target_dir"
time "$dir/build_sysroot/build_sysroot.sh"
if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
time TARGET_TRIPLE="$HOST_TRIPLE" "$dir/build_sysroot/build_sysroot.sh"
fi
cp lib/rustlib/*/lib/libstd-* lib/
;;
*)
echo "Unknown sysroot kind \`$build_sysroot\`."
echo "The allowed values are:"
echo " none A sysroot that doesn't contain the standard library"
echo " llvm Copy the sysroot from rustc compiled by cg_llvm"
echo " clif Build a new sysroot using cg_clif"
exit 1
esac

View File

@ -56,7 +56,7 @@ dependencies = [
[[package]] [[package]]
name = "compiler_builtins" name = "compiler_builtins"
version = "0.1.43" version = "0.1.46"
dependencies = [ dependencies = [
"rustc-std-workspace-core", "rustc-std-workspace-core",
] ]
@ -121,9 +121,9 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.18" version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"libc", "libc",
@ -132,9 +132,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.95" version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
dependencies = [ dependencies = [
"rustc-std-workspace-core", "rustc-std-workspace-core",
] ]
@ -195,9 +195,9 @@ dependencies = [
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.19" version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-core", "rustc-std-workspace-core",

View File

@ -1,39 +0,0 @@
#!/usr/bin/env bash
# Requires the CHANNEL env var to be set to `debug` or `release.`
set -e
source ./config.sh
dir=$(pwd)
# Use rustc with cg_clif as hotpluggable backend instead of the custom cg_clif driver so that
# build scripts are still compiled using cg_llvm.
export RUSTC=$dir"/bin/cg_clif_build_sysroot"
export RUSTFLAGS=$RUSTFLAGS" --clif"
cd "$(dirname "$0")"
# Cleanup for previous run
# v Clean target dir except for build scripts and incremental cache
rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true
# We expect the target dir in the default location. Guard against the user changing it.
export CARGO_TARGET_DIR=target
# Build libs
export RUSTFLAGS="$RUSTFLAGS -Zforce-unstable-if-unmarked -Cpanic=abort"
export __CARGO_DEFAULT_LIB_METADATA="cg_clif"
if [[ "$1" != "--debug" ]]; then
sysroot_channel='release'
# FIXME Enable incremental again once rust-lang/rust#74946 is fixed
CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target "$TARGET_TRIPLE" --release
else
sysroot_channel='debug'
cargo build --target "$TARGET_TRIPLE"
fi
# Copy files to sysroot
ln "target/$TARGET_TRIPLE/$sysroot_channel/deps/"* "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"
rm "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"*.{rmeta,d}

View File

@ -1,39 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
SRC_DIR="$(dirname "$(rustup which rustc)")/../lib/rustlib/src/rust/"
DST_DIR="sysroot_src"
if [ ! -e "$SRC_DIR" ]; then
echo "Please install rust-src component"
exit 1
fi
rm -rf $DST_DIR
mkdir -p $DST_DIR/library
cp -a "$SRC_DIR/library" $DST_DIR/
pushd $DST_DIR
echo "[GIT] init"
git init
echo "[GIT] add"
git add .
echo "[GIT] commit"
git commit -m "Initial commit" -q
for file in $(ls ../../patches/ | grep -v patcha); do
echo "[GIT] apply" "$file"
git apply ../../patches/"$file"
git add -A
git commit --no-gpg-sign -m "Patch $file"
done
popd
git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
pushd compiler-builtins
git checkout -- .
git checkout 0.1.43
git apply ../../crate_patches/000*-compiler-builtins-*.patch
popd
echo "Successfully prepared sysroot source for building"

View File

@ -0,0 +1,40 @@
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
pub(crate) fn build_backend(channel: &str, host_triple: &str) -> PathBuf {
let mut cmd = Command::new("cargo");
cmd.arg("build").arg("--target").arg(host_triple);
match channel {
"debug" => {}
"release" => {
cmd.arg("--release");
}
_ => unreachable!(),
}
if cfg!(unix) {
if cfg!(target_os = "macos") {
cmd.env(
"RUSTFLAGS",
"-Csplit-debuginfo=unpacked \
-Clink-arg=-Wl,-rpath,@loader_path/../lib \
-Zosx-rpath-install-name"
.to_string()
+ env::var("RUSTFLAGS").as_deref().unwrap_or(""),
);
} else {
cmd.env(
"RUSTFLAGS",
"-Clink-arg=-Wl,-rpath=$ORIGIN/../lib ".to_string()
+ env::var("RUSTFLAGS").as_deref().unwrap_or(""),
);
}
}
eprintln!("[BUILD] rustc_codegen_cranelift");
crate::utils::spawn_and_wait(cmd);
Path::new("target").join(host_triple).join(channel)
}

View File

@ -0,0 +1,216 @@
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use crate::rustc_info::{get_file_name, get_rustc_version};
use crate::utils::{spawn_and_wait, try_hard_link};
use crate::SysrootKind;
pub(crate) fn build_sysroot(
channel: &str,
sysroot_kind: SysrootKind,
target_dir: &Path,
cg_clif_build_dir: PathBuf,
host_triple: &str,
target_triple: &str,
) {
if target_dir.exists() {
fs::remove_dir_all(target_dir).unwrap();
}
fs::create_dir_all(target_dir.join("bin")).unwrap();
fs::create_dir_all(target_dir.join("lib")).unwrap();
// Copy the backend
for file in ["cg_clif", "cg_clif_build_sysroot"] {
try_hard_link(
cg_clif_build_dir.join(get_file_name(file, "bin")),
target_dir.join("bin").join(get_file_name(file, "bin")),
);
}
let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib");
try_hard_link(
cg_clif_build_dir.join(&cg_clif_dylib),
target_dir
.join(if cfg!(windows) {
// Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
// binaries.
"bin"
} else {
"lib"
})
.join(cg_clif_dylib),
);
// Build and copy cargo wrapper
let mut build_cargo_wrapper_cmd = Command::new("rustc");
build_cargo_wrapper_cmd
.arg("scripts/cargo.rs")
.arg("-o")
.arg(target_dir.join("cargo"))
.arg("-g");
spawn_and_wait(build_cargo_wrapper_cmd);
let default_sysroot = crate::rustc_info::get_default_sysroot();
let rustlib = target_dir.join("lib").join("rustlib");
let host_rustlib_lib = rustlib.join(host_triple).join("lib");
let target_rustlib_lib = rustlib.join(target_triple).join("lib");
fs::create_dir_all(&host_rustlib_lib).unwrap();
fs::create_dir_all(&target_rustlib_lib).unwrap();
if target_triple == "x86_64-pc-windows-gnu" {
if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() {
eprintln!(
"The x86_64-pc-windows-gnu target needs to be installed first before it is possible \
to compile a sysroot for it.",
);
process::exit(1);
}
for file in fs::read_dir(
default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
)
.unwrap()
{
let file = file.unwrap().path();
if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") {
continue; // only copy object files
}
try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
}
}
match sysroot_kind {
SysrootKind::None => {} // Nothing to do
SysrootKind::Llvm => {
for file in fs::read_dir(
default_sysroot.join("lib").join("rustlib").join(host_triple).join("lib"),
)
.unwrap()
{
let file = file.unwrap().path();
let file_name_str = file.file_name().unwrap().to_str().unwrap();
if file_name_str.contains("rustc_")
|| file_name_str.contains("chalk")
|| file_name_str.contains("tracing")
|| file_name_str.contains("regex")
{
// These are large crates that are part of the rustc-dev component and are not
// necessary to run regular programs.
continue;
}
try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap()));
}
if target_triple != host_triple {
for file in fs::read_dir(
default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
)
.unwrap()
{
let file = file.unwrap().path();
try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
}
}
}
SysrootKind::Clif => {
build_clif_sysroot_for_triple(channel, target_dir, host_triple, None);
if host_triple != target_triple {
// When cross-compiling it is often necessary to manually pick the right linker
let linker = if target_triple == "aarch64-unknown-linux-gnu" {
Some("aarch64-linux-gnu-gcc")
} else {
None
};
build_clif_sysroot_for_triple(channel, target_dir, target_triple, linker);
}
// Copy std for the host to the lib dir. This is necessary for the jit mode to find
// libstd.
for file in fs::read_dir(host_rustlib_lib).unwrap() {
let file = file.unwrap().path();
if file.file_name().unwrap().to_str().unwrap().contains("std-") {
try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
}
}
}
}
}
fn build_clif_sysroot_for_triple(
channel: &str,
target_dir: &Path,
triple: &str,
linker: Option<&str>,
) {
match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
Err(e) => {
eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
process::exit(1);
}
Ok(source_version) => {
let rustc_version = get_rustc_version();
if source_version != rustc_version {
eprintln!("The patched sysroot source is outdated");
eprintln!("Source version: {}", source_version.trim());
eprintln!("Rustc version: {}", rustc_version.trim());
eprintln!("Hint: Try `./y.rs prepare` to update the patched sysroot source");
process::exit(1);
}
}
}
let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
if !crate::config::get_bool("keep_sysroot") {
// Cleanup the target dir with the exception of build scripts and the incremental cache
for dir in ["build", "deps", "examples", "native"] {
if build_dir.join(dir).exists() {
fs::remove_dir_all(build_dir.join(dir)).unwrap();
}
}
}
// Build sysroot
let mut build_cmd = Command::new("cargo");
build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot");
let mut rustflags = "--clif -Zforce-unstable-if-unmarked".to_string();
if channel == "release" {
build_cmd.arg("--release");
rustflags.push_str(" -Zmir-opt-level=3");
}
if let Some(linker) = linker {
use std::fmt::Write;
write!(rustflags, " -Clinker={}", linker).unwrap();
}
build_cmd.env("RUSTFLAGS", rustflags);
build_cmd.env(
"RUSTC",
env::current_dir().unwrap().join(target_dir).join("bin").join("cg_clif_build_sysroot"),
);
// FIXME Enable incremental again once rust-lang/rust#74946 is fixed
build_cmd.env("CARGO_INCREMENTAL", "0").env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
spawn_and_wait(build_cmd);
// Copy all relevant files to the sysroot
for entry in
fs::read_dir(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
.unwrap()
{
let entry = entry.unwrap();
if let Some(ext) = entry.path().extension() {
if ext == "rmeta" || ext == "d" || ext == "dSYM" {
continue;
}
} else {
continue;
};
try_hard_link(
entry.path(),
target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),
);
}
}

View File

@ -0,0 +1,55 @@
use std::{fs, process};
fn load_config_file() -> Vec<(String, Option<String>)> {
fs::read_to_string("config.txt")
.unwrap()
.lines()
.map(|line| if let Some((line, _comment)) = line.split_once('#') { line } else { line })
.map(|line| line.trim())
.filter(|line| !line.is_empty())
.map(|line| {
if let Some((key, val)) = line.split_once('=') {
(key.trim().to_owned(), Some(val.trim().to_owned()))
} else {
(line.to_owned(), None)
}
})
.collect()
}
pub(crate) fn get_bool(name: &str) -> bool {
let values = load_config_file()
.into_iter()
.filter(|(key, _)| key == name)
.map(|(_, val)| val)
.collect::<Vec<_>>();
if values.is_empty() {
false
} else {
if values.iter().any(|val| val.is_some()) {
eprintln!("Boolean config `{}` has a value", name);
process::exit(1);
}
true
}
}
pub(crate) fn get_value(name: &str) -> Option<String> {
let values = load_config_file()
.into_iter()
.filter(|(key, _)| key == name)
.map(|(_, val)| val)
.collect::<Vec<_>>();
if values.is_empty() {
None
} else if values.len() == 1 {
if values[0].is_none() {
eprintln!("Config `{}` missing value", name);
process::exit(1);
}
values.into_iter().next().unwrap()
} else {
eprintln!("Config `{}` given multiple values: {:?}", name, values);
process::exit(1);
}
}

View File

@ -0,0 +1,133 @@
use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs;
use std::path::Path;
use std::process::Command;
use crate::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
use crate::utils::{copy_dir_recursively, spawn_and_wait};
pub(crate) fn prepare() {
prepare_sysroot();
eprintln!("[INSTALL] hyperfine");
Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
clone_repo(
"rand",
"https://github.com/rust-random/rand.git",
"0f933f9c7176e53b2a3c7952ded484e1783f0bf1",
);
apply_patches("rand", Path::new("rand"));
clone_repo(
"regex",
"https://github.com/rust-lang/regex.git",
"341f207c1071f7290e3f228c710817c280c8dca1",
);
clone_repo(
"simple-raytracer",
"https://github.com/ebobby/simple-raytracer",
"804a7a21b9e673a482797aa289a18ed480e4d813",
);
eprintln!("[LLVM BUILD] simple-raytracer");
let mut build_cmd = Command::new("cargo");
build_cmd.arg("build").env_remove("CARGO_TARGET_DIR").current_dir("simple-raytracer");
spawn_and_wait(build_cmd);
fs::copy(
Path::new("simple-raytracer/target/debug").join(get_file_name("main", "bin")),
// FIXME use get_file_name here too once testing is migrated to rust
"simple-raytracer/raytracer_cg_llvm",
)
.unwrap();
}
fn prepare_sysroot() {
let rustc_path = get_rustc_path();
let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
let sysroot_src = env::current_dir().unwrap().join("build_sysroot").join("sysroot_src");
assert!(sysroot_src_orig.exists());
if sysroot_src.exists() {
fs::remove_dir_all(&sysroot_src).unwrap();
}
fs::create_dir_all(sysroot_src.join("library")).unwrap();
eprintln!("[COPY] sysroot src");
copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
let rustc_version = get_rustc_version();
fs::write(
Path::new("build_sysroot").join("rustc_version"),
&rustc_version,
)
.unwrap();
eprintln!("[GIT] init");
let mut git_init_cmd = Command::new("git");
git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
spawn_and_wait(git_init_cmd);
let mut git_add_cmd = Command::new("git");
git_add_cmd.arg("add").arg(".").current_dir(&sysroot_src);
spawn_and_wait(git_add_cmd);
let mut git_commit_cmd = Command::new("git");
git_commit_cmd
.arg("commit")
.arg("-m")
.arg("Initial commit")
.arg("-q")
.current_dir(&sysroot_src);
spawn_and_wait(git_commit_cmd);
apply_patches("sysroot", &sysroot_src);
clone_repo(
"build_sysroot/compiler-builtins",
"https://github.com/rust-lang/compiler-builtins.git",
"0.1.46",
);
apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins"));
}
fn clone_repo(target_dir: &str, repo: &str, rev: &str) {
eprintln!("[CLONE] {}", repo);
// Ignore exit code as the repo may already have been checked out
Command::new("git").arg("clone").arg(repo).arg(target_dir).spawn().unwrap().wait().unwrap();
let mut clean_cmd = Command::new("git");
clean_cmd.arg("checkout").arg("--").arg(".").current_dir(target_dir);
spawn_and_wait(clean_cmd);
let mut checkout_cmd = Command::new("git");
checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(target_dir);
spawn_and_wait(checkout_cmd);
}
fn get_patches(crate_name: &str) -> Vec<OsString> {
let mut patches: Vec<_> = fs::read_dir("patches")
.unwrap()
.map(|entry| entry.unwrap().path())
.filter(|path| path.extension() == Some(OsStr::new("patch")))
.map(|path| path.file_name().unwrap().to_owned())
.filter(|file_name| {
file_name.to_str().unwrap().split_once("-").unwrap().1.starts_with(crate_name)
})
.collect();
patches.sort();
patches
}
fn apply_patches(crate_name: &str, target_dir: &Path) {
for patch in get_patches(crate_name) {
eprintln!("[PATCH] {:?} <- {:?}", target_dir.file_name().unwrap(), patch);
let patch_arg = env::current_dir().unwrap().join("patches").join(patch);
let mut apply_patch_cmd = Command::new("git");
apply_patch_cmd.arg("am").arg(patch_arg).arg("-q").current_dir(target_dir);
spawn_and_wait(apply_patch_cmd);
}
}

View File

@ -0,0 +1,65 @@
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
pub(crate) fn get_rustc_version() -> String {
let version_info =
Command::new("rustc").stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
String::from_utf8(version_info).unwrap()
}
pub(crate) fn get_host_triple() -> String {
let version_info =
Command::new("rustc").stderr(Stdio::inherit()).args(&["-vV"]).output().unwrap().stdout;
String::from_utf8(version_info)
.unwrap()
.lines()
.to_owned()
.find(|line| line.starts_with("host"))
.unwrap()
.split(":")
.nth(1)
.unwrap()
.trim()
.to_owned()
}
pub(crate) fn get_rustc_path() -> PathBuf {
let rustc_path = Command::new("rustup")
.stderr(Stdio::inherit())
.args(&["which", "rustc"])
.output()
.unwrap()
.stdout;
Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
}
pub(crate) fn get_default_sysroot() -> PathBuf {
let default_sysroot = Command::new("rustc")
.stderr(Stdio::inherit())
.args(&["--print", "sysroot"])
.output()
.unwrap()
.stdout;
Path::new(String::from_utf8(default_sysroot).unwrap().trim()).to_owned()
}
pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
let file_name = Command::new("rustc")
.stderr(Stdio::inherit())
.args(&[
"--crate-name",
crate_name,
"--crate-type",
crate_type,
"--print",
"file-names",
"-",
])
.output()
.unwrap()
.stdout;
let file_name = String::from_utf8(file_name).unwrap().trim().to_owned();
assert!(!file_name.contains('\n'));
assert!(file_name.contains(crate_name));
file_name
}

View File

@ -0,0 +1,35 @@
use std::fs;
use std::path::Path;
use std::process::{self, Command};
#[track_caller]
pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
let src = src.as_ref();
let dst = dst.as_ref();
if let Err(_) = fs::hard_link(src, dst) {
fs::copy(src, dst).unwrap(); // Fallback to copying if hardlinking failed
}
}
#[track_caller]
pub(crate) fn spawn_and_wait(mut cmd: Command) {
if !cmd.spawn().unwrap().wait().unwrap().success() {
process::exit(1);
}
}
pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
for entry in fs::read_dir(from).unwrap() {
let entry = entry.unwrap();
let filename = entry.file_name();
if filename == "." || filename == ".." {
continue;
}
if entry.metadata().unwrap().is_dir() {
fs::create_dir(to.join(&filename)).unwrap();
copy_dir_recursively(&from.join(&filename), &to.join(&filename));
} else {
fs::copy(from.join(&filename), to.join(&filename)).unwrap();
}
}
}

View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
rm -rf target/ build/ build_sysroot/{sysroot_src/,target/,compiler-builtins/} perf.data{,.old} rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
rm -rf target/ build/ perf.data{,.old}
rm -rf rand/ regex/ simple-raytracer/ rm -rf rand/ regex/ simple-raytracer/

View File

@ -0,0 +1,17 @@
# This file allows configuring the build system.
# Which triple to produce a compiler toolchain for.
#
# Defaults to the default triple of rustc on the host system.
#host = x86_64-unknown-linux-gnu
# Which triple to build libraries (core/alloc/std/test/proc_macro) for.
#
# Defaults to `host`.
#target = x86_64-unknown-linux-gnu
# Disables cleaning of the sysroot dir. This will cause old compiled artifacts to be re-used when
# the sysroot source hasn't changed. This is useful when the codegen backend hasn't been modified.
# This option can be changed while the build system is already running for as long as sysroot
# building hasn't started yet.
#keep_sysroot

View File

@ -2,14 +2,14 @@
rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `build.sh` or `test.sh`). Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`y.rs prepare` and `y.rs build` or `test.sh`).
## Cargo ## Cargo
In the directory with your project (where you can do the usual `cargo build`), run: In the directory with your project (where you can do the usual `cargo build`), run:
```bash ```bash
$ $cg_clif_dir/build/cargo.sh build $ $cg_clif_dir/build/cargo build
``` ```
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
@ -30,7 +30,7 @@ In jit mode cg_clif will immediately execute your code without creating an execu
> The jit mode will probably need cargo integration to make this possible. > The jit mode will probably need cargo integration to make this possible.
```bash ```bash
$ $cg_clif_dir/build/cargo.sh jit $ $cg_clif_dir/build/cargo jit
``` ```
or or
@ -40,11 +40,10 @@ $ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.
``` ```
There is also an experimental lazy jit mode. In this mode functions are only compiled once they are There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
first called. It currently does not work with multi-threaded programs. When a not yet compiled first called.
function is called from another thread than the main thread, you will get an ICE.
```bash ```bash
$ $cg_clif_dir/build/cargo.sh lazy-jit $ $cg_clif_dir/build/cargo lazy-jit
``` ```
## Shell ## Shell

View File

@ -292,7 +292,7 @@ fn main() {
#[cfg(not(any(jit, windows)))] #[cfg(not(any(jit, windows)))]
test_tls(); test_tls();
#[cfg(all(not(jit), target_os = "linux"))] #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
unsafe { unsafe {
global_asm_test(); global_asm_test();
} }
@ -303,12 +303,12 @@ fn main() {
assert_eq!(*REF1, *REF2); assert_eq!(*REF1, *REF2);
} }
#[cfg(all(not(jit), target_os = "linux"))] #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
extern "C" { extern "C" {
fn global_asm_test(); fn global_asm_test();
} }
#[cfg(all(not(jit), target_os = "linux"))] #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
global_asm! { global_asm! {
" "
.global global_asm_test .global global_asm_test

View File

@ -15,8 +15,6 @@ fn main() {
let stderr = ::std::io::stderr(); let stderr = ::std::io::stderr();
let mut stderr = stderr.lock(); let mut stderr = stderr.lock();
// FIXME support lazy jit when multi threading
#[cfg(not(lazy_jit))]
std::thread::spawn(move || { std::thread::spawn(move || {
println!("Hello from another thread!"); println!("Hello from another thread!");
}); });

View File

@ -1,29 +0,0 @@
#!/usr/bin/env bash
set -e
./build_sysroot/prepare_sysroot_src.sh
cargo install hyperfine || echo "Skipping hyperfine install"
git clone https://github.com/rust-random/rand.git || echo "rust-random/rand has already been cloned"
pushd rand
git checkout -- .
git checkout 0f933f9c7176e53b2a3c7952ded484e1783f0bf1
git am ../crate_patches/*-rand-*.patch
popd
git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned"
pushd regex
git checkout -- .
git checkout 341f207c1071f7290e3f228c710817c280c8dca1
popd
git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned"
pushd simple-raytracer
git checkout -- .
git checkout 804a7a21b9e673a482797aa289a18ed480e4d813
# build with cg_llvm for perf comparison
unset CARGO_TARGET_DIR
cargo build
mv target/debug/main raytracer_cg_llvm
popd

View File

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2021-05-26" channel = "nightly-2021-07-07"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"] components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View File

@ -0,0 +1,70 @@
use std::env;
#[cfg(unix)]
use std::os::unix::process::CommandExt;
use std::path::PathBuf;
use std::process::Command;
fn main() {
if env::var("RUSTC_WRAPPER").map_or(false, |wrapper| wrapper.contains("sccache")) {
eprintln!(
"\x1b[1;93m=== Warning: Unsetting RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m"
);
env::remove_var("RUSTC_WRAPPER");
}
let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
env::set_var("RUSTC", sysroot.join("bin/cg_clif".to_string() + env::consts::EXE_SUFFIX));
let mut rustdoc_flags = env::var("RUSTDOCFLAGS").unwrap_or(String::new());
rustdoc_flags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
rustdoc_flags.push_str(
sysroot
.join(if cfg!(windows) { "bin" } else { "lib" })
.join(
env::consts::DLL_PREFIX.to_string()
+ "rustc_codegen_cranelift"
+ env::consts::DLL_SUFFIX,
)
.to_str()
.unwrap(),
);
rustdoc_flags.push_str(" --sysroot ");
rustdoc_flags.push_str(sysroot.to_str().unwrap());
env::set_var("RUSTDOCFLAGS", rustdoc_flags);
// Ensure that the right toolchain is used
env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
let args: Vec<_> = match env::args().nth(1).as_deref() {
Some("jit") => {
env::set_var(
"RUSTFLAGS",
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
);
std::array::IntoIter::new(["rustc".to_string()])
.chain(env::args().skip(2))
.chain(["--".to_string(), "-Cllvm-args=mode=jit".to_string()])
.collect()
}
Some("lazy-jit") => {
env::set_var(
"RUSTFLAGS",
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
);
std::array::IntoIter::new(["rustc".to_string()])
.chain(env::args().skip(2))
.chain(["--".to_string(), "-Cllvm-args=mode=jit-lazy".to_string()])
.collect()
}
_ => env::args().skip(1).collect(),
};
#[cfg(unix)]
Command::new("cargo").args(args).exec();
#[cfg(not(unix))]
std::process::exit(
Command::new("cargo").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
);
}

View File

@ -1,18 +0,0 @@
#!/usr/bin/env bash
dir=$(dirname "$0")
source "$dir/config.sh"
# read nightly compiler from rust-toolchain file
TOOLCHAIN=$(cat "$dir/rust-toolchain" | grep channel | sed "s/channel = \"\(.*\)\"/\1/")
cmd=$1
shift || true
if [[ "$cmd" = "jit" ]]; then
cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit -Cprefer-dynamic
elif [[ "$cmd" = "lazy-jit" ]]; then
cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit-lazy -Cprefer-dynamic
else
cargo "+${TOOLCHAIN}" "$cmd" "$@"
fi

View File

@ -2,26 +2,5 @@
set -e set -e
dylib=$(echo "" | rustc --print file-names --crate-type dylib --crate-name rustc_codegen_cranelift -) export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH"
if echo "$RUSTC_WRAPPER" | grep sccache; then
echo
echo -e "\x1b[1;93m=== Warning: Unset RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m"
echo
export RUSTC_WRAPPER=
fi
dir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)
export RUSTC=$dir"/bin/cg_clif"
export RUSTDOCFLAGS=$linker' -Cpanic=abort -Zpanic-abort-tests '\
'-Zcodegen-backend='$dir'/lib/'$dylib' --sysroot '$dir
# FIXME fix `#[linkage = "extern_weak"]` without this
if [[ "$(uname)" == 'Darwin' ]]; then
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
fi
export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:"$dir"/lib"
export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH

View File

@ -1,6 +1,6 @@
# Note to people running shellcheck: this file should only be sourced, not executed directly. # Note to people running shellcheck: this file should only be sourced, not executed directly.
# Various env vars that should only be set for the build system but not for cargo.sh # Various env vars that should only be set for the build system
set -e set -e
@ -25,3 +25,8 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
echo "Unknown non-native platform" echo "Unknown non-native platform"
fi fi
fi fi
# FIXME fix `#[linkage = "extern_weak"]` without this
if [[ "$(uname)" == 'Darwin' ]]; then
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
fi

View File

@ -2,9 +2,10 @@
#![forbid(unsafe_code)]/* This line is ignored by bash #![forbid(unsafe_code)]/* This line is ignored by bash
# This block is ignored by rustc # This block is ignored by rustc
pushd $(dirname "$0")/../ pushd $(dirname "$0")/../
source build/config.sh source scripts/config.sh
RUSTC="$(pwd)/build/bin/cg_clif"
popd popd
PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS -Cllvm-args=mode=jit -Cprefer-dynamic $0 PROFILE=$1 OUTPUT=$2 exec $RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/ #*/
//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse //! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse

View File

@ -17,7 +17,7 @@ case $1 in
done done
./clean_all.sh ./clean_all.sh
./prepare.sh ./y.rs prepare
(cd build_sysroot && cargo update) (cd build_sysroot && cargo update)

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
set -e set -e
./build.sh ./y.rs build
source build/config.sh source scripts/config.sh
echo "[SETUP] Rust fork" echo "[SETUP] Rust fork"
git clone https://github.com/rust-lang/rust.git || true git clone https://github.com/rust-lang/rust.git || true
@ -33,7 +33,7 @@ index d95b5b7f17f..00b6f0e3635 100644
[dependencies] [dependencies]
core = { path = "../core" } core = { path = "../core" }
-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.43", features = ['rustc-dep-of-std', 'no-asm'] } +compiler_builtins = { version = "0.1.45", features = ['rustc-dep-of-std', 'no-asm'] }
[dev-dependencies] [dev-dependencies]
rand = "0.7" rand = "0.7"

View File

@ -38,7 +38,8 @@ rm src/test/ui/threads-sendsync/task-stderr.rs
rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs
rm src/test/ui/drop/drop-trait-enum.rs rm src/test/ui/drop/drop-trait-enum.rs
rm src/test/ui/numbers-arithmetic/issue-8460.rs rm src/test/ui/numbers-arithmetic/issue-8460.rs
rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind rm src/test/ui/rt-explody-panic-payloads.rs
rm src/test/incremental/change_crate_dep_kind.rs
rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
rm src/test/ui/init-large-type.rs # same rm src/test/ui/init-large-type.rs # same
@ -64,6 +65,7 @@ rm src/test/incremental/lto.rs # requires lto
rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/ rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
rm -r src/test/run-make/unstable-flag-required # same rm -r src/test/run-make/unstable-flag-required # same
rm -r src/test/run-make/emit-named-files # requires full --emit support
rm src/test/pretty/asm.rs # inline asm rm src/test/pretty/asm.rs # inline asm
rm src/test/pretty/raw-str-nonexpr.rs # same rm src/test/pretty/raw-str-nonexpr.rs # same

View File

@ -2,9 +2,10 @@
set -e set -e
source build/config.sh source scripts/config.sh
source scripts/ext_config.sh source scripts/ext_config.sh
MY_RUSTC="$RUSTC $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2" export RUSTC=false # ensure that cg_llvm isn't accidentally used
MY_RUSTC="$(pwd)/build/bin/cg_clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
function no_sysroot_tests() { function no_sysroot_tests() {
echo "[BUILD] mini_core" echo "[BUILD] mini_core"
@ -46,7 +47,7 @@ function base_sysroot_tests() {
$MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE" $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
echo "[JIT-lazy] std_example" echo "[JIT-lazy] std_example"
$MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --cfg lazy_jit --target "$HOST_TRIPLE" $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
else else
echo "[JIT] std_example (skipped)" echo "[JIT] std_example (skipped)"
fi fi
@ -75,63 +76,64 @@ function base_sysroot_tests() {
function extended_sysroot_tests() { function extended_sysroot_tests() {
pushd rand pushd rand
cargo clean ../build/cargo clean
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
echo "[TEST] rust-random/rand" echo "[TEST] rust-random/rand"
../build/cargo.sh test --workspace ../build/cargo test --workspace
else else
echo "[AOT] rust-random/rand" echo "[AOT] rust-random/rand"
../build/cargo.sh build --workspace --target $TARGET_TRIPLE --tests ../build/cargo build --workspace --target $TARGET_TRIPLE --tests
fi fi
popd popd
pushd simple-raytracer pushd simple-raytracer
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
echo "[BENCH COMPILE] ebobby/simple-raytracer" echo "[BENCH COMPILE] ebobby/simple-raytracer"
hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \ hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo clean" \
"RUSTC=rustc RUSTFLAGS='' cargo build" \ "RUSTC=rustc RUSTFLAGS='' cargo build" \
"../build/cargo.sh build" "../build/cargo build"
echo "[BENCH RUN] ebobby/simple-raytracer" echo "[BENCH RUN] ebobby/simple-raytracer"
cp ./target/debug/main ./raytracer_cg_clif cp ./target/debug/main ./raytracer_cg_clif
hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif
else else
../build/cargo clean
echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
echo "[COMPILE] ebobby/simple-raytracer" echo "[COMPILE] ebobby/simple-raytracer"
../build/cargo.sh build --target $TARGET_TRIPLE ../build/cargo build --target $TARGET_TRIPLE
echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
fi fi
popd popd
pushd build_sysroot/sysroot_src/library/core/tests pushd build_sysroot/sysroot_src/library/core/tests
echo "[TEST] libcore" echo "[TEST] libcore"
cargo clean ../../../../../build/cargo clean
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
../../../../../build/cargo.sh test ../../../../../build/cargo test
else else
../../../../../build/cargo.sh build --target $TARGET_TRIPLE --tests ../../../../../build/cargo build --target $TARGET_TRIPLE --tests
fi fi
popd popd
pushd regex pushd regex
echo "[TEST] rust-lang/regex example shootout-regex-dna" echo "[TEST] rust-lang/regex example shootout-regex-dna"
cargo clean ../build/cargo clean
export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
# Make sure `[codegen mono items] start` doesn't poison the diff # Make sure `[codegen mono items] start` doesn't poison the diff
../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE ../build/cargo build --example shootout-regex-dna --target $TARGET_TRIPLE
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
cat examples/regexdna-input.txt \ cat examples/regexdna-input.txt \
| ../build/cargo.sh run --example shootout-regex-dna --target $TARGET_TRIPLE \ | ../build/cargo run --example shootout-regex-dna --target $TARGET_TRIPLE \
| grep -v "Spawned thread" > res.txt | grep -v "Spawned thread" > res.txt
diff -u res.txt examples/regexdna-output.txt diff -u res.txt examples/regexdna-output.txt
fi fi
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
echo "[TEST] rust-lang/regex tests" echo "[TEST] rust-lang/regex tests"
../build/cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q ../build/cargo test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
else else
echo "[AOT] rust-lang/regex tests" echo "[AOT] rust-lang/regex tests"
../build/cargo.sh build --tests --target $TARGET_TRIPLE ../build/cargo build --tests --target $TARGET_TRIPLE
fi fi
popd popd
} }

View File

@ -19,7 +19,7 @@ pub(crate) fn codegen(
}); });
if any_dynamic_crate { if any_dynamic_crate {
false false
} else if let Some(kind) = tcx.allocator_kind() { } else if let Some(kind) = tcx.allocator_kind(()) {
codegen_inner(module, unwind_context, kind); codegen_inner(module, unwind_context, kind);
true true
} else { } else {

View File

@ -21,6 +21,11 @@ pub(crate) fn codegen_fn<'tcx>(
debug_assert!(!instance.substs.needs_infer()); debug_assert!(!instance.substs.needs_infer());
let mir = tcx.instance_mir(instance.def); let mir = tcx.instance_mir(instance.def);
let _mir_guard = crate::PrintOnPanic(|| {
let mut buf = Vec::new();
rustc_mir::util::write_mir_pretty(tcx, Some(instance.def_id()), &mut buf).unwrap();
String::from_utf8_lossy(&buf).into_owned()
});
// Declare function // Declare function
let symbol_name = tcx.symbol_name(instance); let symbol_name = tcx.symbol_name(instance);
@ -52,7 +57,6 @@ pub(crate) fn codegen_fn<'tcx>(
module, module,
tcx, tcx,
pointer_type, pointer_type,
vtables: FxHashMap::default(),
constants_cx: ConstantCx::new(), constants_cx: ConstantCx::new(),
instance, instance,
@ -105,7 +109,14 @@ pub(crate) fn codegen_fn<'tcx>(
let context = &mut cx.cached_context; let context = &mut cx.cached_context;
context.func = func; context.func = func;
crate::pretty_clif::write_clif_file(tcx, "unopt", None, instance, &context, &clif_comments); crate::pretty_clif::write_clif_file(
tcx,
"unopt",
module.isa(),
instance,
&context,
&clif_comments,
);
// Verify function // Verify function
verify_func(tcx, &clif_comments, &context.func); verify_func(tcx, &clif_comments, &context.func);
@ -122,7 +133,13 @@ pub(crate) fn codegen_fn<'tcx>(
// Perform rust specific optimizations // Perform rust specific optimizations
tcx.sess.time("optimize clif ir", || { tcx.sess.time("optimize clif ir", || {
crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments); crate::optimize::optimize_function(
tcx,
module.isa(),
instance,
context,
&mut clif_comments,
);
}); });
// Define function // Define function
@ -137,7 +154,7 @@ pub(crate) fn codegen_fn<'tcx>(
crate::pretty_clif::write_clif_file( crate::pretty_clif::write_clif_file(
tcx, tcx,
"opt", "opt",
Some(module.isa()), module.isa(),
instance, instance,
&context, &context,
&clif_comments, &clif_comments,

View File

@ -1,4 +1,4 @@
#![feature(rustc_private)] #![feature(rustc_private, once_cell)]
extern crate rustc_data_structures; extern crate rustc_data_structures;
extern crate rustc_driver; extern crate rustc_driver;
@ -6,12 +6,33 @@ extern crate rustc_interface;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_target; extern crate rustc_target;
use std::lazy::SyncLazy;
use std::panic;
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_interface::interface; use rustc_interface::interface;
use rustc_session::config::ErrorOutputType; use rustc_session::config::ErrorOutputType;
use rustc_session::early_error; use rustc_session::early_error;
use rustc_target::spec::PanicStrategy; use rustc_target::spec::PanicStrategy;
const BUG_REPORT_URL: &str = "https://github.com/bjorn3/rustc_codegen_cranelift/issues/new";
static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
SyncLazy::new(|| {
let hook = panic::take_hook();
panic::set_hook(Box::new(|info| {
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
(*DEFAULT_HOOK)(info);
// Separate the output with an empty line
eprintln!();
// Print the ICE message
rustc_driver::report_ice(info, BUG_REPORT_URL);
}));
hook
});
#[derive(Default)] #[derive(Default)]
pub struct CraneliftPassesCallbacks { pub struct CraneliftPassesCallbacks {
time_passes: bool, time_passes: bool,
@ -37,7 +58,7 @@ fn main() {
let start_rss = get_resident_set_size(); let start_rss = get_resident_set_size();
rustc_driver::init_rustc_env_logger(); rustc_driver::init_rustc_env_logger();
let mut callbacks = CraneliftPassesCallbacks::default(); let mut callbacks = CraneliftPassesCallbacks::default();
rustc_driver::install_ice_hook(); SyncLazy::force(&DEFAULT_HOOK); // Install ice hook
let exit_code = rustc_driver::catch_with_exit_code(|| { let exit_code = rustc_driver::catch_with_exit_code(|| {
let args = std::env::args_os() let args = std::env::args_os()
.enumerate() .enumerate()

View File

@ -233,7 +233,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
pub(crate) module: &'m mut dyn Module, pub(crate) module: &'m mut dyn Module,
pub(crate) tcx: TyCtxt<'tcx>, pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) pointer_type: Type, // Cached from module pub(crate) pointer_type: Type, // Cached from module
pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
pub(crate) constants_cx: ConstantCx, pub(crate) constants_cx: ConstantCx,
pub(crate) instance: Instance<'tcx>, pub(crate) instance: Instance<'tcx>,

View File

@ -7,7 +7,7 @@ macro builtin_functions($register:ident; $(fn $name:ident($($arg_name:ident: $ar
#[cfg(feature = "jit")] #[cfg(feature = "jit")]
pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) { pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) {
for &(name, val) in &[$((stringify!($name), $name as *const u8)),*] { for (name, val) in [$((stringify!($name), $name as *const u8)),*] {
builder.symbol(name, val); builder.symbol(name, val);
} }
} }

View File

@ -1,16 +1,13 @@
//! Handling of `static`s, `const`s and promoted allocations //! Handling of `static`s, `const`s and promoted allocations
use rustc_span::DUMMY_SP;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{ use rustc_middle::mir::interpret::{
alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
Scalar,
}; };
use rustc_middle::ty::ConstKind; use rustc_middle::ty::ConstKind;
use rustc_span::DUMMY_SP;
use cranelift_codegen::ir::GlobalValueData; use cranelift_codegen::ir::GlobalValueData;
use cranelift_module::*; use cranelift_module::*;
@ -171,66 +168,75 @@ pub(crate) fn codegen_const_value<'tcx>(
} }
match const_val { match const_val {
ConstValue::Scalar(x) => { ConstValue::Scalar(x) => match x {
if fx.clif_type(layout.ty).is_none() { Scalar::Int(int) => {
let (size, align) = (layout.size, layout.align.pref); if fx.clif_type(layout.ty).is_some() {
let mut alloc = Allocation::from_bytes( return CValue::const_val(fx, layout, int);
std::iter::repeat(0).take(size.bytes_usize()).collect::<Vec<u8>>(), } else {
align, let raw_val = int.to_bits(int.size()).unwrap();
Mutability::Not, let val = match int.size().bytes() {
); 1 => fx.bcx.ins().iconst(types::I8, raw_val as i64),
alloc.write_scalar(fx, alloc_range(Size::ZERO, size), x.into()).unwrap(); 2 => fx.bcx.ins().iconst(types::I16, raw_val as i64),
let alloc = fx.tcx.intern_const_alloc(alloc); 4 => fx.bcx.ins().iconst(types::I32, raw_val as i64),
return CValue::by_ref(pointer_for_allocation(fx, alloc), layout); 8 => fx.bcx.ins().iconst(types::I64, raw_val as i64),
} 16 => {
let lsb = fx.bcx.ins().iconst(types::I64, raw_val as u64 as i64);
let msb =
fx.bcx.ins().iconst(types::I64, (raw_val >> 64) as u64 as i64);
fx.bcx.ins().iconcat(lsb, msb)
}
_ => unreachable!(),
};
match x { let place = CPlace::new_stack_slot(fx, layout);
Scalar::Int(int) => CValue::const_val(fx, layout, int), place.to_ptr().store(fx, val, MemFlags::trusted());
Scalar::Ptr(ptr) => { place.to_cvalue(fx)
let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id);
let base_addr = match alloc_kind {
Some(GlobalAlloc::Memory(alloc)) => {
fx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
let data_id = data_id_for_alloc_id(
&mut fx.constants_cx,
fx.module,
ptr.alloc_id,
alloc.mutability,
);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id));
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
Some(GlobalAlloc::Function(instance)) => {
let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
let local_func_id =
fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
}
Some(GlobalAlloc::Static(def_id)) => {
assert!(fx.tcx.is_static(def_id));
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", def_id));
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
None => bug!("missing allocation {:?}", ptr.alloc_id),
};
let val = if ptr.offset.bytes() != 0 {
fx.bcx.ins().iadd_imm(base_addr, i64::try_from(ptr.offset.bytes()).unwrap())
} else {
base_addr
};
CValue::by_val(val, layout)
} }
} }
} Scalar::Ptr(ptr, _size) => {
let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative
let alloc_kind = fx.tcx.get_global_alloc(alloc_id);
let base_addr = match alloc_kind {
Some(GlobalAlloc::Memory(alloc)) => {
let data_id = data_id_for_alloc_id(
&mut fx.constants_cx,
fx.module,
alloc_id,
alloc.mutability,
);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", alloc_id));
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
Some(GlobalAlloc::Function(instance)) => {
let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
let local_func_id =
fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
}
Some(GlobalAlloc::Static(def_id)) => {
assert!(fx.tcx.is_static(def_id));
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", def_id));
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
None => bug!("missing allocation {:?}", alloc_id),
};
let val = if offset.bytes() != 0 {
fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap())
} else {
base_addr
};
CValue::by_val(val, layout)
}
},
ConstValue::ByRef { alloc, offset } => CValue::by_ref( ConstValue::ByRef { alloc, offset } => CValue::by_ref(
pointer_for_allocation(fx, alloc) pointer_for_allocation(fx, alloc)
.offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()),
@ -249,12 +255,11 @@ pub(crate) fn codegen_const_value<'tcx>(
} }
} }
fn pointer_for_allocation<'tcx>( pub(crate) fn pointer_for_allocation<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>, fx: &mut FunctionCx<'_, '_, 'tcx>,
alloc: &'tcx Allocation, alloc: &'tcx Allocation,
) -> crate::pointer::Pointer { ) -> crate::pointer::Pointer {
let alloc_id = fx.tcx.create_memory_alloc(alloc); let alloc_id = fx.tcx.create_memory_alloc(alloc);
fx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
let data_id = let data_id =
data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability); data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
@ -266,12 +271,13 @@ fn pointer_for_allocation<'tcx>(
crate::pointer::Pointer::new(global_ptr) crate::pointer::Pointer::new(global_ptr)
} }
fn data_id_for_alloc_id( pub(crate) fn data_id_for_alloc_id(
cx: &mut ConstantCx, cx: &mut ConstantCx,
module: &mut dyn Module, module: &mut dyn Module,
alloc_id: AllocId, alloc_id: AllocId,
mutability: rustc_hir::Mutability, mutability: rustc_hir::Mutability,
) -> DataId { ) -> DataId {
cx.todo.push(TodoItem::Alloc(alloc_id));
*cx.anon_allocs.entry(alloc_id).or_insert_with(|| { *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap() module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap()
}) })
@ -352,7 +358,14 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Memory(alloc) => alloc,
GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(), GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(),
}; };
let data_id = data_id_for_alloc_id(cx, module, alloc_id, alloc.mutability); let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
module
.declare_anonymous_data(
alloc.mutability == rustc_hir::Mutability::Mut,
false,
)
.unwrap()
});
(data_id, alloc, None) (data_id, alloc, None)
} }
TodoItem::Static(def_id) => { TodoItem::Static(def_id) => {
@ -394,7 +407,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
data_ctx.define(bytes.into_boxed_slice()); data_ctx.define(bytes.into_boxed_slice());
for &(offset, (_tag, reloc)) in alloc.relocations().iter() { for &(offset, alloc_id) in alloc.relocations().iter() {
let addend = { let addend = {
let endianness = tcx.data_layout.endian; let endianness = tcx.data_layout.endian;
let offset = offset.bytes() as usize; let offset = offset.bytes() as usize;
@ -405,7 +418,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
read_target_uint(endianness, bytes).unwrap() read_target_uint(endianness, bytes).unwrap()
}; };
let reloc_target_alloc = tcx.get_global_alloc(reloc).unwrap(); let reloc_target_alloc = tcx.get_global_alloc(alloc_id).unwrap();
let data_id = match reloc_target_alloc { let data_id = match reloc_target_alloc {
GlobalAlloc::Function(instance) => { GlobalAlloc::Function(instance) => {
assert_eq!(addend, 0); assert_eq!(addend, 0);
@ -415,8 +428,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
continue; continue;
} }
GlobalAlloc::Memory(target_alloc) => { GlobalAlloc::Memory(target_alloc) => {
cx.todo.push(TodoItem::Alloc(reloc)); data_id_for_alloc_id(cx, module, alloc_id, target_alloc.mutability)
data_id_for_alloc_id(cx, module, reloc, target_alloc.mutability)
} }
GlobalAlloc::Static(def_id) => { GlobalAlloc::Static(def_id) => {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)

View File

@ -10,7 +10,7 @@ use rustc_span::{
}; };
use cranelift_codegen::binemit::CodeOffset; use cranelift_codegen::binemit::CodeOffset;
use cranelift_codegen::machinst::MachSrcLoc; use cranelift_codegen::MachSrcLoc;
use gimli::write::{ use gimli::write::{
Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable, Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable,

View File

@ -61,9 +61,11 @@ impl<'tcx> DebugContext<'tcx> {
let mut dwarf = DwarfUnit::new(encoding); let mut dwarf = DwarfUnit::new(encoding);
// FIXME: how to get version when building out of tree? let producer = format!(
// Normally this would use option_env!("CFG_VERSION"). "cg_clif (rustc {}, cranelift {})",
let producer = format!("cg_clif (rustc {})", "unknown version"); rustc_interface::util::version_str().unwrap_or("unknown version"),
cranelift_codegen::VERSION,
);
let comp_dir = tcx.sess.working_dir.to_string_lossy(false).into_owned(); let comp_dir = tcx.sess.working_dir.to_string_lossy(false).into_owned();
let (name, file_info) = match tcx.sess.local_crate_source_file.clone() { let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
Some(path) => { Some(path) => {

View File

@ -4,7 +4,6 @@
use std::path::PathBuf; use std::path::PathBuf;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@ -290,14 +289,16 @@ pub(crate) fn run_aot(
None None
}; };
// FIXME handle `-Ctarget-cpu=native`
let target_cpu =
tcx.sess.opts.cg.target_cpu.as_ref().unwrap_or(&tcx.sess.target.cpu).to_owned();
Box::new(( Box::new((
CodegenResults { CodegenResults {
modules, modules,
allocator_module, allocator_module,
metadata_module, metadata_module,
metadata, metadata,
linker_info: LinkerInfo::new(tcx, crate::target_triple(tcx.sess).to_string()), crate_info: CrateInfo::new(tcx, target_cpu),
crate_info: CrateInfo::new(tcx),
}, },
work_products, work_products,
)) ))

View File

@ -3,11 +3,14 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::CString; use std::ffi::CString;
use std::lazy::{Lazy, SyncOnceCell};
use std::os::raw::{c_char, c_int}; use std::os::raw::{c_char, c_int};
use std::sync::{mpsc, Mutex};
use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink}; use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
use rustc_codegen_ssa::CrateInfo; use rustc_codegen_ssa::CrateInfo;
use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::MonoItem;
use rustc_session::Session;
use cranelift_jit::{JITBuilder, JITModule}; use cranelift_jit::{JITBuilder, JITModule};
@ -23,12 +26,48 @@ thread_local! {
static LAZY_JIT_STATE: RefCell<Option<JitState>> = RefCell::new(None); static LAZY_JIT_STATE: RefCell<Option<JitState>> = RefCell::new(None);
} }
/// The Sender owned by the rustc thread
static GLOBAL_MESSAGE_SENDER: SyncOnceCell<Mutex<mpsc::Sender<UnsafeMessage>>> =
SyncOnceCell::new();
/// A message that is sent from the jitted runtime to the rustc thread.
/// Senders are responsible for upholding `Send` semantics.
enum UnsafeMessage {
/// Request that the specified `Instance` be lazily jitted.
///
/// Nothing accessible through `instance_ptr` may be moved or mutated by the sender after
/// this message is sent.
JitFn {
instance_ptr: *const Instance<'static>,
trampoline_ptr: *const u8,
tx: mpsc::Sender<*const u8>,
},
}
unsafe impl Send for UnsafeMessage {}
impl UnsafeMessage {
/// Send the message.
fn send(self) -> Result<(), mpsc::SendError<UnsafeMessage>> {
thread_local! {
/// The Sender owned by the local thread
static LOCAL_MESSAGE_SENDER: Lazy<mpsc::Sender<UnsafeMessage>> = Lazy::new(||
GLOBAL_MESSAGE_SENDER
.get().unwrap()
.lock().unwrap()
.clone()
);
}
LOCAL_MESSAGE_SENDER.with(|sender| sender.send(self))
}
}
fn create_jit_module<'tcx>( fn create_jit_module<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
backend_config: &BackendConfig, backend_config: &BackendConfig,
hotswap: bool, hotswap: bool,
) -> (JITModule, CodegenCx<'tcx>) { ) -> (JITModule, CodegenCx<'tcx>) {
let imported_symbols = load_imported_symbols_for_jit(tcx); let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info);
let isa = crate::build_isa(tcx.sess, backend_config); let isa = crate::build_isa(tcx.sess, backend_config);
let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
@ -116,11 +155,6 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
.chain(backend_config.jit_args.iter().map(|arg| &**arg)) .chain(backend_config.jit_args.iter().map(|arg| &**arg))
.map(|arg| CString::new(arg).unwrap()) .map(|arg| CString::new(arg).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
// Push a null pointer as a terminating argument. This is required by POSIX and
// useful as some dynamic linkers use it as a marker to jump over.
argv.push(std::ptr::null());
let start_sig = Signature { let start_sig = Signature {
params: vec![ params: vec![
@ -128,7 +162,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
AbiParam::new(jit_module.target_config().pointer_type()), AbiParam::new(jit_module.target_config().pointer_type()),
], ],
returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)], returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)],
call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)), call_conv: jit_module.target_config().default_call_conv,
}; };
let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap();
let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
@ -141,12 +175,51 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
let f: extern "C" fn(c_int, *const *const c_char) -> c_int = let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
unsafe { ::std::mem::transmute(finalized_start) }; unsafe { ::std::mem::transmute(finalized_start) };
let ret = f(args.len() as c_int, argv.as_ptr());
std::process::exit(ret); let (tx, rx) = mpsc::channel();
GLOBAL_MESSAGE_SENDER.set(Mutex::new(tx)).unwrap();
// Spawn the jitted runtime in a new thread so that this rustc thread can handle messages
// (eg to lazily JIT further functions as required)
std::thread::spawn(move || {
let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
// Push a null pointer as a terminating argument. This is required by POSIX and
// useful as some dynamic linkers use it as a marker to jump over.
argv.push(std::ptr::null());
let ret = f(args.len() as c_int, argv.as_ptr());
std::process::exit(ret);
});
// Handle messages
loop {
match rx.recv().unwrap() {
// lazy JIT compilation request - compile requested instance and return pointer to result
UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } => {
tx.send(jit_fn(instance_ptr, trampoline_ptr))
.expect("jitted runtime hung up before response to lazy JIT request was sent");
}
}
}
} }
#[no_mangle] #[no_mangle]
extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 { extern "C" fn __clif_jit_fn(
instance_ptr: *const Instance<'static>,
trampoline_ptr: *const u8,
) -> *const u8 {
// send the JIT request to the rustc thread, with a channel for the response
let (tx, rx) = mpsc::channel();
UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx }
.send()
.expect("rustc thread hung up before lazy JIT request was sent");
// block on JIT compilation result
rx.recv().expect("rustc thread hung up before responding to sent lazy JIT request")
}
fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 {
rustc_middle::ty::tls::with(|tcx| { rustc_middle::ty::tls::with(|tcx| {
// lift is used to ensure the correct lifetime for instance. // lift is used to ensure the correct lifetime for instance.
let instance = tcx.lift(unsafe { *instance_ptr }).unwrap(); let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
@ -160,6 +233,17 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8
let name = tcx.symbol_name(instance).name; let name = tcx.symbol_name(instance).name;
let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance); let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap(); let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
let current_ptr = jit_module.read_got_entry(func_id);
// If the function's GOT entry has already been updated to point at something other
// than the shim trampoline, don't re-jit but just return the new pointer instead.
// This does not need synchronization as this code is executed only by a sole rustc
// thread.
if current_ptr != trampoline_ptr {
return current_ptr;
}
jit_module.prepare_for_function_redefine(func_id).unwrap(); jit_module.prepare_for_function_redefine(func_id).unwrap();
let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false); let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false);
@ -173,26 +257,27 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8
}) })
} }
fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { fn load_imported_symbols_for_jit(
sess: &Session,
crate_info: CrateInfo,
) -> Vec<(String, *const u8)> {
use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::dependency_format::Linkage;
let mut dylib_paths = Vec::new(); let mut dylib_paths = Vec::new();
let crate_info = CrateInfo::new(tcx); let data = &crate_info
let formats = tcx.dependency_formats(()); .dependency_formats
let data = &formats
.iter() .iter()
.find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable) .find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable)
.unwrap() .unwrap()
.1; .1;
for &(cnum, _) in &crate_info.used_crates_dynamic { for &cnum in &crate_info.used_crates {
let src = &crate_info.used_crate_source[&cnum]; let src = &crate_info.used_crate_source[&cnum];
match data[cnum.as_usize() - 1] { match data[cnum.as_usize() - 1] {
Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::NotLinked | Linkage::IncludedFromDylib => {}
Linkage::Static => { Linkage::Static => {
let name = tcx.crate_name(cnum); let name = &crate_info.crate_name[&cnum];
let mut err = let mut err = sess.struct_err(&format!("Can't load static lib {}", name.as_str()));
tcx.sess.struct_err(&format!("Can't load static lib {}", name.as_str()));
err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
err.emit(); err.emit();
} }
@ -232,7 +317,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
std::mem::forget(lib) std::mem::forget(lib)
} }
tcx.sess.abort_if_errors(); sess.abort_if_errors();
imported_symbols imported_symbols
} }
@ -254,7 +339,7 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
Linkage::Import, Linkage::Import,
&Signature { &Signature {
call_conv: module.target_config().default_call_conv, call_conv: module.target_config().default_call_conv,
params: vec![AbiParam::new(pointer_type)], params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)],
returns: vec![AbiParam::new(pointer_type)], returns: vec![AbiParam::new(pointer_type)],
}, },
) )
@ -267,6 +352,7 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
let mut builder_ctx = FunctionBuilderContext::new(); let mut builder_ctx = FunctionBuilderContext::new();
let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx); let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx);
let trampoline_fn = module.declare_func_in_func(func_id, trampoline_builder.func);
let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func); let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func);
let sig_ref = trampoline_builder.func.import_signature(sig); let sig_ref = trampoline_builder.func.import_signature(sig);
@ -276,7 +362,8 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
trampoline_builder.switch_to_block(entry_block); trampoline_builder.switch_to_block(entry_block);
let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64); let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64);
let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr]); let trampoline_ptr = trampoline_builder.ins().func_addr(pointer_type, trampoline_fn);
let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr, trampoline_ptr]);
let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0]; let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0];
let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args); let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args);
let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec(); let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();

View File

@ -106,6 +106,26 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout()); let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
dest.write_cvalue(fx, a); dest.write_cvalue(fx, a);
}; };
"llvm.x86.addcarry.64", (v c_in, c a, c b) {
llvm_add_sub(
fx,
BinOp::Add,
ret,
c_in,
a,
b
);
};
"llvm.x86.subborrow.64", (v b_in, c a, c b) {
llvm_add_sub(
fx,
BinOp::Sub,
ret,
b_in,
a,
b
);
};
} }
if let Some((_, dest)) = destination { if let Some((_, dest)) = destination {
@ -121,3 +141,41 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
// llvm.x86.avx2.pshuf.b // llvm.x86.avx2.pshuf.b
// llvm.x86.avx2.psrli.w // llvm.x86.avx2.psrli.w
// llvm.x86.sse2.psrli.w // llvm.x86.sse2.psrli.w
fn llvm_add_sub<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
bin_op: BinOp,
ret: CPlace<'tcx>,
cb_in: Value,
a: CValue<'tcx>,
b: CValue<'tcx>,
) {
assert_eq!(
a.layout().ty,
fx.tcx.types.u64,
"llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
);
assert_eq!(
b.layout().ty,
fx.tcx.types.u64,
"llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
);
// c + carry -> c + first intermediate carry or borrow respectively
let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
let c = int0.value_field(fx, mir::Field::new(0));
let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
// c + carry -> c + second intermediate carry or borrow respectively
let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
let (c, cb1) = int1.load_scalar_pair(fx);
// carry0 | carry1 -> carry or borrow respectively
let cb_out = fx.bcx.ins().bor(cb0, cb1);
let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
let val = CValue::by_val_pair(cb_out, c, layout);
ret.write_cvalue(fx, val);
}

View File

@ -1115,6 +1115,40 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
); );
ret.write_cvalue(fx, CValue::by_val(res, ret.layout())); ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
}; };
raw_eq, <T>(v lhs_ref, v rhs_ref) {
fn type_by_size(size: Size) -> Option<Type> {
Type::int(size.bits().try_into().ok()?)
}
let size = fx.layout_of(T).layout.size;
let is_eq_value =
if size == Size::ZERO {
// No bytes means they're trivially equal
fx.bcx.ins().iconst(types::I8, 1)
} else if let Some(clty) = type_by_size(size) {
// Can't use `trusted` for these loads; they could be unaligned.
let mut flags = MemFlags::new();
flags.set_notrap();
let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
fx.bcx.ins().bint(types::I8, eq)
} else {
// Just call `memcmp` (like slices do in core) when the
// size is too large or it's not a power-of-two.
let ptr_ty = pointer_ty(fx.tcx);
let signed_bytes = i64::try_from(size.bytes()).unwrap();
let bytes_val = fx.bcx.ins().iconst(ptr_ty, signed_bytes);
let params = vec![AbiParam::new(ptr_ty); 3];
let returns = vec![AbiParam::new(types::I32)];
let args = &[lhs_ref, rhs_ref, bytes_val];
let cmp = fx.lib_call("memcmp", params, returns, args)[0];
let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
fx.bcx.ins().bint(types::I8, eq)
};
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
};
} }
if let Some((_, dest)) = destination { if let Some((_, dest)) = destination {

View File

@ -1,4 +1,4 @@
#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)] #![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)] #![warn(unused_lifetimes)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]
@ -14,7 +14,9 @@ extern crate rustc_fs_util;
extern crate rustc_hir; extern crate rustc_hir;
extern crate rustc_incremental; extern crate rustc_incremental;
extern crate rustc_index; extern crate rustc_index;
extern crate rustc_interface;
extern crate rustc_metadata; extern crate rustc_metadata;
extern crate rustc_mir;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
extern crate rustc_target; extern crate rustc_target;
@ -98,7 +100,7 @@ mod prelude {
pub(crate) use cranelift_codegen::isa::{self, CallConv}; pub(crate) use cranelift_codegen::isa::{self, CallConv};
pub(crate) use cranelift_codegen::Context; pub(crate) use cranelift_codegen::Context;
pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module}; pub(crate) use cranelift_module::{self, DataContext, FuncId, Linkage, Module};
pub(crate) use crate::abi::*; pub(crate) use crate::abi::*;
pub(crate) use crate::base::{codegen_operand, codegen_place}; pub(crate) use crate::base::{codegen_operand, codegen_place};
@ -219,10 +221,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
sess, sess,
&codegen_results, &codegen_results,
outputs, outputs,
&codegen_results.crate_info.local_crate_name.as_str(), )
);
Ok(())
} }
} }
@ -285,10 +284,12 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
} }
None => { None => {
let mut builder = let mut builder =
cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); cranelift_codegen::isa::lookup_variant(target_triple.clone(), variant).unwrap();
// Don't use "haswell" as the default, as it implies `has_lzcnt`. if target_triple.architecture == target_lexicon::Architecture::X86_64 {
// macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`. // Don't use "haswell" as the default, as it implies `has_lzcnt`.
builder.enable("nehalem").unwrap(); // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
builder.enable("nehalem").unwrap();
}
builder builder
} }
}; };

View File

@ -1,17 +1,20 @@
//! Various optimizations specific to cg_clif //! Various optimizations specific to cg_clif
use cranelift_codegen::isa::TargetIsa;
use crate::prelude::*; use crate::prelude::*;
pub(crate) mod peephole; pub(crate) mod peephole;
pub(crate) fn optimize_function<'tcx>( pub(crate) fn optimize_function<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
isa: &dyn TargetIsa,
instance: Instance<'tcx>, instance: Instance<'tcx>,
ctx: &mut Context, ctx: &mut Context,
clif_comments: &mut crate::pretty_clif::CommentWriter, clif_comments: &mut crate::pretty_clif::CommentWriter,
) { ) {
// FIXME classify optimizations over opt levels once we have more // FIXME classify optimizations over opt levels once we have more
crate::pretty_clif::write_clif_file(tcx, "preopt", None, instance, &ctx, &*clif_comments); crate::pretty_clif::write_clif_file(tcx, "preopt", isa, instance, &ctx, &*clif_comments);
crate::base::verify_func(tcx, &*clif_comments, &ctx.func); crate::base::verify_func(tcx, &*clif_comments, &ctx.func);
} }

View File

@ -233,7 +233,7 @@ pub(crate) fn write_ir_file(
pub(crate) fn write_clif_file<'tcx>( pub(crate) fn write_clif_file<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
postfix: &str, postfix: &str,
isa: Option<&dyn cranelift_codegen::isa::TargetIsa>, isa: &dyn cranelift_codegen::isa::TargetIsa,
instance: Instance<'tcx>, instance: Instance<'tcx>,
context: &cranelift_codegen::Context, context: &cranelift_codegen::Context,
mut clif_comments: &CommentWriter, mut clif_comments: &CommentWriter,
@ -242,22 +242,23 @@ pub(crate) fn write_clif_file<'tcx>(
tcx, tcx,
|| format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
|file| { |file| {
let value_ranges = isa
.map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
let mut clif = String::new(); let mut clif = String::new();
cranelift_codegen::write::decorate_function( cranelift_codegen::write::decorate_function(
&mut clif_comments, &mut clif_comments,
&mut clif, &mut clif,
&context.func, &context.func,
&DisplayFunctionAnnotations { isa, value_ranges: value_ranges.as_ref() }, &DisplayFunctionAnnotations { isa: Some(isa), value_ranges: None },
) )
.unwrap(); .unwrap();
writeln!(file, "test compile")?; for flag in isa.flags().iter() {
writeln!(file, "set is_pic")?; writeln!(file, "set {}", flag)?;
writeln!(file, "set enable_simd")?; }
writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?; write!(file, "target {}", isa.triple().architecture.to_string())?;
for isa_flag in isa.isa_flags().iter() {
write!(file, " {}", isa_flag)?;
}
writeln!(file, "\n")?;
writeln!(file)?; writeln!(file)?;
file.write_all(clif.as_bytes())?; file.write_all(clif.as_bytes())?;
Ok(()) Ok(())

View File

@ -31,9 +31,7 @@ pub(crate) fn unsized_info<'tcx>(
// change to the vtable. // change to the vtable.
old_info.expect("unsized_info: missing old info for trait upcast") old_info.expect("unsized_info: missing old info for trait upcast")
} }
(_, &ty::Dynamic(ref data, ..)) => { (_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
crate::vtable::get_vtable(fx, fx.layout_of(source), data.principal())
}
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
} }
} }

View File

@ -453,6 +453,10 @@ impl<'tcx> CPlace<'tcx> {
ptr.store(fx, data, MemFlags::trusted()); ptr.store(fx, data, MemFlags::trusted());
ptr.load(fx, dst_ty, MemFlags::trusted()) ptr.load(fx, dst_ty, MemFlags::trusted())
} }
// `CValue`s should never contain SSA-only types, so if you ended
// up here having seen an error like `B1 -> I8`, then before
// calling `write_cvalue` you need to add a `bint` instruction.
_ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty), _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty),
}; };
//fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index())); //fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index()));

View File

@ -1,14 +1,10 @@
//! Codegen vtables and vtable accesses. //! Codegen vtables and vtable accesses.
//! //!
//! See `rustc_codegen_ssa/src/meth.rs` for reference. //! See `rustc_codegen_ssa/src/meth.rs` for reference.
// FIXME dedup this logic between miri, cg_llvm and cg_clif
use crate::constant::data_id_for_alloc_id;
use crate::prelude::*; use crate::prelude::*;
const DROP_FN_INDEX: usize = 0;
const SIZE_INDEX: usize = 1;
const ALIGN_INDEX: usize = 2;
fn vtable_memflags() -> MemFlags { fn vtable_memflags() -> MemFlags {
let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap. let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
flags.set_readonly(); // A vtable is always read-only. flags.set_readonly(); // A vtable is always read-only.
@ -21,7 +17,7 @@ pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) ->
pointer_ty(fx.tcx), pointer_ty(fx.tcx),
vtable_memflags(), vtable_memflags(),
vtable, vtable,
(DROP_FN_INDEX * usize_size) as i32, (ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
) )
} }
@ -31,7 +27,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
pointer_ty(fx.tcx), pointer_ty(fx.tcx),
vtable_memflags(), vtable_memflags(),
vtable, vtable,
(SIZE_INDEX * usize_size) as i32, (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
) )
} }
@ -41,7 +37,7 @@ pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -
pointer_ty(fx.tcx), pointer_ty(fx.tcx),
vtable_memflags(), vtable_memflags(),
vtable, vtable,
(ALIGN_INDEX * usize_size) as i32, (ty::COMMON_VTABLE_ENTRIES_ALIGN * usize_size) as i32,
) )
} }
@ -62,105 +58,22 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
pointer_ty(fx.tcx), pointer_ty(fx.tcx),
vtable_memflags(), vtable_memflags(),
vtable, vtable,
((idx + 3) * usize_size as usize) as i32, (idx * usize_size as usize) as i32,
); );
(ptr, func_ref) (ptr, func_ref)
} }
pub(crate) fn get_vtable<'tcx>( pub(crate) fn get_vtable<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>, fx: &mut FunctionCx<'_, '_, 'tcx>,
layout: TyAndLayout<'tcx>, ty: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Value { ) -> Value {
let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) { let alloc_id = fx.tcx.vtable_allocation(ty, trait_ref);
*data_id let data_id =
} else { data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not);
let data_id = build_vtable(fx, layout, trait_ref);
fx.vtables.insert((layout.ty, trait_ref), data_id);
data_id
};
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("vtable: {:?}", alloc_id));
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id) fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
} }
fn build_vtable<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
layout: TyAndLayout<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> DataId {
let tcx = fx.tcx;
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
let drop_in_place_fn = import_function(
tcx,
fx.module,
Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
);
let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];
let methods_root;
let methods = if let Some(trait_ref) = trait_ref {
methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
methods_root.iter()
} else {
(&[]).iter()
};
let methods = methods.cloned().map(|opt_mth| {
opt_mth.map(|(def_id, substs)| {
import_function(
tcx,
fx.module,
Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
.unwrap()
.polymorphize(fx.tcx),
)
})
});
components.extend(methods);
let mut data_ctx = DataContext::new();
let mut data = ::std::iter::repeat(0u8)
.take(components.len() * usize_size)
.collect::<Vec<u8>>()
.into_boxed_slice();
write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
data_ctx.define(data);
for (i, component) in components.into_iter().enumerate() {
if let Some(func_id) = component {
let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
}
}
data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes());
let data_id = fx.module.declare_anonymous_data(false, false).unwrap();
fx.module.define_data(data_id, &data_ctx).unwrap();
data_id
}
fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) {
let pointer_size =
tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.usize)).unwrap().size.bytes() as usize;
let target = &mut buf[idx * pointer_size..(idx + 1) * pointer_size];
match tcx.data_layout.endian {
rustc_target::abi::Endian::Little => match pointer_size {
4 => target.copy_from_slice(&(num as u32).to_le_bytes()),
8 => target.copy_from_slice(&(num as u64).to_le_bytes()),
_ => todo!("pointer size {} is not yet supported", pointer_size),
},
rustc_target::abi::Endian::Big => match pointer_size {
4 => target.copy_from_slice(&(num as u32).to_be_bytes()),
8 => target.copy_from_slice(&(num as u64).to_be_bytes()),
_ => todo!("pointer size {} is not yet supported", pointer_size),
},
}
}

View File

@ -1,13 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
./build.sh --sysroot none "$@" ./y.rs build --sysroot none "$@"
rm -r target/out || true rm -r target/out || true
scripts/tests.sh no_sysroot scripts/tests.sh no_sysroot
./build.sh "$@" ./y.rs build "$@"
scripts/tests.sh base_sysroot scripts/tests.sh base_sysroot
scripts/tests.sh extended_sysroot scripts/tests.sh extended_sysroot

View File

@ -0,0 +1,153 @@
#!/usr/bin/env bash
#![allow()] /*This line is ignored by bash
# This block is ignored by rustc
set -e
echo "[BUILD] y.rs" 1>&2
rustc $0 -o ${0/.rs/.bin} -g
exec ${0/.rs/.bin} $@
*/
//! The build system for cg_clif
//!
//! # Manual compilation
//!
//! If your system doesn't support shell scripts you can manually compile and run this file using
//! for example:
//!
//! ```shell
//! $ rustc y.rs -o build/y.bin
//! $ build/y.bin
//! ```
//!
//! # Naming
//!
//! The name `y.rs` was chosen to not conflict with rustc's `x.py`.
use std::env;
use std::path::PathBuf;
use std::process;
#[path = "build_system/build_backend.rs"]
mod build_backend;
#[path = "build_system/build_sysroot.rs"]
mod build_sysroot;
#[path = "build_system/config.rs"]
mod config;
#[path = "build_system/prepare.rs"]
mod prepare;
#[path = "build_system/rustc_info.rs"]
mod rustc_info;
#[path = "build_system/utils.rs"]
mod utils;
fn usage() {
eprintln!("Usage:");
eprintln!(" ./y.rs prepare");
eprintln!(" ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR]");
}
macro_rules! arg_error {
($($err:tt)*) => {{
eprintln!($($err)*);
usage();
std::process::exit(1);
}};
}
enum Command {
Build,
}
#[derive(Copy, Clone)]
enum SysrootKind {
None,
Clif,
Llvm,
}
fn main() {
env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
// The target dir is expected in the default location. Guard against the user changing it.
env::set_var("CARGO_TARGET_DIR", "target");
let mut args = env::args().skip(1);
let command = match args.next().as_deref() {
Some("prepare") => {
if args.next().is_some() {
arg_error!("./x.rs prepare doesn't expect arguments");
}
prepare::prepare();
process::exit(0);
}
Some("build") => Command::Build,
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
Some(command) => arg_error!("Unknown command {}", command),
None => {
usage();
process::exit(0);
}
};
let mut target_dir = PathBuf::from("build");
let mut channel = "release";
let mut sysroot_kind = SysrootKind::Clif;
while let Some(arg) = args.next().as_deref() {
match arg {
"--target-dir" => {
target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
arg_error!("--target-dir requires argument");
}))
}
"--debug" => channel = "debug",
"--sysroot" => {
sysroot_kind = match args.next().as_deref() {
Some("none") => SysrootKind::None,
Some("clif") => SysrootKind::Clif,
Some("llvm") => SysrootKind::Llvm,
Some(arg) => arg_error!("Unknown sysroot kind {}", arg),
None => arg_error!("--sysroot requires argument"),
}
}
flag if flag.starts_with("-") => arg_error!("Unknown flag {}", flag),
arg => arg_error!("Unexpected argument {}", arg),
}
}
let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
host_triple
} else if let Some(host_triple) = crate::config::get_value("host") {
host_triple
} else {
rustc_info::get_host_triple()
};
let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") {
if target_triple != "" {
target_triple
} else {
host_triple.clone() // Empty target triple can happen on GHA
}
} else if let Some(target_triple) = crate::config::get_value("target") {
target_triple
} else {
host_triple.clone()
};
if target_triple.ends_with("-msvc") {
eprintln!("The MSVC toolchain is not yet supported by rustc_codegen_cranelift.");
eprintln!("Switch to the MinGW toolchain for Windows support.");
eprintln!("Hint: You can use `rustup set default-host x86_64-pc-windows-gnu` to");
eprintln!("set the global default target to MinGW");
process::exit(1);
}
let cg_clif_build_dir = build_backend::build_backend(channel, &host_triple);
build_sysroot::build_sysroot(
channel,
sysroot_kind,
&target_dir,
cg_clif_build_dir,
&host_triple,
&target_triple,
);
}

View File

@ -21,10 +21,8 @@ rustc_attr = { path = "../rustc_attr" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_data_structures = { path = "../rustc_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" } rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_fs_util = { path = "../rustc_fs_util" } rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" } rustc_hir = { path = "../rustc_hir" }
rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }
rustc_llvm = { path = "../rustc_llvm" } rustc_llvm = { path = "../rustc_llvm" }
rustc_metadata = { path = "../rustc_metadata" } rustc_metadata = { path = "../rustc_metadata" }

View File

@ -128,6 +128,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
let mut clobbers = vec![]; let mut clobbers = vec![];
let mut output_types = vec![]; let mut output_types = vec![];
let mut op_idx = FxHashMap::default(); let mut op_idx = FxHashMap::default();
let mut clobbered_x87 = false;
for (idx, op) in operands.iter().enumerate() { for (idx, op) in operands.iter().enumerate() {
match *op { match *op {
InlineAsmOperandRef::Out { reg, late, place } => { InlineAsmOperandRef::Out { reg, late, place } => {
@ -150,7 +151,27 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
let ty = if let Some(ref place) = place { let ty = if let Some(ref place) = place {
layout = Some(&place.layout); layout = Some(&place.layout);
llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout) llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout)
} else if !is_target_supported(reg.reg_class()) { } else if matches!(
reg.reg_class(),
InlineAsmRegClass::X86(
X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::x87_reg
)
) {
// Special handling for x87/mmx registers: we always
// clobber the whole set if one register is marked as
// clobbered. This is due to the way LLVM handles the
// FP stack in inline assembly.
if !clobbered_x87 {
clobbered_x87 = true;
clobbers.push("~{st}".to_string());
for i in 1..=7 {
clobbers.push(format!("~{{st({})}}", i));
}
}
continue;
} else if !is_target_supported(reg.reg_class())
|| reg.reg_class().is_clobber_only(asm_arch)
{
// We turn discarded outputs into clobber constraints // We turn discarded outputs into clobber constraints
// if the target feature needed by the register class is // if the target feature needed by the register class is
// disabled. This is necessary otherwise LLVM will try // disabled. This is necessary otherwise LLVM will try
@ -565,6 +586,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => "l", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => "l",
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
@ -586,6 +610,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
@ -593,6 +620,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk", InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
InlineAsmRegClass::X86(
X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
) => unreachable!("clobber-only"),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
@ -617,6 +647,9 @@ fn modifier_to_llvm(
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
if modifier == Some('v') { None } else { modifier } if modifier == Some('v') { None } else { modifier }
} }
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => None, | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => None,
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
@ -639,6 +672,9 @@ fn modifier_to_llvm(
InlineAsmRegClass::PowerPC(_) => None, InlineAsmRegClass::PowerPC(_) => None,
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier { | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
None if arch == InlineAsmArch::X86_64 => Some('q'), None if arch == InlineAsmArch::X86_64 => Some('q'),
@ -663,6 +699,9 @@ fn modifier_to_llvm(
_ => unreachable!(), _ => unreachable!(),
}, },
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None, InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
InlineAsmRegClass::Bpf(_) => None, InlineAsmRegClass::Bpf(_) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
@ -681,6 +720,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
cx.type_vector(cx.type_i64(), 2) cx.type_vector(cx.type_i64(), 2)
} }
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(), | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
@ -704,6 +746,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(), | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(), InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(),
@ -711,6 +756,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(), InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(), InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),

View File

@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::OptLevel; use rustc_session::config::OptLevel;
use rustc_session::Session; use rustc_session::Session;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_target::spec::{SanitizerSet, StackProbeType}; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
use crate::attributes; use crate::attributes;
use crate::llvm::AttributePlace::Function; use crate::llvm::AttributePlace::Function;
@ -69,15 +69,25 @@ fn naked(val: &'ll Value, is_naked: bool) {
Attribute::Naked.toggle_llfn(Function, val, is_naked); Attribute::Naked.toggle_llfn(Function, val, is_naked);
} }
pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { pub fn set_frame_pointer_type(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
if cx.sess().must_not_eliminate_frame_pointers() { let mut fp = cx.sess().target.frame_pointer;
llvm::AddFunctionAttrStringValue( // "mcount" function relies on stack pointer.
llfn, // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
llvm::AttributePlace::Function, if cx.sess().instrument_mcount() || matches!(cx.sess().opts.cg.force_frame_pointers, Some(true))
cstr!("frame-pointer"), {
cstr!("all"), fp = FramePointer::Always;
);
} }
let attr_value = match fp {
FramePointer::Always => cstr!("all"),
FramePointer::NonLeaf => cstr!("non-leaf"),
FramePointer::MayOmit => return,
};
llvm::AddFunctionAttrStringValue(
llfn,
llvm::AttributePlace::Function,
cstr!("frame-pointer"),
attr_value,
);
} }
/// Tell LLVM what instrument function to insert. /// Tell LLVM what instrument function to insert.
@ -254,7 +264,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
} }
// FIXME: none of these three functions interact with source level attributes. // FIXME: none of these three functions interact with source level attributes.
set_frame_pointer_elimination(cx, llfn); set_frame_pointer_type(cx, llfn);
set_instrument_function(cx, llfn); set_instrument_function(cx, llfn);
set_probestack(cx, llfn); set_probestack(cx, llfn);
@ -279,6 +289,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
llvm::AddFunctionAttrString(llfn, Function, cstr!("cmse_nonsecure_entry")); llvm::AddFunctionAttrString(llfn, Function, cstr!("cmse_nonsecure_entry"));
} }
if let Some(align) = codegen_fn_attrs.alignment {
llvm::set_alignment(llfn, align as usize);
}
sanitize(cx, codegen_fn_attrs.no_sanitize, llfn); sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
// Always annotate functions with the target-cpu they are compiled for. // Always annotate functions with the target-cpu they are compiled for.

View File

@ -12,7 +12,7 @@ use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_middle::middle::cstore::DllImport; use rustc_middle::middle::cstore::{DllCallingConvention, DllImport};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
@ -208,10 +208,12 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
// have any \0 characters // have any \0 characters
let import_name_vector: Vec<CString> = dll_imports let import_name_vector: Vec<CString> = dll_imports
.iter() .iter()
.map(if self.config.sess.target.arch == "x86" { .map(|import: &DllImport| {
|import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap() if self.config.sess.target.arch == "x86" {
} else { LlvmArchiveBuilder::i686_decorated_name(import)
|import: &DllImport| CString::new(import.name.to_string()).unwrap() } else {
CString::new(import.name.to_string()).unwrap()
}
}) })
.collect(); .collect();
@ -391,6 +393,21 @@ impl<'a> LlvmArchiveBuilder<'a> {
ret ret
} }
} }
fn i686_decorated_name(import: &DllImport) -> CString {
let name = import.name;
// We verified during construction that `name` does not contain any NULL characters, so the
// conversion to CString is guaranteed to succeed.
CString::new(match import.calling_convention {
DllCallingConvention::C => format!("_{}", name),
DllCallingConvention::Stdcall(arg_list_size) => format!("_{}@{}", name, arg_list_size),
DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
DllCallingConvention::Vectorcall(arg_list_size) => {
format!("{}@@{}", name, arg_list_size)
}
})
.unwrap()
}
} }
fn string_to_io_error(s: String) -> io::Error { fn string_to_io_error(s: String) -> io::Error {

Some files were not shown because too many files have changed in this diff Show More