mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-14 03:03:34 +00:00
New upstream version 1.55.0+dfsg1
This commit is contained in:
parent
17df50a58d
commit
136023e0d2
540
Cargo.lock
generated
540
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -34,11 +34,13 @@ members = [
|
||||
"src/tools/unicode-table-generator",
|
||||
"src/tools/expand-yaml-anchors",
|
||||
"src/tools/jsondocck",
|
||||
"src/tools/html-checker",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
"build",
|
||||
"compiler/rustc_codegen_cranelift",
|
||||
"src/test/rustdoc-gui",
|
||||
# HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
|
||||
"obj",
|
||||
# The `x` binary is a thin wrapper that calls `x.py`, which initializes
|
||||
|
@ -21,7 +21,7 @@ Read ["Installation"] from [The Book].
|
||||
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.
|
||||
|
||||
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
|
||||
./x.py <subcommand> [flags]
|
||||
@ -272,15 +272,14 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and
|
||||
|
||||
## Trademark
|
||||
|
||||
The Rust programming language is an open source, community project governed
|
||||
by a core team. It is also sponsored by the Mozilla Foundation (“Mozilla”),
|
||||
which owns and protects the Rust and Cargo trademarks and logos
|
||||
(the “Rust Trademarks”).
|
||||
[The Rust Foundation][rust-foundation] 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].
|
||||
|
||||
Third-party logos may be subject to third-party copyrights and trademarks. See
|
||||
[Licenses][policies-licenses] for details.
|
||||
|
||||
[rust-foundation]: https://foundation.rust-lang.org/
|
||||
[media-guide]: https://www.rust-lang.org/policies/media-guide
|
||||
[policies-licenses]: https://www.rust-lang.org/policies/licenses
|
||||
|
151
RELEASES.md
151
RELEASES.md
@ -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)
|
||||
============================
|
||||
|
||||
Language
|
||||
-----------------------
|
||||
|
||||
- [You can now use macros for values in built-in attribute macros.][83366]
|
||||
While a seemingly minor addition on its own, this enables a lot of
|
||||
powerful functionality when combined correctly. Most notably you can
|
||||
now include external documentation in your crate by writing the following.
|
||||
- [You can now use macros for values in some built-in attributes.][83366]
|
||||
This primarily allows you to call macros within the `#[doc]` attribute. For
|
||||
example, to include external documentation in your crate, you can now write
|
||||
the following:
|
||||
```rust
|
||||
#![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
|
||||
unsized slices) in `const fn`.][85078]
|
||||
@ -37,6 +166,7 @@ Compiler
|
||||
- [Improved debugger output for enums on Windows MSVC platforms.][85292]
|
||||
- [Added tier 3\* support for `bpfel-unknown-none`
|
||||
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
|
||||
information on Rust's tiered platform support.
|
||||
@ -106,6 +236,7 @@ Compatibility Notes
|
||||
[83366]: https://github.com/rust-lang/rust/pull/83366
|
||||
[83278]: https://github.com/rust-lang/rust/pull/83278
|
||||
[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/9499]: https://github.com/rust-lang/cargo/pull/9499
|
||||
[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
|
||||
`NonZero` integer types.][84082]
|
||||
- [`{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]
|
||||
- [Add the `BITS` associated constant to all numeric types.][82565]
|
||||
|
||||
|
@ -552,7 +552,7 @@ fn fma() {
|
||||
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 m2 = X87DoubleExtended::from_u128(1).value;
|
||||
@ -1939,7 +1939,7 @@ fn add() {
|
||||
(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 result = unpack!(status=, x + y);
|
||||
assert_eq!(status, e_status);
|
||||
@ -2262,7 +2262,7 @@ fn subtract() {
|
||||
(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 result = unpack!(status=, x - y);
|
||||
assert_eq!(status, e_status);
|
||||
@ -2538,7 +2538,7 @@ fn multiply() {
|
||||
(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 result = unpack!(status=, x * y);
|
||||
assert_eq!(status, e_status);
|
||||
@ -2814,7 +2814,7 @@ fn divide() {
|
||||
(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 result = unpack!(status=, x / y);
|
||||
assert_eq!(status, e_status);
|
||||
|
@ -64,7 +64,7 @@ fn ppc_double_double_add_special() {
|
||||
(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 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 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 a2 = DoubleDouble::from_bits(op2);
|
||||
a1 = a1.sub_r(a2, round).value;
|
||||
@ -204,7 +204,7 @@ fn ppc_double_double_multiply_special() {
|
||||
(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 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 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 a2 = DoubleDouble::from_bits(op2);
|
||||
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 a2 = DoubleDouble::from_bits(op2);
|
||||
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 a2 = DoubleDouble::from_bits(op2);
|
||||
let r = (a1 % a2).value;
|
||||
@ -426,7 +426,7 @@ fn ppc_double_double_compare() {
|
||||
(0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)),
|
||||
];
|
||||
|
||||
for &(op1, op2, expected) in &data {
|
||||
for (op1, op2, expected) in data {
|
||||
let a1 = DoubleDouble::from_bits(op1);
|
||||
let a2 = DoubleDouble::from_bits(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),
|
||||
];
|
||||
|
||||
for &(op1, op2, expected) in &data {
|
||||
for (op1, op2, expected) in data {
|
||||
let a1 = DoubleDouble::from_bits(op1);
|
||||
let a2 = DoubleDouble::from_bits(op2);
|
||||
assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
|
||||
|
@ -677,7 +677,9 @@ pub enum BindingMode {
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum RangeEnd {
|
||||
/// `..=` or `...`
|
||||
Included(RangeSyntax),
|
||||
/// `..`
|
||||
Excluded,
|
||||
}
|
||||
|
||||
@ -689,6 +691,7 @@ pub enum RangeSyntax {
|
||||
DotDotEq,
|
||||
}
|
||||
|
||||
/// All the different flavors of pattern that Rust recognizes.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PatKind {
|
||||
/// Represents a wildcard pattern (`_`).
|
||||
@ -729,7 +732,7 @@ pub enum PatKind {
|
||||
/// A literal.
|
||||
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>),
|
||||
|
||||
/// A slice pattern `[a, b, c]`.
|
||||
@ -1017,7 +1020,7 @@ pub struct Local {
|
||||
/// ```
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Arm {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
|
||||
pub pat: P<Pat>,
|
||||
/// 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 NOSTACK = 1 << 5;
|
||||
const ATT_SYNTAX = 1 << 6;
|
||||
const RAW = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2293,7 +2297,7 @@ pub struct EnumDef {
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Variant {
|
||||
/// Attributes of the variant.
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
/// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
|
||||
pub id: NodeId,
|
||||
/// Span
|
||||
@ -2474,7 +2478,7 @@ impl VisibilityKind {
|
||||
/// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct FieldDef {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub vis: Visibility,
|
||||
|
@ -1,3 +1,4 @@
|
||||
#[derive(Debug)]
|
||||
pub enum EntryPointType {
|
||||
None,
|
||||
MainNamed,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Debug, Copy, HashStable_Generic)]
|
||||
pub enum AllocatorKind {
|
||||
Global,
|
||||
Default,
|
||||
|
@ -10,7 +10,6 @@
|
||||
)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(box_patterns)]
|
||||
#![cfg_attr(bootstrap, feature(const_fn_unsize))]
|
||||
#![feature(const_fn_transmute)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(iter_zip)]
|
||||
|
@ -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]> {
|
||||
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_pat(pat);
|
||||
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;
|
||||
visitor.visit_ident(ident);
|
||||
visitor.visit_vis(vis);
|
||||
visit_attrs(attrs, visitor);
|
||||
visit_thin_attrs(attrs, visitor);
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_variant_data(data);
|
||||
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_id(id);
|
||||
visitor.visit_ty(ty);
|
||||
visit_attrs(attrs, visitor);
|
||||
visit_thin_attrs(attrs, visitor);
|
||||
smallvec![fd]
|
||||
}
|
||||
|
||||
@ -1347,12 +1347,6 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
}
|
||||
ExprKind::Paren(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) => {
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_span::ExpnId;
|
||||
use rustc_span::LocalExpnId;
|
||||
use std::fmt;
|
||||
|
||||
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;
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn placeholder_to_expn_id(self) -> ExpnId {
|
||||
ExpnId::from_u32(self.as_u32())
|
||||
pub fn placeholder_to_expn_id(self) -> LocalExpnId {
|
||||
LocalExpnId::from_u32(self.as_u32())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
use super::*;
|
||||
use rustc_span::with_default_session_globals;
|
||||
use rustc_span::create_default_session_globals_then;
|
||||
|
||||
#[test]
|
||||
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 stripped = beautify_doc_string(Symbol::intern(comment));
|
||||
assert_eq!(stripped.as_str(), " Test \n* Test\n Test");
|
||||
@ -12,7 +12,7 @@ fn test_block_doc_comment_1() {
|
||||
|
||||
#[test]
|
||||
fn test_block_doc_comment_2() {
|
||||
with_default_session_globals(|| {
|
||||
create_default_session_globals_then(|| {
|
||||
let comment = "\n * Test\n * Test\n";
|
||||
let stripped = beautify_doc_string(Symbol::intern(comment));
|
||||
assert_eq!(stripped.as_str(), " Test\n Test");
|
||||
@ -21,7 +21,7 @@ fn test_block_doc_comment_2() {
|
||||
|
||||
#[test]
|
||||
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 stripped = beautify_doc_string(Symbol::intern(comment));
|
||||
assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
|
||||
@ -30,7 +30,7 @@ fn test_block_doc_comment_3() {
|
||||
|
||||
#[test]
|
||||
fn test_line_doc_comment() {
|
||||
with_default_session_globals(|| {
|
||||
create_default_session_globals_then(|| {
|
||||
let stripped = beautify_doc_string(Symbol::intern(" test"));
|
||||
assert_eq!(stripped.as_str(), " test");
|
||||
let stripped = beautify_doc_string(Symbol::intern("! test"));
|
||||
|
@ -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 {
|
||||
// Validate register classes against currently enabled target
|
||||
// features. We check that at least one type is available for
|
||||
|
@ -1067,6 +1067,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
eq_sign_span: Span,
|
||||
assignments: &mut Vec<hir::Stmt<'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 {
|
||||
// Underscore pattern.
|
||||
ExprKind::Underscore => {
|
||||
@ -1080,7 +1089,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (before, after) = pats.split_at(i);
|
||||
hir::PatKind::Slice(
|
||||
before,
|
||||
Some(self.pat_without_dbm(span, hir::PatKind::Wild)),
|
||||
Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))),
|
||||
after,
|
||||
)
|
||||
} else {
|
||||
@ -1165,14 +1174,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
|
||||
return self.pat_without_dbm(lhs.span, tuple_pat);
|
||||
} 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.
|
||||
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 assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, eq_sign_span);
|
||||
let expr = self.expr(lhs.span, assign, ThinVec::new());
|
||||
@ -1191,7 +1200,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ctx: &str,
|
||||
eq_sign_span: Span,
|
||||
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 elements =
|
||||
self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {
|
||||
@ -1204,7 +1213,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
None
|
||||
} else {
|
||||
Some(self.destructure_assign(e, eq_sign_span, assignments))
|
||||
Some(self.destructure_assign_mut(e, eq_sign_span, assignments))
|
||||
}
|
||||
}));
|
||||
(elements, rest)
|
||||
@ -1559,13 +1568,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
/// Desugar `ExprKind::Try` from: `<expr>?` into:
|
||||
/// ```rust
|
||||
/// match Try::into_result(<expr>) {
|
||||
/// Ok(val) => #[allow(unreachable_code)] val,
|
||||
/// Err(err) => #[allow(unreachable_code)]
|
||||
/// // If there is an enclosing `try {...}`:
|
||||
/// break 'catch_target Try::from_error(From::from(err)),
|
||||
/// // Otherwise:
|
||||
/// return Try::from_error(From::from(err)),
|
||||
/// match Try::branch(<expr>) {
|
||||
/// ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,
|
||||
/// ControlFlow::Break(residual) =>
|
||||
/// #[allow(unreachable_code)]
|
||||
/// // If there is an enclosing `try {...}`:
|
||||
/// break 'catch_target Try::from_residual(residual),
|
||||
/// // Otherwise:
|
||||
/// return Try::from_residual(residual),
|
||||
/// }
|
||||
/// ```
|
||||
fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> {
|
||||
|
@ -343,9 +343,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// opaque type Foo1: Trait
|
||||
let ty = self.lower_ty(
|
||||
ty,
|
||||
ImplTraitContext::OtherOpaqueTy {
|
||||
ImplTraitContext::TypeAliasesOpaqueTy {
|
||||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
||||
},
|
||||
);
|
||||
let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
|
||||
@ -484,17 +483,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: Span,
|
||||
body: Option<&Expr>,
|
||||
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
|
||||
let mut capturable_lifetimes;
|
||||
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);
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Binding));
|
||||
(ty, self.lower_const_body(span, body))
|
||||
}
|
||||
|
||||
@ -926,9 +915,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
Some(ty) => {
|
||||
let ty = self.lower_ty(
|
||||
ty,
|
||||
ImplTraitContext::OtherOpaqueTy {
|
||||
ImplTraitContext::TypeAliasesOpaqueTy {
|
||||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
||||
},
|
||||
);
|
||||
hir::ImplItemKind::TyAlias(ty)
|
||||
@ -1385,50 +1373,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> GenericsCtor<'hir> {
|
||||
// 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();
|
||||
for pred in &generics.where_clause.predicates {
|
||||
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
|
||||
'next_bound: for bound in &bound_pred.bounds {
|
||||
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.
|
||||
match bound_pred.bounded_ty.kind {
|
||||
TyKind::Path(None, ref path)
|
||||
if path.segments.len() == 1
|
||||
&& bound_pred.bound_generic_params.is_empty() =>
|
||||
match self
|
||||
.resolver
|
||||
.get_partial_res(bound_pred.bounded_ty.id)
|
||||
.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
|
||||
.resolver
|
||||
.get_partial_res(bound_pred.bounded_ty.id)
|
||||
.map(|d| d.base_res())
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
for param in &generics.params {
|
||||
if def_id == self.resolver.local_def_id(param.id).to_def_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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
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::intravisit;
|
||||
use rustc_hir::{ConstArg, GenericArg, ParamName};
|
||||
@ -59,7 +59,7 @@ use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
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::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
@ -204,6 +204,8 @@ pub trait ResolverAstLowering {
|
||||
|
||||
fn local_def_id(&self, node: NodeId) -> LocalDefId;
|
||||
|
||||
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
|
||||
|
||||
fn create_def(
|
||||
&mut self,
|
||||
parent: LocalDefId,
|
||||
@ -214,6 +216,32 @@ pub trait ResolverAstLowering {
|
||||
) -> 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,
|
||||
/// and if so, what meaning it has.
|
||||
#[derive(Debug)]
|
||||
@ -236,8 +264,8 @@ enum ImplTraitContext<'b, 'a> {
|
||||
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
},
|
||||
/// Impl trait in type aliases, consts and statics.
|
||||
OtherOpaqueTy {
|
||||
/// Impl trait in type aliases.
|
||||
TypeAliasesOpaqueTy {
|
||||
/// Set of lifetimes that this opaque type can capture, if it uses
|
||||
/// them. This includes lifetimes bound since we entered this context.
|
||||
/// For example:
|
||||
@ -252,8 +280,6 @@ enum ImplTraitContext<'b, 'a> {
|
||||
// FIXME(impl_trait): but `required_region_bounds` will ICE later
|
||||
// anyway.
|
||||
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.
|
||||
Disallowed(ImplTraitPosition),
|
||||
@ -282,8 +308,8 @@ impl<'a> ImplTraitContext<'_, 'a> {
|
||||
ReturnPositionOpaqueTy { fn_def_id, origin } => {
|
||||
ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin }
|
||||
}
|
||||
OtherOpaqueTy { capturable_lifetimes, origin } => {
|
||||
OtherOpaqueTy { capturable_lifetimes, origin: *origin }
|
||||
TypeAliasesOpaqueTy { capturable_lifetimes } => {
|
||||
TypeAliasesOpaqueTy { capturable_lifetimes }
|
||||
}
|
||||
Disallowed(pos) => Disallowed(*pos),
|
||||
}
|
||||
@ -296,7 +322,7 @@ pub fn lower_crate<'a, 'hir>(
|
||||
resolver: &'a mut dyn ResolverAstLowering,
|
||||
nt_to_tokenstream: NtToTokenstream,
|
||||
arena: &'hir Arena<'hir>,
|
||||
) -> hir::Crate<'hir> {
|
||||
) -> &'hir hir::Crate<'hir> {
|
||||
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
|
||||
|
||||
LoweringContext {
|
||||
@ -331,7 +357,7 @@ pub fn lower_crate<'a, 'hir>(
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_in_band_lifetimes: false,
|
||||
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()),
|
||||
}
|
||||
.lower_crate(krate)
|
||||
@ -403,7 +429,7 @@ enum AnonymousLifetimeMode {
|
||||
}
|
||||
|
||||
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
|
||||
/// `LoweringContext` any information that may be
|
||||
/// 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) {
|
||||
match tree.kind {
|
||||
UseTreeKind::Simple(_, id1, id2) => {
|
||||
for &id in &[id1, id2] {
|
||||
for id in [id1, id2] {
|
||||
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,
|
||||
exported_macros: self.arena.alloc_from_iter(self.exported_macros),
|
||||
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,
|
||||
trait_map,
|
||||
attrs: self.attrs,
|
||||
}
|
||||
};
|
||||
self.arena.alloc(krate)
|
||||
}
|
||||
|
||||
fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
|
||||
@ -564,6 +591,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
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(
|
||||
&mut self,
|
||||
ast_node_id: NodeId,
|
||||
@ -683,7 +717,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
span: Span,
|
||||
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||
) -> 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>(
|
||||
@ -1085,7 +1124,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
//
|
||||
// fn foo() -> impl Iterator<Item = impl Debug>
|
||||
ImplTraitContext::ReturnPositionOpaqueTy { .. }
|
||||
| ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx),
|
||||
| ImplTraitContext::TypeAliasesOpaqueTy { .. } => (true, itctx),
|
||||
|
||||
// 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();
|
||||
(
|
||||
true,
|
||||
ImplTraitContext::OtherOpaqueTy {
|
||||
ImplTraitContext::TypeAliasesOpaqueTy {
|
||||
capturable_lifetimes: &mut capturable_lifetimes,
|
||||
origin: hir::OpaqueTyOrigin::Misc,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -1375,18 +1413,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
None,
|
||||
|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
|
||||
// types will inherit lifetimes from this opaque type,
|
||||
// so don't need to capture them again.
|
||||
let nested_itctx = ImplTraitContext::OtherOpaqueTy {
|
||||
let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy {
|
||||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
origin,
|
||||
};
|
||||
self.lower_opaque_impl_trait(
|
||||
span,
|
||||
None,
|
||||
origin,
|
||||
hir::OpaqueTyOrigin::TyAlias,
|
||||
def_node_id,
|
||||
Some(capturable_lifetimes),
|
||||
|this| this.lower_param_bounds(bounds, nested_itctx),
|
||||
@ -1423,25 +1460,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}),
|
||||
))
|
||||
}
|
||||
ImplTraitContext::Disallowed(pos) => {
|
||||
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"
|
||||
};
|
||||
ImplTraitContext::Disallowed(_) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
t.span,
|
||||
E0562,
|
||||
"`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();
|
||||
hir::TyKind::Err
|
||||
}
|
||||
@ -1726,21 +1752,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn lower_local(&mut self, l: &Local) -> hir::Local<'hir> {
|
||||
let ty = l.ty.as_ref().map(|t| {
|
||||
let mut capturable_lifetimes;
|
||||
self.lower_ty(
|
||||
t,
|
||||
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 ty = l
|
||||
.ty
|
||||
.as_ref()
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
|
||||
let init = l.init.as_ref().map(|e| self.lower_expr(e));
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
self.lower_attrs(hir_id, &l.attrs);
|
||||
@ -2291,13 +2306,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
)),
|
||||
_ => 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());
|
||||
}
|
||||
|
||||
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 {
|
||||
capturable_lifetimes.remove(¶m);
|
||||
}
|
||||
@ -2536,21 +2555,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
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(
|
||||
&mut self,
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
bm: hir::BindingAnnotation,
|
||||
) -> (&'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();
|
||||
|
||||
(
|
||||
self.arena.alloc(hir::Pat {
|
||||
hir::Pat {
|
||||
hir_id,
|
||||
kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
|
||||
span,
|
||||
default_binding_modes: true,
|
||||
}),
|
||||
},
|
||||
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> {
|
||||
self.arena.alloc(hir::Pat {
|
||||
hir_id: self.next_id(),
|
||||
kind,
|
||||
span,
|
||||
default_binding_modes: false,
|
||||
})
|
||||
fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
|
||||
hir::Pat { hir_id: self.next_id(), kind, span, default_binding_modes: false }
|
||||
}
|
||||
|
||||
fn ty_path(
|
||||
|
@ -10,7 +10,11 @@ use rustc_span::symbol::Ident;
|
||||
use rustc_span::{source_map::Spanned, Span};
|
||||
|
||||
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(|| {
|
||||
// loop here to avoid recursion
|
||||
let node = loop {
|
||||
@ -34,7 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
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) => {
|
||||
@ -101,7 +105,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&mut self,
|
||||
pats: &[P<Pat>],
|
||||
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 rest = None;
|
||||
|
||||
@ -140,7 +144,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@ -149,7 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// ...but there was one again, so error.
|
||||
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
|
||||
} 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.
|
||||
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
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;
|
||||
}
|
||||
// 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");
|
||||
} else {
|
||||
// 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> {
|
||||
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.
|
||||
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(hir::Pat {
|
||||
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
|
||||
hir::Pat {
|
||||
hir_id: self.lower_node_id(p.id),
|
||||
kind,
|
||||
span: p.span,
|
||||
default_binding_modes: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
||||
|
@ -336,6 +336,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
insertion_sp,
|
||||
suggestion,
|
||||
);
|
||||
err.note("assuming a `'static` lifetime...");
|
||||
err.emit();
|
||||
}
|
||||
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
|
||||
|
@ -652,7 +652,7 @@ impl<'a> AstValidator<'a> {
|
||||
self.err_handler()
|
||||
.struct_span_err(
|
||||
*span,
|
||||
"only foreign or `unsafe extern \"C\" functions may be C-variadic",
|
||||
"only foreign or `unsafe extern \"C\"` functions may be C-variadic",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
@ -889,35 +889,32 @@ fn validate_generic_param_order(
|
||||
) {
|
||||
let mut max_param: Option<ParamKindOrd> = None;
|
||||
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 {
|
||||
let ident = Some(param.ident.to_string());
|
||||
let (kind, bounds, span) = (¶m.kind, Some(&*param.bounds), param.ident.span);
|
||||
for (idx, param) in generics.iter().enumerate() {
|
||||
let ident = param.ident;
|
||||
let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
|
||||
let (ord_kind, ident) = match ¶m.kind {
|
||||
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
|
||||
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
|
||||
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
|
||||
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
|
||||
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
|
||||
let ty = pprust::ty_to_string(ty);
|
||||
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, param_idents.len(), ident));
|
||||
}
|
||||
let max_param = &mut max_param;
|
||||
param_idents.push((kind, ord_kind, bounds, idx, ident));
|
||||
match max_param {
|
||||
Some(max_param) if *max_param > ord_kind => {
|
||||
let entry = out_of_order.entry(ord_kind).or_insert((*max_param, vec![]));
|
||||
Some(max_param) if max_param > ord_kind => {
|
||||
let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
|
||||
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() {
|
||||
let mut ordered_params = "<".to_string();
|
||||
param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
|
||||
let mut first = true;
|
||||
for (kind, _, bounds, _, ident) in param_idents {
|
||||
@ -925,12 +922,12 @@ fn validate_generic_param_order(
|
||||
ordered_params += ", ";
|
||||
}
|
||||
ordered_params += &ident;
|
||||
if let Some(bounds) = bounds {
|
||||
if !bounds.is_empty() {
|
||||
ordered_params += ": ";
|
||||
ordered_params += &pprust::bounds_to_string(&bounds);
|
||||
}
|
||||
|
||||
if !bounds.is_empty() {
|
||||
ordered_params += ": ";
|
||||
ordered_params += &pprust::bounds_to_string(&bounds);
|
||||
}
|
||||
|
||||
match kind {
|
||||
GenericParamKind::Type { default: Some(default) } => {
|
||||
ordered_params += " = ";
|
||||
@ -946,32 +943,32 @@ fn validate_generic_param_order(
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
ordered_params += ">";
|
||||
|
||||
for (param_ord, (max_param, spans)) in &out_of_order {
|
||||
let mut err =
|
||||
handler.struct_span_err(
|
||||
ordered_params += ">";
|
||||
|
||||
for (param_ord, (max_param, spans)) in &out_of_order {
|
||||
let mut err = handler.struct_span_err(
|
||||
spans.clone(),
|
||||
&format!(
|
||||
"{} parameters must be declared prior to {} parameters",
|
||||
param_ord, max_param,
|
||||
),
|
||||
);
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!(
|
||||
"reorder the parameters: lifetimes, {}",
|
||||
if sess.features_untracked().unordered_const_ty_params() {
|
||||
"then consts and types"
|
||||
} else {
|
||||
"then types, then consts"
|
||||
}
|
||||
),
|
||||
ordered_params.clone(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!(
|
||||
"reorder the parameters: lifetimes, {}",
|
||||
if sess.features_untracked().unordered_const_ty_params() {
|
||||
"then consts and types"
|
||||
} else {
|
||||
"then types, then consts"
|
||||
}
|
||||
),
|
||||
ordered_params.clone(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,6 +565,22 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
|
||||
fn visit_pat(&mut self, pattern: &'a ast::Pat) {
|
||||
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(..) => {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
@ -573,7 +589,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
"box pattern syntax is experimental"
|
||||
);
|
||||
}
|
||||
PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
|
||||
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
exclusive_range_pattern,
|
||||
|
@ -136,11 +136,11 @@ pub fn print_crate<'a>(
|
||||
s.s.eof()
|
||||
}
|
||||
|
||||
// This makes printed token streams look slightly nicer,
|
||||
// and also addresses some specific regressions described in #63896 and #73345.
|
||||
/// This makes printed token streams look slightly nicer,
|
||||
/// and also addresses some specific regressions described in #63896 and #73345.
|
||||
fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
|
||||
if let TokenTree::Token(token) = prev {
|
||||
if matches!(token.kind, token::Dot) {
|
||||
if matches!(token.kind, token::Dot | token::Dollar) {
|
||||
return false;
|
||||
}
|
||||
if let token::DocComment(comment_kind, ..) = token.kind {
|
||||
@ -1954,7 +1954,6 @@ impl<'a> State<'a> {
|
||||
self.word_space(":");
|
||||
}
|
||||
self.head("loop");
|
||||
self.s.space();
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Match(ref expr, ref arms) => {
|
||||
@ -2284,6 +2283,9 @@ impl<'a> State<'a> {
|
||||
if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||
options.push("att_syntax");
|
||||
}
|
||||
if opts.contains(InlineAsmOptions::RAW) {
|
||||
options.push("raw");
|
||||
}
|
||||
s.commasep(Inconsistent, &options, |s, &opt| {
|
||||
s.word(opt);
|
||||
});
|
||||
|
@ -1,8 +1,8 @@
|
||||
use super::*;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_span::create_default_session_globals_then;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::with_default_session_globals;
|
||||
|
||||
fn fun_to_string(
|
||||
decl: &ast::FnDecl,
|
||||
@ -24,7 +24,7 @@ fn variant_to_string(var: &ast::Variant) -> String {
|
||||
|
||||
#[test]
|
||||
fn test_fun_to_string() {
|
||||
with_default_session_globals(|| {
|
||||
create_default_session_globals_then(|| {
|
||||
let abba_ident = Ident::from_str("abba");
|
||||
|
||||
let decl =
|
||||
@ -39,7 +39,7 @@ fn test_fun_to_string() {
|
||||
|
||||
#[test]
|
||||
fn test_variant_to_string() {
|
||||
with_default_session_globals(|| {
|
||||
create_default_session_globals_then(|| {
|
||||
let ident = Ident::from_str("principal_skinner");
|
||||
|
||||
let var = ast::Variant {
|
||||
@ -49,7 +49,7 @@ fn test_variant_to_string() {
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None,
|
||||
},
|
||||
attrs: Vec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
|
||||
disr_expr: None,
|
||||
|
@ -862,18 +862,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
sess.mark_attr_used(attr);
|
||||
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;
|
||||
if item.is_word() {
|
||||
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::transparent => Some(ReprTransparent),
|
||||
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),
|
||||
};
|
||||
|
||||
@ -890,23 +895,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
acc.push(h);
|
||||
}
|
||||
} 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;
|
||||
if name == sym::align {
|
||||
recognised = true;
|
||||
@ -920,33 +908,47 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
Ok(literal) => acc.push(ReprPacked(literal)),
|
||||
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 {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0589,
|
||||
"invalid `repr(align)` attribute: {}",
|
||||
"invalid `repr({})` attribute: {}",
|
||||
name.to_ident_string(),
|
||||
literal_error
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} 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;
|
||||
let mut err = struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0693,
|
||||
"incorrect `repr(align)` attribute format"
|
||||
"incorrect `repr({})` attribute format",
|
||||
name,
|
||||
);
|
||||
match value.kind {
|
||||
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("align({})", int),
|
||||
format!("{}({})", name, int),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
@ -954,25 +956,76 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("align({})", s),
|
||||
format!("{}({})", name, s),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
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 {
|
||||
// Not a word we recognize
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0552,
|
||||
"unrecognized representation hint"
|
||||
)
|
||||
.emit();
|
||||
// Not a word we recognize. This will be caught and reported by
|
||||
// the `check_mod_attrs` pass, but this pass doesn't always run
|
||||
// (e.g. if we only pretty-print the source), so we have to gate
|
||||
// the `delay_span_bug` call as follows:
|
||||
if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
|
||||
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1080,3 +1133,16 @@ fn allow_unstable<'a>(
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
@ -356,6 +356,8 @@ fn parse_options<'a>(
|
||||
try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
|
||||
} else if p.eat_keyword(sym::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 {
|
||||
return p.unexpected();
|
||||
}
|
||||
@ -453,7 +455,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
ecx.parse_sess().buffer_lint(
|
||||
lint::builtin::BAD_ASM_STYLE,
|
||||
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",
|
||||
);
|
||||
}
|
||||
@ -461,12 +463,20 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
ecx.parse_sess().buffer_lint(
|
||||
lint::builtin::BAD_ASM_STYLE,
|
||||
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",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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(
|
||||
template_str,
|
||||
str_style,
|
||||
|
@ -24,61 +24,60 @@ crate fn expand(
|
||||
annotatable: Annotatable,
|
||||
) -> Vec<Annotatable> {
|
||||
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> {
|
||||
let mut visitor = CfgEval {
|
||||
crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable {
|
||||
CfgEval {
|
||||
cfg: &mut StripUnconfigured {
|
||||
sess: ecx.sess,
|
||||
features: ecx.ecfg.features,
|
||||
config_tokens: true,
|
||||
},
|
||||
};
|
||||
let annotatable = visitor.configure_annotatable(annotatable);
|
||||
vec![annotatable]
|
||||
}
|
||||
.configure_annotatable(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> {
|
||||
cfg: &'a mut StripUnconfigured<'b>,
|
||||
}
|
||||
|
||||
fn flat_map_annotatable(vis: &mut impl MutVisitor, annotatable: Annotatable) -> Annotatable {
|
||||
// Since the item itself has already been configured by the InvocationCollector,
|
||||
// we know that fold result vector will contain exactly one element
|
||||
fn flat_map_annotatable(
|
||||
vis: &mut impl MutVisitor,
|
||||
annotatable: Annotatable,
|
||||
) -> Option<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(vis.flat_map_trait_item(item).pop().unwrap())
|
||||
vis.flat_map_trait_item(item).pop().map(Annotatable::TraitItem)
|
||||
}
|
||||
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(vis.flat_map_foreign_item(item).pop().unwrap())
|
||||
vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
|
||||
}
|
||||
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);
|
||||
expr
|
||||
}),
|
||||
Annotatable::Arm(arm) => Annotatable::Arm(vis.flat_map_arm(arm).pop().unwrap()),
|
||||
Some(Annotatable::Expr(expr))
|
||||
}
|
||||
Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm),
|
||||
Annotatable::ExprField(field) => {
|
||||
Annotatable::ExprField(vis.flat_map_expr_field(field).pop().unwrap())
|
||||
}
|
||||
Annotatable::PatField(fp) => {
|
||||
Annotatable::PatField(vis.flat_map_pat_field(fp).pop().unwrap())
|
||||
vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField)
|
||||
}
|
||||
Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField),
|
||||
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::FieldDef(sf) => {
|
||||
Annotatable::FieldDef(vis.flat_map_field_def(sf).pop().unwrap())
|
||||
}
|
||||
Annotatable::Variant(v) => Annotatable::Variant(vis.flat_map_variant(v).pop().unwrap()),
|
||||
Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
|
||||
Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
|
||||
Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,11 +122,11 @@ impl CfgEval<'_, '_> {
|
||||
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
|
||||
// performance impact, so try to avoid it if possible
|
||||
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
|
||||
|
@ -26,6 +26,8 @@ impl MultiItemModifier for Expander {
|
||||
return ExpandResult::Ready(vec![item]);
|
||||
}
|
||||
|
||||
let item = cfg_eval(ecx, item);
|
||||
|
||||
let result =
|
||||
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
|
||||
let template =
|
||||
@ -54,12 +56,12 @@ impl MultiItemModifier for Expander {
|
||||
report_path_args(sess, &meta);
|
||||
meta.path
|
||||
})
|
||||
.map(|path| (path, None))
|
||||
.map(|path| (path, item.clone(), None))
|
||||
.collect()
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(()) => ExpandResult::Ready(cfg_eval(ecx, item)),
|
||||
Ok(()) => ExpandResult::Ready(vec![item]),
|
||||
Err(Indeterminate) => ExpandResult::Retry(item),
|
||||
}
|
||||
}
|
||||
@ -82,8 +84,10 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
|
||||
sess,
|
||||
span,
|
||||
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();
|
||||
}
|
||||
bad_target
|
||||
@ -97,6 +101,7 @@ fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) {
|
||||
_ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
|
||||
};
|
||||
struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",)
|
||||
.span_label(lit.span, "not a trait")
|
||||
.help(&help_msg)
|
||||
.emit();
|
||||
}
|
||||
|
@ -36,8 +36,9 @@ pub fn expand_deriving_clone(
|
||||
Annotatable::Item(ref annitem) => match annitem.kind {
|
||||
ItemKind::Struct(_, Generics { ref params, .. })
|
||||
| ItemKind::Enum(_, Generics { ref params, .. }) => {
|
||||
let container_id = cx.current_expansion.id.expn_data().parent;
|
||||
if cx.resolver.has_derive_copy(container_id)
|
||||
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
|
||||
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
|
||||
if has_derive_copy
|
||||
&& !params
|
||||
.iter()
|
||||
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
|
||||
@ -148,11 +149,7 @@ fn cs_clone_shallow(
|
||||
}
|
||||
_ => cx.span_bug(
|
||||
trait_span,
|
||||
&format!(
|
||||
"unexpected substructure in \
|
||||
shallow `derive({})`",
|
||||
name
|
||||
),
|
||||
&format!("unexpected substructure in shallow `derive({})`", name),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -124,12 +124,7 @@ pub fn expand_deriving_rustc_encodable(
|
||||
explicit_self: borrowed_explicit_self(),
|
||||
args: vec![(
|
||||
Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
|
||||
// FIXME: we could use `sym::s` here, but making `s` a static
|
||||
// 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"),
|
||||
sym::s,
|
||||
)],
|
||||
ret_ty: Literal(Path::new_(
|
||||
pathvec_std!(result::Result),
|
||||
|
@ -410,7 +410,7 @@ impl<'a> TraitDef<'a> {
|
||||
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
|
||||
_ => 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 use_temporaries = is_packed && always_copy;
|
||||
|
||||
|
@ -72,13 +72,9 @@ impl Path {
|
||||
) -> ast::Path {
|
||||
let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
|
||||
let lt = mk_lifetimes(cx, span, &self.lifetime);
|
||||
let tys: Vec<P<ast::Ty>> =
|
||||
self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
|
||||
let params = lt
|
||||
.into_iter()
|
||||
.map(GenericArg::Lifetime)
|
||||
.chain(tys.into_iter().map(GenericArg::Type))
|
||||
.collect();
|
||||
let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
|
||||
let params =
|
||||
lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect();
|
||||
|
||||
match self.kind {
|
||||
PathKind::Global => cx.path_all(span, true, idents, params),
|
||||
|
@ -939,6 +939,7 @@ pub fn expand_preparsed_format_args(
|
||||
|
||||
let msg = "format argument must be a string literal";
|
||||
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) {
|
||||
Ok(mut fmt) if append_newline => {
|
||||
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
|
||||
@ -989,7 +990,19 @@ pub fn expand_preparsed_format_args(
|
||||
|
||||
if !parser.errors.is_empty() {
|
||||
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));
|
||||
e.span_label(sp, err.label + " in format string");
|
||||
if let Some(note) = err.note {
|
||||
|
@ -19,7 +19,6 @@ use crate::deriving::*;
|
||||
|
||||
use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
|
||||
use rustc_expand::proc_macro::BangProcMacro;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
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);
|
||||
register(
|
||||
sym::quote,
|
||||
SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client, krate: LOCAL_CRATE })),
|
||||
);
|
||||
register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{self as ast, NodeId};
|
||||
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_session::Session;
|
||||
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) {
|
||||
// Once we've located the `#[proc_macro_derive]` attribute, verify
|
||||
// that it's of the form `#[proc_macro_derive(Foo)]` or
|
||||
// `#[proc_macro_derive(Foo, attributes(A, ..))]`
|
||||
let list = match attr.meta_item_list() {
|
||||
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()
|
||||
};
|
||||
let (trait_name, proc_attrs) =
|
||||
match parse_macro_name_and_helper_attrs(self.handler, attr, "derive") {
|
||||
Some(name_and_attrs) => name_and_attrs,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if self.in_root && item.vis.kind.is_pub() {
|
||||
self.macros.push(ProcMacro::Derive(ProcMacroDerive {
|
||||
id: item.id,
|
||||
span: item.span,
|
||||
trait_name: trait_ident.name,
|
||||
trait_name,
|
||||
function_name: item.ident,
|
||||
attrs: proc_attrs,
|
||||
}));
|
||||
@ -373,7 +304,7 @@ fn mk_decls(
|
||||
&[sym::rustc_attrs, sym::proc_macro_internals],
|
||||
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 krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None));
|
||||
|
@ -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
|
||||
|
@ -34,8 +34,8 @@ pub fn inject(
|
||||
&[sym::prelude_import],
|
||||
None,
|
||||
);
|
||||
let span = DUMMY_SP.with_def_site_ctxt(expn_id);
|
||||
let call_site = DUMMY_SP.with_call_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.to_expn_id());
|
||||
|
||||
let ecfg = ExpansionConfig::default("std_lib_injection".to_string());
|
||||
let cx = ExtCtxt::new(sess, ecfg, resolver, None);
|
||||
|
@ -126,7 +126,8 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||
for test in &mut tests {
|
||||
// See the comment on `mk_main` for why we're using
|
||||
// `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);
|
||||
}
|
||||
@ -223,7 +224,7 @@ fn generate_test_harness(
|
||||
&[sym::test, sym::rustc_attrs],
|
||||
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
|
||||
let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site };
|
||||
|
@ -14,7 +14,7 @@ task:
|
||||
- . $HOME/.cargo/env
|
||||
- git config --global user.email "user@example.com"
|
||||
- git config --global user.name "User"
|
||||
- ./prepare.sh
|
||||
- ./y.rs prepare
|
||||
test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- # Enable backtraces for easier debugging
|
||||
|
@ -19,6 +19,9 @@ jobs:
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: aarch64-unknown-linux-gnu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -49,11 +52,19 @@ jobs:
|
||||
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
|
||||
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
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
./prepare.sh
|
||||
./y.rs prepare
|
||||
|
||||
- name: Build
|
||||
run: ./y.rs build --sysroot none
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
@ -87,3 +98,63 @@ jobs:
|
||||
with:
|
||||
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
|
||||
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
|
||||
|
@ -34,7 +34,7 @@ jobs:
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
./prepare.sh
|
||||
./y.rs prepare
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
@ -72,7 +72,7 @@ jobs:
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
./prepare.sh
|
||||
./y.rs prepare
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
|
@ -1,7 +1,9 @@
|
||||
{
|
||||
// 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.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.linkedProjects": [
|
||||
"./Cargo.toml",
|
||||
@ -49,6 +51,23 @@
|
||||
"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": [],
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
58
compiler/rustc_codegen_cranelift/Cargo.lock
generated
58
compiler/rustc_codegen_cranelift/Cargo.lock
generated
@ -33,16 +33,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"cranelift-bforest",
|
||||
"cranelift-codegen-meta",
|
||||
@ -57,8 +57,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-entity",
|
||||
@ -66,18 +66,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
@ -87,8 +87,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@ -104,8 +104,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@ -115,17 +115,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.74.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
|
||||
version = "0.75.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@ -171,9 +172,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.86"
|
||||
version = "0.2.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
|
||||
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -204,13 +205,20 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.24.0"
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
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 = [
|
||||
"crc32fast",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -9,7 +9,7 @@ crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
# 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-module = { 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" }
|
||||
target-lexicon = "0.12.0"
|
||||
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" }
|
||||
indexmap = "1.0.2"
|
||||
|
@ -10,8 +10,8 @@ If not please open an issue.
|
||||
```bash
|
||||
$ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git
|
||||
$ cd rustc_codegen_cranelift
|
||||
$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking
|
||||
$ ./build.sh
|
||||
$ ./y.rs prepare # download and patch sysroot src and install hyperfine for benchmarking
|
||||
$ ./y.rs build
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
```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.
|
||||
|
@ -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
|
@ -56,7 +56,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.43"
|
||||
version = "0.1.46"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@ -121,9 +121,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
@ -132,9 +132,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.95"
|
||||
version = "0.2.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
|
||||
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@ -195,9 +195,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.19"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
|
||||
checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
|
@ -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}
|
@ -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"
|
@ -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)
|
||||
}
|
216
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
Normal file
216
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
Normal 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()),
|
||||
);
|
||||
}
|
||||
}
|
55
compiler/rustc_codegen_cranelift/build_system/config.rs
Normal file
55
compiler/rustc_codegen_cranelift/build_system/config.rs
Normal 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);
|
||||
}
|
||||
}
|
133
compiler/rustc_codegen_cranelift/build_system/prepare.rs
Normal file
133
compiler/rustc_codegen_cranelift/build_system/prepare.rs
Normal 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);
|
||||
}
|
||||
}
|
65
compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
Normal file
65
compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
Normal 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
|
||||
}
|
35
compiler/rustc_codegen_cranelift/build_system/utils.rs
Normal file
35
compiler/rustc_codegen_cranelift/build_system/utils.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
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/
|
||||
|
17
compiler/rustc_codegen_cranelift/config.txt
Normal file
17
compiler/rustc_codegen_cranelift/config.txt
Normal 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
|
@ -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.
|
||||
|
||||
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
|
||||
|
||||
In the directory with your project (where you can do the usual `cargo build`), run:
|
||||
|
||||
```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.
|
||||
@ -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.
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/cargo.sh jit
|
||||
$ $cg_clif_dir/build/cargo jit
|
||||
```
|
||||
|
||||
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
|
||||
first called. It currently does not work with multi-threaded programs. When a not yet compiled
|
||||
function is called from another thread than the main thread, you will get an ICE.
|
||||
first called.
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/cargo.sh lazy-jit
|
||||
$ $cg_clif_dir/build/cargo lazy-jit
|
||||
```
|
||||
|
||||
## Shell
|
||||
|
@ -292,7 +292,7 @@ fn main() {
|
||||
#[cfg(not(any(jit, windows)))]
|
||||
test_tls();
|
||||
|
||||
#[cfg(all(not(jit), target_os = "linux"))]
|
||||
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
|
||||
unsafe {
|
||||
global_asm_test();
|
||||
}
|
||||
@ -303,12 +303,12 @@ fn main() {
|
||||
assert_eq!(*REF1, *REF2);
|
||||
}
|
||||
|
||||
#[cfg(all(not(jit), target_os = "linux"))]
|
||||
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
|
||||
extern "C" {
|
||||
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 global_asm_test
|
||||
|
@ -15,8 +15,6 @@ fn main() {
|
||||
let stderr = ::std::io::stderr();
|
||||
let mut stderr = stderr.lock();
|
||||
|
||||
// FIXME support lazy jit when multi threading
|
||||
#[cfg(not(lazy_jit))]
|
||||
std::thread::spawn(move || {
|
||||
println!("Hello from another thread!");
|
||||
});
|
||||
|
@ -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
|
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2021-05-26"
|
||||
channel = "nightly-2021-07-07"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
70
compiler/rustc_codegen_cranelift/scripts/cargo.rs
Normal file
70
compiler/rustc_codegen_cranelift/scripts/cargo.rs
Normal 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),
|
||||
);
|
||||
}
|
@ -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
|
@ -2,26 +2,5 @@
|
||||
|
||||
set -e
|
||||
|
||||
dylib=$(echo "" | rustc --print file-names --crate-type dylib --crate-name rustc_codegen_cranelift -)
|
||||
|
||||
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
|
||||
export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH"
|
||||
export DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH"
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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
|
||||
|
||||
@ -25,3 +25,8 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
|
||||
echo "Unknown non-native platform"
|
||||
fi
|
||||
fi
|
||||
|
||||
# FIXME fix `#[linkage = "extern_weak"]` without this
|
||||
if [[ "$(uname)" == 'Darwin' ]]; then
|
||||
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
|
||||
fi
|
||||
|
@ -2,9 +2,10 @@
|
||||
#![forbid(unsafe_code)]/* This line is ignored by bash
|
||||
# This block is ignored by rustc
|
||||
pushd $(dirname "$0")/../
|
||||
source build/config.sh
|
||||
source scripts/config.sh
|
||||
RUSTC="$(pwd)/build/bin/cg_clif"
|
||||
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
|
||||
|
@ -17,7 +17,7 @@ case $1 in
|
||||
done
|
||||
|
||||
./clean_all.sh
|
||||
./prepare.sh
|
||||
./y.rs prepare
|
||||
|
||||
(cd build_sysroot && cargo update)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
./build.sh
|
||||
source build/config.sh
|
||||
./y.rs build
|
||||
source scripts/config.sh
|
||||
|
||||
echo "[SETUP] Rust fork"
|
||||
git clone https://github.com/rust-lang/rust.git || true
|
||||
@ -33,7 +33,7 @@ index d95b5b7f17f..00b6f0e3635 100644
|
||||
[dependencies]
|
||||
core = { path = "../core" }
|
||||
-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]
|
||||
rand = "0.7"
|
||||
|
@ -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/drop/drop-trait-enum.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/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/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/raw-str-nonexpr.rs # same
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
set -e
|
||||
|
||||
source build/config.sh
|
||||
source scripts/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() {
|
||||
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"
|
||||
|
||||
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
|
||||
echo "[JIT] std_example (skipped)"
|
||||
fi
|
||||
@ -75,63 +76,64 @@ function base_sysroot_tests() {
|
||||
|
||||
function extended_sysroot_tests() {
|
||||
pushd rand
|
||||
cargo clean
|
||||
../build/cargo clean
|
||||
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
|
||||
echo "[TEST] rust-random/rand"
|
||||
../build/cargo.sh test --workspace
|
||||
../build/cargo test --workspace
|
||||
else
|
||||
echo "[AOT] rust-random/rand"
|
||||
../build/cargo.sh build --workspace --target $TARGET_TRIPLE --tests
|
||||
../build/cargo build --workspace --target $TARGET_TRIPLE --tests
|
||||
fi
|
||||
popd
|
||||
|
||||
pushd simple-raytracer
|
||||
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
|
||||
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" \
|
||||
"../build/cargo.sh build"
|
||||
"../build/cargo build"
|
||||
|
||||
echo "[BENCH RUN] ebobby/simple-raytracer"
|
||||
cp ./target/debug/main ./raytracer_cg_clif
|
||||
hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif
|
||||
else
|
||||
../build/cargo clean
|
||||
echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
|
||||
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)"
|
||||
fi
|
||||
popd
|
||||
|
||||
pushd build_sysroot/sysroot_src/library/core/tests
|
||||
echo "[TEST] libcore"
|
||||
cargo clean
|
||||
../../../../../build/cargo clean
|
||||
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
|
||||
../../../../../build/cargo.sh test
|
||||
../../../../../build/cargo test
|
||||
else
|
||||
../../../../../build/cargo.sh build --target $TARGET_TRIPLE --tests
|
||||
../../../../../build/cargo build --target $TARGET_TRIPLE --tests
|
||||
fi
|
||||
popd
|
||||
|
||||
pushd regex
|
||||
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
|
||||
# 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
|
||||
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
|
||||
diff -u res.txt examples/regexdna-output.txt
|
||||
fi
|
||||
|
||||
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
|
||||
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
|
||||
echo "[AOT] rust-lang/regex tests"
|
||||
../build/cargo.sh build --tests --target $TARGET_TRIPLE
|
||||
../build/cargo build --tests --target $TARGET_TRIPLE
|
||||
fi
|
||||
popd
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub(crate) fn codegen(
|
||||
});
|
||||
if any_dynamic_crate {
|
||||
false
|
||||
} else if let Some(kind) = tcx.allocator_kind() {
|
||||
} else if let Some(kind) = tcx.allocator_kind(()) {
|
||||
codegen_inner(module, unwind_context, kind);
|
||||
true
|
||||
} else {
|
||||
|
@ -21,6 +21,11 @@ pub(crate) fn codegen_fn<'tcx>(
|
||||
debug_assert!(!instance.substs.needs_infer());
|
||||
|
||||
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
|
||||
let symbol_name = tcx.symbol_name(instance);
|
||||
@ -52,7 +57,6 @@ pub(crate) fn codegen_fn<'tcx>(
|
||||
module,
|
||||
tcx,
|
||||
pointer_type,
|
||||
vtables: FxHashMap::default(),
|
||||
constants_cx: ConstantCx::new(),
|
||||
|
||||
instance,
|
||||
@ -105,7 +109,14 @@ pub(crate) fn codegen_fn<'tcx>(
|
||||
let context = &mut cx.cached_context;
|
||||
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_func(tcx, &clif_comments, &context.func);
|
||||
@ -122,7 +133,13 @@ pub(crate) fn codegen_fn<'tcx>(
|
||||
|
||||
// Perform rust specific optimizations
|
||||
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
|
||||
@ -137,7 +154,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
||||
crate::pretty_clif::write_clif_file(
|
||||
tcx,
|
||||
"opt",
|
||||
Some(module.isa()),
|
||||
module.isa(),
|
||||
instance,
|
||||
&context,
|
||||
&clif_comments,
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![feature(rustc_private)]
|
||||
#![feature(rustc_private, once_cell)]
|
||||
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_driver;
|
||||
@ -6,12 +6,33 @@ extern crate rustc_interface;
|
||||
extern crate rustc_session;
|
||||
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_interface::interface;
|
||||
use rustc_session::config::ErrorOutputType;
|
||||
use rustc_session::early_error;
|
||||
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)]
|
||||
pub struct CraneliftPassesCallbacks {
|
||||
time_passes: bool,
|
||||
@ -37,7 +58,7 @@ fn main() {
|
||||
let start_rss = get_resident_set_size();
|
||||
rustc_driver::init_rustc_env_logger();
|
||||
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 args = std::env::args_os()
|
||||
.enumerate()
|
||||
|
@ -233,7 +233,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
|
||||
pub(crate) module: &'m mut dyn Module,
|
||||
pub(crate) tcx: TyCtxt<'tcx>,
|
||||
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) instance: Instance<'tcx>,
|
||||
|
@ -7,7 +7,7 @@ macro builtin_functions($register:ident; $(fn $name:ident($($arg_name:ident: $ar
|
||||
|
||||
#[cfg(feature = "jit")]
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,13 @@
|
||||
//! 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_errors::ErrorReported;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::interpret::{
|
||||
alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc,
|
||||
Scalar,
|
||||
read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
|
||||
};
|
||||
use rustc_middle::ty::ConstKind;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use cranelift_codegen::ir::GlobalValueData;
|
||||
use cranelift_module::*;
|
||||
@ -171,66 +168,75 @@ pub(crate) fn codegen_const_value<'tcx>(
|
||||
}
|
||||
|
||||
match const_val {
|
||||
ConstValue::Scalar(x) => {
|
||||
if fx.clif_type(layout.ty).is_none() {
|
||||
let (size, align) = (layout.size, layout.align.pref);
|
||||
let mut alloc = Allocation::from_bytes(
|
||||
std::iter::repeat(0).take(size.bytes_usize()).collect::<Vec<u8>>(),
|
||||
align,
|
||||
Mutability::Not,
|
||||
);
|
||||
alloc.write_scalar(fx, alloc_range(Size::ZERO, size), x.into()).unwrap();
|
||||
let alloc = fx.tcx.intern_const_alloc(alloc);
|
||||
return CValue::by_ref(pointer_for_allocation(fx, alloc), layout);
|
||||
}
|
||||
ConstValue::Scalar(x) => match x {
|
||||
Scalar::Int(int) => {
|
||||
if fx.clif_type(layout.ty).is_some() {
|
||||
return CValue::const_val(fx, layout, int);
|
||||
} else {
|
||||
let raw_val = int.to_bits(int.size()).unwrap();
|
||||
let val = match int.size().bytes() {
|
||||
1 => fx.bcx.ins().iconst(types::I8, raw_val as i64),
|
||||
2 => fx.bcx.ins().iconst(types::I16, raw_val as i64),
|
||||
4 => fx.bcx.ins().iconst(types::I32, raw_val as i64),
|
||||
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 {
|
||||
Scalar::Int(int) => CValue::const_val(fx, layout, int),
|
||||
Scalar::Ptr(ptr) => {
|
||||
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)
|
||||
let place = CPlace::new_stack_slot(fx, layout);
|
||||
place.to_ptr().store(fx, val, MemFlags::trusted());
|
||||
place.to_cvalue(fx)
|
||||
}
|
||||
}
|
||||
}
|
||||
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(
|
||||
pointer_for_allocation(fx, alloc)
|
||||
.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>,
|
||||
alloc: &'tcx Allocation,
|
||||
) -> crate::pointer::Pointer {
|
||||
let alloc_id = fx.tcx.create_memory_alloc(alloc);
|
||||
fx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
|
||||
let data_id =
|
||||
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)
|
||||
}
|
||||
|
||||
fn data_id_for_alloc_id(
|
||||
pub(crate) fn data_id_for_alloc_id(
|
||||
cx: &mut ConstantCx,
|
||||
module: &mut dyn Module,
|
||||
alloc_id: AllocId,
|
||||
mutability: rustc_hir::Mutability,
|
||||
) -> DataId {
|
||||
cx.todo.push(TodoItem::Alloc(alloc_id));
|
||||
*cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
|
||||
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::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)
|
||||
}
|
||||
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();
|
||||
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 endianness = tcx.data_layout.endian;
|
||||
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()
|
||||
};
|
||||
|
||||
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 {
|
||||
GlobalAlloc::Function(instance) => {
|
||||
assert_eq!(addend, 0);
|
||||
@ -415,8 +428,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
||||
continue;
|
||||
}
|
||||
GlobalAlloc::Memory(target_alloc) => {
|
||||
cx.todo.push(TodoItem::Alloc(reloc));
|
||||
data_id_for_alloc_id(cx, module, reloc, target_alloc.mutability)
|
||||
data_id_for_alloc_id(cx, module, alloc_id, target_alloc.mutability)
|
||||
}
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
|
||||
|
@ -10,7 +10,7 @@ use rustc_span::{
|
||||
};
|
||||
|
||||
use cranelift_codegen::binemit::CodeOffset;
|
||||
use cranelift_codegen::machinst::MachSrcLoc;
|
||||
use cranelift_codegen::MachSrcLoc;
|
||||
|
||||
use gimli::write::{
|
||||
Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable,
|
||||
|
@ -61,9 +61,11 @@ impl<'tcx> DebugContext<'tcx> {
|
||||
|
||||
let mut dwarf = DwarfUnit::new(encoding);
|
||||
|
||||
// FIXME: how to get version when building out of tree?
|
||||
// Normally this would use option_env!("CFG_VERSION").
|
||||
let producer = format!("cg_clif (rustc {})", "unknown version");
|
||||
let producer = format!(
|
||||
"cg_clif (rustc {}, cranelift {})",
|
||||
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 (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
|
||||
Some(path) => {
|
||||
|
@ -4,7 +4,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_codegen_ssa::back::linker::LinkerInfo;
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
@ -290,14 +289,16 @@ pub(crate) fn run_aot(
|
||||
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((
|
||||
CodegenResults {
|
||||
modules,
|
||||
allocator_module,
|
||||
metadata_module,
|
||||
metadata,
|
||||
linker_info: LinkerInfo::new(tcx, crate::target_triple(tcx.sess).to_string()),
|
||||
crate_info: CrateInfo::new(tcx),
|
||||
crate_info: CrateInfo::new(tcx, target_cpu),
|
||||
},
|
||||
work_products,
|
||||
))
|
||||
|
@ -3,11 +3,14 @@
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CString;
|
||||
use std::lazy::{Lazy, SyncOnceCell};
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::sync::{mpsc, Mutex};
|
||||
|
||||
use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
|
||||
use rustc_codegen_ssa::CrateInfo;
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_session::Session;
|
||||
|
||||
use cranelift_jit::{JITBuilder, JITModule};
|
||||
|
||||
@ -23,12 +26,48 @@ thread_local! {
|
||||
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>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
backend_config: &BackendConfig,
|
||||
hotswap: bool,
|
||||
) -> (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 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))
|
||||
.map(|arg| CString::new(arg).unwrap())
|
||||
.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 {
|
||||
params: vec![
|
||||
@ -128,7 +162,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
||||
AbiParam::new(jit_module.target_config().pointer_type()),
|
||||
],
|
||||
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 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 =
|
||||
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]
|
||||
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| {
|
||||
// lift is used to ensure the correct lifetime for instance.
|
||||
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 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 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();
|
||||
|
||||
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;
|
||||
|
||||
let mut dylib_paths = Vec::new();
|
||||
|
||||
let crate_info = CrateInfo::new(tcx);
|
||||
let formats = tcx.dependency_formats(());
|
||||
let data = &formats
|
||||
let data = &crate_info
|
||||
.dependency_formats
|
||||
.iter()
|
||||
.find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable)
|
||||
.unwrap()
|
||||
.1;
|
||||
for &(cnum, _) in &crate_info.used_crates_dynamic {
|
||||
for &cnum in &crate_info.used_crates {
|
||||
let src = &crate_info.used_crate_source[&cnum];
|
||||
match data[cnum.as_usize() - 1] {
|
||||
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
|
||||
Linkage::Static => {
|
||||
let name = tcx.crate_name(cnum);
|
||||
let mut err =
|
||||
tcx.sess.struct_err(&format!("Can't load static lib {}", name.as_str()));
|
||||
let name = &crate_info.crate_name[&cnum];
|
||||
let mut err = 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.emit();
|
||||
}
|
||||
@ -232,7 +317,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
|
||||
std::mem::forget(lib)
|
||||
}
|
||||
|
||||
tcx.sess.abort_if_errors();
|
||||
sess.abort_if_errors();
|
||||
|
||||
imported_symbols
|
||||
}
|
||||
@ -254,7 +339,7 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
|
||||
Linkage::Import,
|
||||
&Signature {
|
||||
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)],
|
||||
},
|
||||
)
|
||||
@ -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 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 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);
|
||||
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 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();
|
||||
|
@ -106,6 +106,26 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
|
||||
let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
|
||||
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 {
|
||||
@ -121,3 +141,41 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
|
||||
// llvm.x86.avx2.pshuf.b
|
||||
// llvm.x86.avx2.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);
|
||||
}
|
||||
|
@ -1115,6 +1115,40 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
|
||||
);
|
||||
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 {
|
||||
|
@ -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(unused_lifetimes)]
|
||||
#![warn(unreachable_pub)]
|
||||
@ -14,7 +14,9 @@ extern crate rustc_fs_util;
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_incremental;
|
||||
extern crate rustc_index;
|
||||
extern crate rustc_interface;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate rustc_target;
|
||||
@ -98,7 +100,7 @@ mod prelude {
|
||||
pub(crate) use cranelift_codegen::isa::{self, CallConv};
|
||||
pub(crate) use cranelift_codegen::Context;
|
||||
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::base::{codegen_operand, codegen_place};
|
||||
@ -219,10 +221,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
||||
sess,
|
||||
&codegen_results,
|
||||
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 => {
|
||||
let mut builder =
|
||||
cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
|
||||
// Don't use "haswell" as the default, as it implies `has_lzcnt`.
|
||||
// macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
|
||||
builder.enable("nehalem").unwrap();
|
||||
cranelift_codegen::isa::lookup_variant(target_triple.clone(), variant).unwrap();
|
||||
if target_triple.architecture == target_lexicon::Architecture::X86_64 {
|
||||
// Don't use "haswell" as the default, as it implies `has_lzcnt`.
|
||||
// macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
|
||||
builder.enable("nehalem").unwrap();
|
||||
}
|
||||
builder
|
||||
}
|
||||
};
|
||||
|
@ -1,17 +1,20 @@
|
||||
//! Various optimizations specific to cg_clif
|
||||
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub(crate) mod peephole;
|
||||
|
||||
pub(crate) fn optimize_function<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
isa: &dyn TargetIsa,
|
||||
instance: Instance<'tcx>,
|
||||
ctx: &mut Context,
|
||||
clif_comments: &mut crate::pretty_clif::CommentWriter,
|
||||
) {
|
||||
// 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);
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ pub(crate) fn write_ir_file(
|
||||
pub(crate) fn write_clif_file<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
postfix: &str,
|
||||
isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
|
||||
isa: &dyn cranelift_codegen::isa::TargetIsa,
|
||||
instance: Instance<'tcx>,
|
||||
context: &cranelift_codegen::Context,
|
||||
mut clif_comments: &CommentWriter,
|
||||
@ -242,22 +242,23 @@ pub(crate) fn write_clif_file<'tcx>(
|
||||
tcx,
|
||||
|| format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
|
||||
|file| {
|
||||
let value_ranges = isa
|
||||
.map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
|
||||
|
||||
let mut clif = String::new();
|
||||
cranelift_codegen::write::decorate_function(
|
||||
&mut clif_comments,
|
||||
&mut clif,
|
||||
&context.func,
|
||||
&DisplayFunctionAnnotations { isa, value_ranges: value_ranges.as_ref() },
|
||||
&DisplayFunctionAnnotations { isa: Some(isa), value_ranges: None },
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
writeln!(file, "test compile")?;
|
||||
writeln!(file, "set is_pic")?;
|
||||
writeln!(file, "set enable_simd")?;
|
||||
writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
|
||||
for flag in isa.flags().iter() {
|
||||
writeln!(file, "set {}", flag)?;
|
||||
}
|
||||
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)?;
|
||||
file.write_all(clif.as_bytes())?;
|
||||
Ok(())
|
||||
|
@ -31,9 +31,7 @@ pub(crate) fn unsized_info<'tcx>(
|
||||
// change to the vtable.
|
||||
old_info.expect("unsized_info: missing old info for trait upcast")
|
||||
}
|
||||
(_, &ty::Dynamic(ref data, ..)) => {
|
||||
crate::vtable::get_vtable(fx, fx.layout_of(source), data.principal())
|
||||
}
|
||||
(_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
|
||||
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
|
||||
}
|
||||
}
|
||||
|
@ -453,6 +453,10 @@ impl<'tcx> CPlace<'tcx> {
|
||||
ptr.store(fx, data, 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),
|
||||
};
|
||||
//fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index()));
|
||||
|
@ -1,14 +1,10 @@
|
||||
//! Codegen vtables and vtable accesses.
|
||||
//!
|
||||
//! 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::*;
|
||||
|
||||
const DROP_FN_INDEX: usize = 0;
|
||||
const SIZE_INDEX: usize = 1;
|
||||
const ALIGN_INDEX: usize = 2;
|
||||
|
||||
fn vtable_memflags() -> MemFlags {
|
||||
let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
|
||||
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),
|
||||
vtable_memflags(),
|
||||
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),
|
||||
vtable_memflags(),
|
||||
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),
|
||||
vtable_memflags(),
|
||||
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),
|
||||
vtable_memflags(),
|
||||
vtable,
|
||||
((idx + 3) * usize_size as usize) as i32,
|
||||
(idx * usize_size as usize) as i32,
|
||||
);
|
||||
(ptr, func_ref)
|
||||
}
|
||||
|
||||
pub(crate) fn get_vtable<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
) -> Value {
|
||||
let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
|
||||
*data_id
|
||||
} else {
|
||||
let data_id = build_vtable(fx, layout, trait_ref);
|
||||
fx.vtables.insert((layout.ty, trait_ref), data_id);
|
||||
data_id
|
||||
};
|
||||
|
||||
let alloc_id = fx.tcx.vtable_allocation(ty, trait_ref);
|
||||
let data_id =
|
||||
data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not);
|
||||
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)
|
||||
}
|
||||
|
||||
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),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
./build.sh --sysroot none "$@"
|
||||
./y.rs build --sysroot none "$@"
|
||||
|
||||
rm -r target/out || true
|
||||
|
||||
scripts/tests.sh no_sysroot
|
||||
|
||||
./build.sh "$@"
|
||||
./y.rs build "$@"
|
||||
|
||||
scripts/tests.sh base_sysroot
|
||||
scripts/tests.sh extended_sysroot
|
||||
|
153
compiler/rustc_codegen_cranelift/y.rs
Executable file
153
compiler/rustc_codegen_cranelift/y.rs
Executable 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,
|
||||
);
|
||||
}
|
@ -21,10 +21,8 @@ rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_incremental = { path = "../rustc_incremental" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_llvm = { path = "../rustc_llvm" }
|
||||
rustc_metadata = { path = "../rustc_metadata" }
|
||||
|
@ -128,6 +128,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
let mut clobbers = vec![];
|
||||
let mut output_types = vec![];
|
||||
let mut op_idx = FxHashMap::default();
|
||||
let mut clobbered_x87 = false;
|
||||
for (idx, op) in operands.iter().enumerate() {
|
||||
match *op {
|
||||
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 {
|
||||
layout = Some(&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
|
||||
// if the target feature needed by the register class is
|
||||
// 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::vreg) => "w",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => "l",
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
@ -586,6 +610,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "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::zmm_reg) => "v",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
|
||||
InlineAsmRegClass::X86(
|
||||
X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
|
||||
) => unreachable!("clobber-only"),
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
|
||||
@ -617,6 +647,9 @@ fn modifier_to_llvm(
|
||||
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
|
||||
if modifier == Some('v') { None } else { modifier }
|
||||
}
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => None,
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
@ -639,6 +672,9 @@ fn modifier_to_llvm(
|
||||
InlineAsmRegClass::PowerPC(_) => None,
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
|
||||
None if arch == InlineAsmArch::X86_64 => Some('q'),
|
||||
@ -663,6 +699,9 @@ fn modifier_to_llvm(
|
||||
_ => unreachable!(),
|
||||
},
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
|
||||
InlineAsmRegClass::Bpf(_) => None,
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
@ -681,6 +720,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
|
||||
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
|
||||
cx.type_vector(cx.type_i64(), 2)
|
||||
}
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
|
||||
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::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
|
||||
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::zmm_reg) => cx.type_f32(),
|
||||
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::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
|
||||
|
@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_target::spec::{SanitizerSet, StackProbeType};
|
||||
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
|
||||
|
||||
use crate::attributes;
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
|
||||
if cx.sess().must_not_eliminate_frame_pointers() {
|
||||
llvm::AddFunctionAttrStringValue(
|
||||
llfn,
|
||||
llvm::AttributePlace::Function,
|
||||
cstr!("frame-pointer"),
|
||||
cstr!("all"),
|
||||
);
|
||||
pub fn set_frame_pointer_type(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
|
||||
let mut fp = cx.sess().target.frame_pointer;
|
||||
// "mcount" function relies on stack pointer.
|
||||
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
|
||||
if cx.sess().instrument_mcount() || matches!(cx.sess().opts.cg.force_frame_pointers, Some(true))
|
||||
{
|
||||
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.
|
||||
@ -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.
|
||||
set_frame_pointer_elimination(cx, llfn);
|
||||
set_frame_pointer_type(cx, llfn);
|
||||
set_instrument_function(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) {
|
||||
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);
|
||||
|
||||
// Always annotate functions with the target-cpu they are compiled for.
|
||||
|
@ -12,7 +12,7 @@ use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
|
||||
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
|
||||
use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
|
||||
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_span::symbol::Symbol;
|
||||
|
||||
@ -208,10 +208,12 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
|
||||
// have any \0 characters
|
||||
let import_name_vector: Vec<CString> = dll_imports
|
||||
.iter()
|
||||
.map(if self.config.sess.target.arch == "x86" {
|
||||
|import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap()
|
||||
} else {
|
||||
|import: &DllImport| CString::new(import.name.to_string()).unwrap()
|
||||
.map(|import: &DllImport| {
|
||||
if self.config.sess.target.arch == "x86" {
|
||||
LlvmArchiveBuilder::i686_decorated_name(import)
|
||||
} else {
|
||||
CString::new(import.name.to_string()).unwrap()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -391,6 +393,21 @@ impl<'a> LlvmArchiveBuilder<'a> {
|
||||
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 {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user