New upstream version 1.55.0+dfsg1

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

540
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -34,11 +34,13 @@ members = [
"src/tools/unicode-table-generator",
"src/tools/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

View File

@ -21,7 +21,7 @@ Read ["Installation"] from [The Book].
The Rust build system uses a Python script called `x.py` to build the compiler,
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

View File

@ -1,21 +1,150 @@
Version 1.55.0 (2021-09-09)
============================
Language
--------
- [You can now write open "from" range patterns (`X..`), which will start at `X` and
will end at the maximum value of the integer.][83918]
- [You can now explicitly import the prelude of different editions
through `std::prelude` (e.g. `use std::prelude::rust_2021::*;`).][86294]
Compiler
--------
- [Added tier 3\* support for `powerpc64le-unknown-freebsd`.][83572]
\* Refer to Rust's [platform support page][platform-support-doc] for more
information on Rust's tiered platform support.
Libraries
---------
- [Updated std's float parsing to use the Eisel-Lemire algorithm.][86761]
These improvements should in general provide faster string parsing of floats,
no longer reject certain valid floating point values, and reduce
the produced code size for non-stripped artifacts.
- [`string::Drain` now implements `AsRef<str>` and `AsRef<[u8]>`.][86858]
Stabilised APIs
---------------
- [`Bound::cloned`]
- [`Drain::as_str`]
- [`IntoInnerError::into_error`]
- [`IntoInnerError::into_parts`]
- [`MaybeUninit::assume_init_mut`]
- [`MaybeUninit::assume_init_ref`]
- [`MaybeUninit::write`]
- [`array::map`]
- [`ops::ControlFlow`]
- [`x86::_bittest`]
- [`x86::_bittestandcomplement`]
- [`x86::_bittestandreset`]
- [`x86::_bittestandset`]
- [`x86_64::_bittest64`]
- [`x86_64::_bittestandcomplement64`]
- [`x86_64::_bittestandreset64`]
- [`x86_64::_bittestandset64`]
The following previously stable functions are now `const`.
- [`str::from_utf8_unchecked`]
- [`mem::transmute`]
Cargo
-----
- [Cargo will now deduplicate compiler diagnostics to the terminal when invoking
rustc in parallel such as when using `cargo test`.][cargo/9675]
- [The package definition in `cargo metadata` now includes the `"default_run"`
field from the manifest.][cargo/9550]
- [Added `cargo d` as an alias for `cargo doc`.][cargo/9680]
- [Added `{lib}` as formatting option for `cargo tree` to print the `"lib_name"`
of packages.][cargo/9663]
Rustdoc
-------
- [Added "Go to item on exact match" search option.][85876]
- [The "Implementors" section on traits no longer shows redundant
method definitions.][85970]
- [Trait implementations are toggled open by default.][86260] This should make the
implementations more searchable by tools like `CTRL+F` in your browser.
- [Intra-doc links should now correctly resolve associated items (e.g. methods)
through type aliases.][86334]
- [Traits which are marked with `#[doc(hidden)]` will no longer appear in the
"Trait Implementations" section.][86513]
Compatibility Notes
-------------------
- [std functions that return an `io::Error` will no longer use the
`ErrorKind::Other` variant.][85746] This is to better reflect that these
kinds of errors could be categorised [into newer more specific `ErrorKind`
variants][79965], and that they do not represent a user error.
- [Using environment variable names with `process::Command` on Windows now
behaves as expected.][85270] Previously using envionment variables with
`Command` would cause them to be ASCII-uppercased.
- [Rustdoc will now warn on using rustdoc lints that aren't prefixed
with `rustdoc::`][86849]
[86849]: https://github.com/rust-lang/rust/pull/86849
[86513]: https://github.com/rust-lang/rust/pull/86513
[86334]: https://github.com/rust-lang/rust/pull/86334
[86260]: https://github.com/rust-lang/rust/pull/86260
[85970]: https://github.com/rust-lang/rust/pull/85970
[85876]: https://github.com/rust-lang/rust/pull/85876
[83572]: https://github.com/rust-lang/rust/pull/83572
[86294]: https://github.com/rust-lang/rust/pull/86294
[86858]: https://github.com/rust-lang/rust/pull/86858
[86761]: https://github.com/rust-lang/rust/pull/86761
[85769]: https://github.com/rust-lang/rust/pull/85769
[85746]: https://github.com/rust-lang/rust/pull/85746
[85305]: https://github.com/rust-lang/rust/pull/85305
[85270]: https://github.com/rust-lang/rust/pull/85270
[84111]: https://github.com/rust-lang/rust/pull/84111
[83918]: https://github.com/rust-lang/rust/pull/83918
[79965]: https://github.com/rust-lang/rust/pull/79965
[87370]: https://github.com/rust-lang/rust/pull/87370
[87298]: https://github.com/rust-lang/rust/pull/87298
[cargo/9663]: https://github.com/rust-lang/cargo/pull/9663
[cargo/9675]: https://github.com/rust-lang/cargo/pull/9675
[cargo/9550]: https://github.com/rust-lang/cargo/pull/9550
[cargo/9680]: https://github.com/rust-lang/cargo/pull/9680
[cargo/9663]: https://github.com/rust-lang/cargo/pull/9663
[`array::map`]: https://doc.rust-lang.org/stable/std/primitive.array.html#method.map
[`Bound::cloned`]: https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.cloned
[`Drain::as_str`]: https://doc.rust-lang.org/stable/std/string/struct.Drain.html#method.as_str
[`IntoInnerError::into_error`]: https://doc.rust-lang.org/stable/std/io/struct.IntoInnerError.html#method.into_error
[`IntoInnerError::into_parts`]: https://doc.rust-lang.org/stable/std/io/struct.IntoInnerError.html#method.into_parts
[`MaybeUninit::assume_init_mut`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_mut
[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref
[`MaybeUninit::write`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.write
[`Seek::rewind`]: https://doc.rust-lang.org/stable/std/io/trait.Seek.html#method.rewind
[`mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html
[`ops::ControlFlow`]: https://doc.rust-lang.org/stable/std/ops/enum.ControlFlow.html
[`str::from_utf8_unchecked`]: https://doc.rust-lang.org/stable/std/str/fn.from_utf8_unchecked.html
[`x86::_bittest`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittest.html
[`x86::_bittestandcomplement`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittestandcomplement.html
[`x86::_bittestandreset`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittestandreset.html
[`x86::_bittestandset`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittestandset.html
[`x86_64::_bittest64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittest64.html
[`x86_64::_bittestandcomplement64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittestandcomplement64.html
[`x86_64::_bittestandreset64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittestandreset64.html
[`x86_64::_bittestandset64`]: https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bittestandset64.html
Version 1.54.0 (2021-07-29)
============================
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]

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

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

View File

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

View File

@ -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)]

View File

@ -420,7 +420,7 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
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));

View File

@ -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())
}
}

View File

@ -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"));

View File

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

View File

@ -1067,6 +1067,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
eq_sign_span: Span,
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> {

View File

@ -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",
);
}
}
}

View File

@ -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(&param);
}
@ -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(

View File

@ -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.

View File

@ -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 => {

View File

@ -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) = (&param.kind, Some(&*param.bounds), param.ident.span);
for (idx, param) in generics.iter().enumerate() {
let ident = param.ident;
let (kind, bounds, span) = (&param.kind, &param.bounds, ident.span);
let (ord_kind, ident) = match &param.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();
}
}
}

View File

@ -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,

View File

@ -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);
});

View File

@ -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,

View File

@ -862,18 +862,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
if let Some(items) = attr.meta_item_list() {
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")
}
}

View File

@ -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,

View File

@ -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

View File

@ -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();
}

View File

@ -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),
),
}
}

View File

@ -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),

View File

@ -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;

View File

@ -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),

View File

@ -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 {

View File

@ -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 })));
}

View File

@ -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));

View File

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

View File

@ -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);

View File

@ -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 };

View File

@ -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

View File

@ -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

View File

@ -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: |

View File

@ -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": [],
},
]
}
]
}

View File

@ -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]]

View File

@ -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"

View File

@ -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.

View File

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

View File

@ -56,7 +56,7 @@ dependencies = [
[[package]]
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",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash
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/

View File

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

View File

@ -2,14 +2,14 @@
rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
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

View File

@ -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

View File

@ -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!");
});

View File

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

View File

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

View File

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

View File

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

View File

@ -2,26 +2,5 @@
set -e
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"

View File

@ -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

View File

@ -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

View File

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

View File

@ -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"

View File

@ -38,7 +38,8 @@ rm src/test/ui/threads-sendsync/task-stderr.rs
rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs
rm src/test/ui/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

View File

@ -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
}

View File

@ -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 {

View File

@ -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,

View File

@ -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()

View File

@ -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>,

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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,

View File

@ -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) => {

View File

@ -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,
))

View File

@ -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();

View File

@ -106,6 +106,26 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
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);
}

View File

@ -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 {

View File

@ -1,4 +1,4 @@
#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)]
#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)]
#![warn(rust_2018_idioms)]
#![warn(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
}
};

View File

@ -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);
}

View File

@ -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(())

View File

@ -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),
}
}

View File

@ -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()));

View File

@ -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),
},
}
}

View File

@ -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

View File

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

View File

@ -21,10 +21,8 @@ rustc_attr = { path = "../rustc_attr" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_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" }

View File

@ -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(),

View File

@ -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.

View File

@ -12,7 +12,7 @@ use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
use rustc_codegen_ssa::{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