Auto merge of #80439 - Dylan-DPC:rollup-rdxcvon, r=Dylan-DPC

Rollup of 11 pull requests

Successful merges:

 - #79662 (Move some more code out of CodegenBackend::{codegen_crate,link})
 - #79815 (Update RELEASES.md for 1.49.0)
 - #80284 (Suggest fn ptr rather than fn item and suggest to use `Fn` trait bounds rather than the unique closure type in E0121)
 - #80331 (Add more comments to trait queries)
 - #80344 (use matches!() macro in more places)
 - #80353 (BTreeMap: test split_off (and append) more thoroughly)
 - #80362 (Document rustc_macros on nightly-rustc)
 - #80399 (Remove FIXME in rustc_privacy)
 - #80408 (Sync rustc_codegen_cranelift)
 - #80411 (rustc_span: Remove `Symbol::with`)
 - #80434 (bootstrap: put the component name in the tarball temp dir path)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2020-12-28 15:57:50 +00:00
commit 2987785df3
79 changed files with 944 additions and 624 deletions

View File

@ -1,3 +1,131 @@
Version 1.49.0 (2020-12-31)
============================
Language
-----------------------
- [Unions can now implement `Drop`, and you can now have a field in a union
with `ManuallyDrop<T>`.][77547]
- [You can now cast uninhabited enums to integers.][76199]
- [You can now bind by reference and by move in patterns.][76119] This
allows you to selectively borrow individual components of a type. E.g.
```rust
#[derive(Debug)]
struct Person {
name: String,
age: u8,
}
let person = Person {
name: String::from("Alice"),
age: 20,
};
// `name` is moved out of person, but `age` is referenced.
let Person { name, ref age } = person;
println!("{} {}", name, age);
```
Compiler
-----------------------
- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228]
- [Added tier 2 support for `aarch64-apple-darwin`.][75991]
- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914]
- [Added tier 3 support for `mipsel-unknown-none`.][78676]
- [Raised the minimum supported LLVM version to LLVM 9.][78848]
- [Output from threads spawned in tests is now captured.][78227]
- [Change os and vendor values to "none" and "unknown" for some targets][78951]
\* Refer to Rust's [platform support page][forge-platform-support] for more
information on Rust's tiered platform support.
Libraries
-----------------------
- [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109]
- [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997]
- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989]
Stabilized APIs
---------------
- [`slice::select_nth_unstable`]
- [`slice::select_nth_unstable_by`]
- [`slice::select_nth_unstable_by_key`]
The following previously stable methods are now `const`.
- [`Poll::is_ready`]
- [`Poll::is_pending`]
Cargo
-----------------------
- [Building a crate with `cargo-package` should now be independently reproducible.][cargo/8864]
- [`cargo-tree` now marks proc-macro crates.][cargo/8765]
- [Added `CARGO_PRIMARY_PACKAGE` build-time environment variable.][cargo/8758] This
variable will be set if the crate being built is one the user selected to build, either
with `-p` or through defaults.
- [You can now use glob patterns when specifying packages & targets.][cargo/8752]
Compatibility Notes
-------------------
- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier 2 support.][78746]
- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376]
- [Rustc will now check for the validity of some built-in attributes on enum variants.][77015]
Previously such invalid or unused attributes could be ignored.
- Leading whitespace is stripped more uniformly in documentation comments, which may change behavior. You
read [this post about the changes][rustdoc-ws-post] for more details.
- [Trait bounds are no longer inferred for associated types.][79904]
Internal Only
-------------
These changes provide no direct user facing benefits, but represent significant
improvements to the internals and overall performance of rustc and
related tools.
- [rustc's internal crates are now compiled using the `initial-exec` Thread
Local Storage model.][78201]
- [Calculate visibilities once in resolve.][78077]
- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703]
- [Added `--color` for configuring terminal color support to bootstrap.][79004]
[75991]: https://github.com/rust-lang/rust/pull/75991
[78951]: https://github.com/rust-lang/rust/pull/78951
[78848]: https://github.com/rust-lang/rust/pull/78848
[78746]: https://github.com/rust-lang/rust/pull/78746
[78376]: https://github.com/rust-lang/rust/pull/78376
[78228]: https://github.com/rust-lang/rust/pull/78228
[78227]: https://github.com/rust-lang/rust/pull/78227
[78201]: https://github.com/rust-lang/rust/pull/78201
[78109]: https://github.com/rust-lang/rust/pull/78109
[78077]: https://github.com/rust-lang/rust/pull/78077
[77997]: https://github.com/rust-lang/rust/pull/77997
[77703]: https://github.com/rust-lang/rust/pull/77703
[77547]: https://github.com/rust-lang/rust/pull/77547
[77015]: https://github.com/rust-lang/rust/pull/77015
[76199]: https://github.com/rust-lang/rust/pull/76199
[76119]: https://github.com/rust-lang/rust/pull/76119
[75914]: https://github.com/rust-lang/rust/pull/75914
[74989]: https://github.com/rust-lang/rust/pull/74989
[79004]: https://github.com/rust-lang/rust/pull/79004
[78676]: https://github.com/rust-lang/rust/pull/78676
[79904]: https://github.com/rust-lang/rust/issues/79904
[cargo/8864]: https://github.com/rust-lang/cargo/pull/8864
[cargo/8765]: https://github.com/rust-lang/cargo/pull/8765
[cargo/8758]: https://github.com/rust-lang/cargo/pull/8758
[cargo/8752]: https://github.com/rust-lang/cargo/pull/8752
[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable
[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by
[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key
[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html
[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready
[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending
[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc
Version 1.48.0 (2020-11-19)
==========================
@ -10,7 +138,7 @@ Language
Compiler
--------
- [Stabilised the `-C link-self-contained=<yes|no>` compiler flag.][76158] This tells
`rustc` whether to link its own C runtime and libraries or to rely on a external
`rustc` whether to link its own C runtime and libraries or to rely on a external
linker to find them. (Supported only on `windows-gnu`, `linux-musl`, and `wasi` platforms.)
- [You can now use `-C target-feature=+crt-static` on `linux-gnu` targets.][77386]
Note: If you're using cargo you must explicitly pass the `--target` flag.
@ -82,7 +210,7 @@ Compatibility Notes
- [Foreign exceptions are now caught by `catch_unwind` and will cause an abort.][70212]
Note: This behaviour is not guaranteed and is still considered undefined behaviour,
see the [`catch_unwind`] documentation for further information.
Internal Only
@ -102,7 +230,7 @@ related tools.
[76030]: https://github.com/rust-lang/rust/pull/76030/
[70212]: https://github.com/rust-lang/rust/pull/70212/
[27675]: https://github.com/rust-lang/rust/issues/27675/
[54121]: https://github.com/rust-lang/rust/issues/54121/
[54121]: https://github.com/rust-lang/rust/issues/54121/
[71274]: https://github.com/rust-lang/rust/pull/71274/
[77386]: https://github.com/rust-lang/rust/pull/77386/
[77153]: https://github.com/rust-lang/rust/pull/77153/

View File

@ -167,10 +167,7 @@ pub enum GenericArgs {
impl GenericArgs {
pub fn is_angle_bracketed(&self) -> bool {
match *self {
AngleBracketed(..) => true,
_ => false,
}
matches!(self, AngleBracketed(..))
}
pub fn span(&self) -> Span {
@ -629,10 +626,7 @@ impl Pat {
/// Is this a `..` pattern?
pub fn is_rest(&self) -> bool {
match self.kind {
PatKind::Rest => true,
_ => false,
}
matches!(self.kind, PatKind::Rest)
}
}
@ -852,10 +846,7 @@ impl BinOpKind {
}
}
pub fn lazy(&self) -> bool {
match *self {
BinOpKind::And | BinOpKind::Or => true,
_ => false,
}
matches!(self, BinOpKind::And | BinOpKind::Or)
}
pub fn is_comparison(&self) -> bool {
@ -963,17 +954,11 @@ impl Stmt {
}
pub fn is_item(&self) -> bool {
match self.kind {
StmtKind::Item(_) => true,
_ => false,
}
matches!(self.kind, StmtKind::Item(_))
}
pub fn is_expr(&self) -> bool {
match self.kind {
StmtKind::Expr(_) => true,
_ => false,
}
matches!(self.kind, StmtKind::Expr(_))
}
}
@ -1652,26 +1637,17 @@ pub enum LitKind {
impl LitKind {
/// Returns `true` if this literal is a string.
pub fn is_str(&self) -> bool {
match *self {
LitKind::Str(..) => true,
_ => false,
}
matches!(self, LitKind::Str(..))
}
/// Returns `true` if this literal is byte literal string.
pub fn is_bytestr(&self) -> bool {
match self {
LitKind::ByteStr(_) => true,
_ => false,
}
matches!(self, LitKind::ByteStr(_))
}
/// Returns `true` if this is a numeric literal.
pub fn is_numeric(&self) -> bool {
match *self {
LitKind::Int(..) | LitKind::Float(..) => true,
_ => false,
}
matches!(self, LitKind::Int(..) | LitKind::Float(..))
}
/// Returns `true` if this literal has no suffix.
@ -2237,10 +2213,7 @@ impl FnDecl {
self.inputs.get(0).map_or(false, Param::is_self)
}
pub fn c_variadic(&self) -> bool {
self.inputs.last().map_or(false, |arg| match arg.ty.kind {
TyKind::CVarArgs => true,
_ => false,
})
self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs))
}
}

View File

@ -234,10 +234,7 @@ impl MetaItem {
}
pub fn is_word(&self) -> bool {
match self.kind {
MetaItemKind::Word => true,
_ => false,
}
matches!(self.kind, MetaItemKind::Word)
}
pub fn has_name(&self, name: Symbol) -> bool {

View File

@ -130,10 +130,7 @@ impl LitKind {
}
crate fn may_have_suffix(self) -> bool {
match self {
Integer | Float | Err => true,
_ => false,
}
matches!(self, Integer | Float | Err)
}
}
@ -305,10 +302,7 @@ impl TokenKind {
}
pub fn should_end_const_arg(&self) -> bool {
match self {
Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true,
_ => false,
}
matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
}
}
@ -346,18 +340,21 @@ impl Token {
}
pub fn is_op(&self) -> bool {
match self.kind {
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
| Lifetime(..) | Interpolated(..) | Eof => false,
_ => true,
}
!matches!(
self.kind,
OpenDelim(..)
| CloseDelim(..)
| Literal(..)
| DocComment(..)
| Ident(..)
| Lifetime(..)
| Interpolated(..)
| Eof
)
}
pub fn is_like_plus(&self) -> bool {
match self.kind {
BinOp(Plus) | BinOpEq(Plus) => true,
_ => false,
}
matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
}
/// Returns `true` if the token can appear at the start of an expression.
@ -379,13 +376,10 @@ impl Token {
ModSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
Interpolated(ref nt) => match **nt {
NtLiteral(..) |
Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
NtExpr(..) |
NtBlock(..) |
NtPath(..) => true,
_ => false,
},
NtPath(..)),
_ => false,
}
}
@ -405,10 +399,7 @@ impl Token {
Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path
ModSep => true, // global path
Interpolated(ref nt) => match **nt {
NtTy(..) | NtPath(..) => true,
_ => false,
},
Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
_ => false,
}
}
@ -417,10 +408,7 @@ impl Token {
pub fn can_begin_const_arg(&self) -> bool {
match self.kind {
OpenDelim(Brace) => true,
Interpolated(ref nt) => match **nt {
NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
_ => false,
},
Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
_ => self.can_begin_literal_maybe_minus(),
}
}
@ -436,10 +424,7 @@ impl Token {
/// Returns `true` if the token is any literal.
pub fn is_lit(&self) -> bool {
match self.kind {
Literal(..) => true,
_ => false,
}
matches!(self.kind, Literal(..))
}
/// Returns `true` if the token is any literal, a minus (which can prefix a literal,

View File

@ -12,14 +12,14 @@ use crate::ast;
/// |x| 5
/// isn't parsed as (if true {...} else {...} | x) | 5
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
match e.kind {
!matches!(
e.kind,
ast::ExprKind::If(..)
| ast::ExprKind::Match(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::TryBlock(..) => false,
_ => true,
}
| ast::ExprKind::Match(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::TryBlock(..)
)
}

View File

@ -180,10 +180,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
}
rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
if doc_style.is_none() {
let code_to_the_right = match text[pos + token.len..].chars().next() {
Some('\r' | '\n') => false,
_ => true,
};
let code_to_the_right =
!matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n'));
let style = match (code_to_the_left, code_to_the_right) {
(_, true) => CommentStyle::Mixed,
(false, false) => CommentStyle::Isolated,

View File

@ -38,10 +38,9 @@ pub fn expand_deriving_clone(
| ItemKind::Enum(_, Generics { ref params, .. }) => {
let container_id = cx.current_expansion.id.expn_data().parent;
if cx.resolver.has_derive_copy(container_id)
&& !params.iter().any(|param| match param.kind {
ast::GenericParamKind::Type { .. } => true,
_ => false,
})
&& !params
.iter()
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
{
bounds = vec![];
is_shallow = true;

View File

@ -404,12 +404,10 @@ impl<'a> TraitDef<'a> {
let has_no_type_params = match item.kind {
ast::ItemKind::Struct(_, ref generics)
| ast::ItemKind::Enum(_, ref generics)
| ast::ItemKind::Union(_, ref generics) => {
!generics.params.iter().any(|param| match param.kind {
ast::GenericParamKind::Type { .. } => true,
_ => false,
})
}
| ast::ItemKind::Union(_, ref generics) => !generics
.params
.iter()
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
_ => unreachable!(),
};
let container_id = cx.current_expansion.id.expn_data().parent;
@ -868,7 +866,7 @@ impl<'a> MethodDef<'a> {
Self_ if nonstatic => {
self_args.push(arg_expr);
}
Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => {
Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
self_args.push(cx.expr_deref(trait_.span, arg_expr))
}
_ => {

View File

@ -1044,10 +1044,7 @@ pub fn expand_preparsed_format_args(
let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
parse::String(_) => false,
parse::NextArgument(arg) => match arg.position {
parse::Position::ArgumentIs(_) => true,
_ => false,
},
parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)),
});
cx.build_index_map();

View File

@ -580,10 +580,7 @@ pub mod printf {
}
fn is_flag(c: &char) -> bool {
match c {
'0' | '-' | '+' | ' ' | '#' | '\'' => true,
_ => false,
}
matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'')
}
#[cfg(test)]

View File

@ -87,9 +87,11 @@ fn parse_inline_asm<'a>(
// parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
let first_colon = tts
.trees()
.position(|tt| match tt {
tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) => true,
_ => false,
.position(|tt| {
matches!(
tt,
tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
)
})
.unwrap_or(tts.len());
let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());

View File

@ -256,10 +256,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
// we're just not interested in this item.
//
// If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
let is_fn = match item.kind {
ast::ItemKind::Fn(..) => true,
_ => false,
};
let is_fn = matches!(item.kind, ast::ItemKind::Fn(..));
let mut found_attr: Option<&'a ast::Attribute> = None;

View File

@ -1,6 +1,7 @@
{
// source for rustc_* is not included in the rust-src component; disable the errors about this
"rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate"],
"rust-analyzer.assist.importMergeBehaviour": "last",
"rust-analyzer.cargo.loadOutDirsFromCheck": true,
"rust-analyzer.linkedProjects": [
"./Cargo.toml",

View File

@ -50,7 +50,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-entity",
]
@ -58,7 +58,7 @@ dependencies = [
[[package]]
name = "cranelift-codegen"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"byteorder",
"cranelift-bforest",
@ -76,7 +76,7 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
@ -85,17 +85,17 @@ dependencies = [
[[package]]
name = "cranelift-codegen-shared"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
[[package]]
name = "cranelift-entity"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
[[package]]
name = "cranelift-frontend"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-codegen",
"log",
@ -103,10 +103,28 @@ dependencies = [
"target-lexicon",
]
[[package]]
name = "cranelift-jit"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"cranelift-module",
"cranelift-native",
"errno",
"libc",
"log",
"region",
"target-lexicon",
"winapi",
]
[[package]]
name = "cranelift-module"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -118,7 +136,7 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-codegen",
"raw-cpuid",
@ -128,7 +146,7 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -138,23 +156,6 @@ dependencies = [
"target-lexicon",
]
[[package]]
name = "cranelift-simplejit"
version = "0.68.0"
source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
dependencies = [
"cranelift-codegen",
"cranelift-entity",
"cranelift-module",
"cranelift-native",
"errno",
"libc",
"log",
"region",
"target-lexicon",
"winapi",
]
[[package]]
name = "crc32fast"
version = "1.2.1"
@ -325,9 +326,9 @@ dependencies = [
"ar",
"cranelift-codegen",
"cranelift-frontend",
"cranelift-jit",
"cranelift-module",
"cranelift-object",
"cranelift-simplejit",
"gimli",
"indexmap",
"libloading",

View File

@ -12,7 +12,7 @@ crate-type = ["dylib"]
cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
cranelift-simplejit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
target-lexicon = "0.11.0"
gimli = { version = "0.23.0", default-features = false, features = ["write"]}
@ -27,7 +27,7 @@ libloading = { version = "0.6.0", optional = true }
#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
#cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
#cranelift-module = { path = "../wasmtime/cranelift/module" }
#cranelift-simplejit = { path = "../wasmtime/cranelift/simplejit" }
#cranelift-jit = { path = "../wasmtime/cranelift/jit" }
#cranelift-object = { path = "../wasmtime/cranelift/object" }
#[patch.crates-io]
@ -35,7 +35,7 @@ libloading = { version = "0.6.0", optional = true }
[features]
default = ["jit", "inline_asm"]
jit = ["cranelift-simplejit", "libloading"]
jit = ["cranelift-jit", "libloading"]
inline_asm = []
[profile.dev]

View File

@ -2,7 +2,7 @@
> ⚠⚠⚠ Certain kinds of FFI don't work yet. ⚠⚠⚠
The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/master/cranelift).
The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift).
This has the potential to improve compilation times in debug mode.
If your project doesn't use any of the things listed under "Not yet supported", it should work fine.
If not please open an issue.
@ -68,7 +68,15 @@ $ $cg_clif_dir/build/cargo.sh jit
or
```bash
$ $cg_clif_dir/build/bin/cg_clif --jit my_crate.rs
$ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
```
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.
```bash
$ $cg_clif_dir/build/cargo.sh lazy-jit
```
### Shell
@ -77,7 +85,7 @@ These are a few functions that allow you to easily run rust code from the shell
```bash
function jit_naked() {
echo "$@" | $cg_clif_dir/build/bin/cg_clif - --jit
echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Cllvm-args=mode=jit -Cprefer-dynamic
}
function jit() {

View File

@ -47,9 +47,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "cc"
version = "1.0.65"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
@ -141,9 +141,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.80"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
dependencies = [
"rustc-std-workspace-core",
]

View File

@ -5,13 +5,14 @@ version = "0.0.0"
[dependencies]
core = { path = "./sysroot_src/library/core" }
compiler_builtins = "0.1"
alloc = { path = "./sysroot_src/library/alloc" }
std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
test = { path = "./sysroot_src/library/test" }
alloc_system = { path = "./alloc_system" }
compiler_builtins = { version = "=0.1.36", default-features = false }
[patch.crates-io]
rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }

View File

@ -15,6 +15,8 @@ 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 +1 @@
nightly-2020-11-27
nightly-2020-12-23

View File

@ -10,7 +10,9 @@ cmd=$1
shift || true
if [[ "$cmd" = "jit" ]]; then
cargo "+${TOOLCHAIN}" rustc "$@" -- --jit
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

@ -4,7 +4,7 @@
pushd $(dirname "$0")/../
source build/config.sh
popd
PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS --jit $0
PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/
//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse

View File

@ -15,7 +15,10 @@ function no_sysroot_tests() {
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] mini_core_hello_world"
CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC --jit example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
echo "[JIT-lazy] mini_core_hello_world"
CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
else
echo "[JIT] mini_core_hello_world (skipped)"
fi
@ -37,7 +40,10 @@ function base_sysroot_tests() {
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] std_example"
$MY_RUSTC --jit example/std_example.rs --target "$HOST_TRIPLE"
$MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
echo "[JIT-lazy] std_example"
$MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --cfg lazy_jit --target "$HOST_TRIPLE"
else
echo "[JIT] std_example (skipped)"
fi

View File

@ -162,7 +162,7 @@ impl AddConstructor for ObjectProduct {
}
pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
let triple = crate::build_isa(sess, true).triple().clone();
let triple = crate::build_isa(sess).triple().clone();
let binary_format = match triple.binary_format {
target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
@ -193,7 +193,7 @@ pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object
pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
let mut builder = ObjectBuilder::new(
crate::build_isa(sess, true),
crate::build_isa(sess),
name + ".o",
cranelift_module::default_libcall_names(),
)

View File

@ -118,6 +118,8 @@ pub(crate) fn codegen_fn<'tcx>(
context.eliminate_unreachable_code(cx.module.isa()).unwrap();
context.dce(cx.module.isa()).unwrap();
context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
// Define function
let module = &mut cx.module;
tcx.sess.time("define function", || {
@ -140,6 +142,16 @@ pub(crate) fn codegen_fn<'tcx>(
&clif_comments,
);
if let Some(mach_compile_result) = &context.mach_compile_result {
if let Some(disasm) = &mach_compile_result.disasm {
crate::pretty_clif::write_ir_file(
tcx,
&format!("{}.vcode", tcx.symbol_name(instance).name),
|file| file.write_all(disasm.as_bytes()),
)
}
}
// Define debuginfo for function
let isa = cx.module.isa();
let debug_context = &mut cx.debug_context;
@ -307,7 +319,9 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) {
} => {
let discr = codegen_operand(fx, discr).load_scalar(fx);
if switch_ty.kind() == fx.tcx.types.bool.kind() {
let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
|| (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
if use_bool_opt {
assert_eq!(targets.iter().count(), 1);
let (then_value, then_block) = targets.iter().next().unwrap();
let then_block = fx.get_block(then_block);
@ -325,12 +339,22 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) {
let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
let discr =
crate::optimize::peephole::make_branchable_value(&mut fx.bcx, discr);
if test_zero {
fx.bcx.ins().brz(discr, then_block, &[]);
fx.bcx.ins().jump(else_block, &[]);
if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
&fx.bcx, discr, test_zero,
) {
if taken {
fx.bcx.ins().jump(then_block, &[]);
} else {
fx.bcx.ins().jump(else_block, &[]);
}
} else {
fx.bcx.ins().brnz(discr, then_block, &[]);
fx.bcx.ins().jump(else_block, &[]);
if test_zero {
fx.bcx.ins().brz(discr, then_block, &[]);
fx.bcx.ins().jump(else_block, &[]);
} else {
fx.bcx.ins().brnz(discr, then_block, &[]);
fx.bcx.ins().jump(else_block, &[]);
}
}
} else {
let mut switch = ::cranelift_frontend::Switch::new();

View File

@ -44,9 +44,7 @@ fn main() {
let mut callbacks = CraneliftPassesCallbacks::default();
rustc_driver::install_ice_hook();
let exit_code = rustc_driver::catch_with_exit_code(|| {
let mut use_jit = false;
let mut args = std::env::args_os()
let args = std::env::args_os()
.enumerate()
.map(|(i, arg)| {
arg.into_string().unwrap_or_else(|arg| {
@ -56,23 +54,10 @@ fn main() {
)
})
})
.filter(|arg| {
if arg == "--jit" {
use_jit = true;
false
} else {
true
}
})
.collect::<Vec<_>>();
if use_jit {
args.push("-Cprefer-dynamic".to_string());
}
let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
config: rustc_codegen_cranelift::BackendConfig { use_jit },
})
Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
})));
run_compiler.run()
});

View File

@ -92,9 +92,7 @@ fn main() {
let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
if use_clif {
run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
config: rustc_codegen_cranelift::BackendConfig { use_jit: false },
})
Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
})));
}
run_compiler.run()

View File

@ -100,7 +100,10 @@ fn codegen_static_ref<'tcx>(
let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
assert!(!layout.is_unsized(), "unsized statics aren't supported");
assert!(
matches!(fx.bcx.func.global_values[local_data_id], GlobalValueData::Symbol { tls: false, ..}),
matches!(
fx.bcx.func.global_values[local_data_id],
GlobalValueData::Symbol { tls: false, .. }
),
"tls static referenced without Rvalue::ThreadLocalRef"
);
CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout)
@ -447,7 +450,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut impl Module, cx: &mut Constan
data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
}
module.define_data(data_id, &data_ctx).unwrap();
// FIXME don't duplicate definitions in lazy jit mode
let _ = module.define_data(data_id, &data_ctx);
cx.done.insert(data_id);
}

View File

@ -74,10 +74,7 @@ impl WriterRelocate {
/// Perform the collected relocations to be usable for JIT usage.
#[cfg(feature = "jit")]
pub(super) fn relocate_for_jit(
mut self,
jit_module: &cranelift_simplejit::SimpleJITModule,
) -> Vec<u8> {
pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
use std::convert::TryInto;
for reloc in self.relocs.drain(..) {

View File

@ -15,11 +15,11 @@ pub(crate) struct UnwindContext<'tcx> {
}
impl<'tcx> UnwindContext<'tcx> {
pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
let mut frame_table = FrameTable::default();
let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
if isa.flags().is_pic() {
if pic_eh_frame {
cie.fde_address_encoding =
gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0);
}
@ -80,7 +80,7 @@ impl<'tcx> UnwindContext<'tcx> {
#[cfg(feature = "jit")]
pub(crate) unsafe fn register_jit(
self,
jit_module: &cranelift_simplejit::SimpleJITModule,
jit_module: &cranelift_jit::JITModule,
) -> Option<UnwindRegistry> {
let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(
self.tcx,

View File

@ -8,7 +8,7 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{DebugInfo, OutputType};
@ -146,11 +146,34 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege
}
}
let mut cx = crate::CodegenCx::new(tcx, module, tcx.sess.opts.debuginfo != DebugInfo::None);
let mut cx = crate::CodegenCx::new(
tcx,
module,
tcx.sess.opts.debuginfo != DebugInfo::None,
true,
);
super::predefine_mono_items(&mut cx, &mono_items);
for (mono_item, (linkage, visibility)) in mono_items {
let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
super::codegen_mono_item(&mut cx, mono_item, linkage);
match mono_item {
MonoItem::Fn(inst) => {
cx.tcx.sess.time("codegen fn", || {
crate::base::codegen_fn(&mut cx, inst, linkage)
});
}
MonoItem::Static(def_id) => {
crate::constant::codegen_static(&mut cx.constants_cx, def_id)
}
MonoItem::GlobalAsm(hir_id) => {
let item = cx.tcx.hir().expect_item(hir_id);
if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
cx.global_asm.push_str(&*asm.as_str());
cx.global_asm.push_str("\n\n");
} else {
bug!("Expected GlobalAsm found {:?}", item);
}
}
}
}
let (mut module, global_asm, debug, mut unwind_context) =
tcx.sess.time("finalize CodegenCx", || cx.finalize());
@ -236,7 +259,7 @@ pub(super) fn run_aot(
tcx.sess.abort_if_errors();
let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa());
let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
let created_alloc_shim =
crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);

View File

@ -1,16 +1,23 @@
//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
//! files.
use std::cell::RefCell;
use std::ffi::CString;
use std::os::raw::{c_char, c_int};
use rustc_codegen_ssa::CrateInfo;
use rustc_middle::mir::mono::MonoItem;
use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule};
use cranelift_jit::{JITBuilder, JITModule};
use crate::prelude::*;
use crate::{CodegenCx, CodegenMode};
pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
thread_local! {
pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None);
}
pub(super) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode) -> ! {
if !tcx.sess.opts.output_types.should_codegen() {
tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
}
@ -35,12 +42,13 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
let imported_symbols = load_imported_symbols_for_jit(tcx);
let mut jit_builder = SimpleJITBuilder::with_isa(
crate::build_isa(tcx.sess, false),
let mut jit_builder = JITBuilder::with_isa(
crate::build_isa(tcx.sess),
cranelift_module::default_libcall_names(),
);
jit_builder.hotswap(matches!(codegen_mode, CodegenMode::JitLazy));
jit_builder.symbols(imported_symbols);
let mut jit_module = SimpleJITModule::new(jit_builder);
let mut jit_module = JITModule::new(jit_builder);
assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
let sig = Signature {
@ -66,20 +74,42 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
.into_iter()
.collect::<Vec<(_, (_, _))>>();
let mut cx = crate::CodegenCx::new(tcx, jit_module, false);
let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
super::time(tcx, "codegen mono items", || {
super::predefine_mono_items(&mut cx, &mono_items);
for (mono_item, (linkage, visibility)) in mono_items {
let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
match mono_item {
MonoItem::Fn(inst) => match codegen_mode {
CodegenMode::Aot => unreachable!(),
CodegenMode::Jit => {
cx.tcx.sess.time("codegen fn", || {
crate::base::codegen_fn(&mut cx, inst, linkage)
});
}
CodegenMode::JitLazy => codegen_shim(&mut cx, inst),
},
MonoItem::Static(def_id) => {
crate::constant::codegen_static(&mut cx.constants_cx, def_id);
}
MonoItem::GlobalAsm(hir_id) => {
let item = cx.tcx.hir().expect_item(hir_id);
tcx.sess
.span_fatal(item.span, "Global asm is not supported in JIT mode");
}
}
}
});
let (mut jit_module, global_asm, _debug, mut unwind_context) =
super::time(tcx, "codegen mono items", || {
super::predefine_mono_items(&mut cx, &mono_items);
for (mono_item, (linkage, visibility)) in mono_items {
let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
super::codegen_mono_item(&mut cx, mono_item, linkage);
}
tcx.sess.time("finalize CodegenCx", || cx.finalize())
});
tcx.sess.time("finalize CodegenCx", || cx.finalize());
jit_module.finalize_definitions();
if !global_asm.is_empty() {
tcx.sess.fatal("Global asm is not supported in JIT mode");
tcx.sess.fatal("Inline asm is not supported in JIT mode");
}
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context, true);
crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
@ -91,7 +121,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed");
println!("Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed");
let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
unsafe { ::std::mem::transmute(finalized_main) };
@ -107,11 +137,50 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
// useful as some dynamic linkers use it as a marker to jump over.
argv.push(std::ptr::null());
CURRENT_MODULE
.with(|current_module| assert!(current_module.borrow_mut().replace(jit_module).is_none()));
let ret = f(args.len() as c_int, argv.as_ptr());
std::process::exit(ret);
}
#[no_mangle]
extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *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();
CURRENT_MODULE.with(|jit_module| {
let mut jit_module = jit_module.borrow_mut();
let jit_module = jit_module.as_mut().unwrap();
let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
let (name, sig) = crate::abi::get_function_name_and_sig(
tcx,
cx.module.isa().triple(),
instance,
true,
);
let func_id = cx
.module
.declare_function(&name, Linkage::Export, &sig)
.unwrap();
cx.module.prepare_for_function_redefine(func_id).unwrap();
tcx.sess.time("codegen fn", || {
crate::base::codegen_fn(&mut cx, instance, Linkage::Export)
});
let (jit_module, global_asm, _debug_context, unwind_context) = cx.finalize();
assert!(global_asm.is_empty());
jit_module.finalize_definitions();
std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) });
jit_module.get_finalized_function(func_id)
})
})
}
fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
use rustc_middle::middle::dependency_format::Linkage;
@ -171,3 +240,68 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
imported_symbols
}
pub(super) fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx, impl Module>, inst: Instance<'tcx>) {
let tcx = cx.tcx;
let pointer_type = cx.module.target_config().pointer_type();
let (name, sig) =
crate::abi::get_function_name_and_sig(tcx, cx.module.isa().triple(), inst, true);
let func_id = cx
.module
.declare_function(&name, Linkage::Export, &sig)
.unwrap();
let instance_ptr = Box::into_raw(Box::new(inst));
let jit_fn = cx
.module
.declare_function(
"__clif_jit_fn",
Linkage::Import,
&Signature {
call_conv: cx.module.target_config().default_call_conv,
params: vec![AbiParam::new(pointer_type)],
returns: vec![AbiParam::new(pointer_type)],
},
)
.unwrap();
let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone());
let mut builder_ctx = FunctionBuilderContext::new();
let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx);
let jit_fn = cx
.module
.declare_func_in_func(jit_fn, trampoline_builder.func);
let sig_ref = trampoline_builder.func.import_signature(sig);
let entry_block = trampoline_builder.create_block();
trampoline_builder.append_block_params_for_function_params(entry_block);
let fn_args = trampoline_builder
.func
.dfg
.block_params(entry_block)
.to_vec();
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 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();
trampoline_builder.ins().return_(&ret_vals);
cx.module
.define_function(
func_id,
&mut Context::for_function(trampoline),
&mut cranelift_codegen::binemit::NullTrapSink {},
)
.unwrap();
}

View File

@ -7,6 +7,7 @@ use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
use crate::prelude::*;
use crate::CodegenMode;
mod aot;
#[cfg(feature = "jit")]
@ -20,24 +21,25 @@ pub(crate) fn codegen_crate(
) -> Box<dyn Any> {
tcx.sess.abort_if_errors();
if config.use_jit {
let is_executable = tcx
.sess
.crate_types()
.contains(&rustc_session::config::CrateType::Executable);
if !is_executable {
tcx.sess.fatal("can't jit non-executable crate");
match config.codegen_mode {
CodegenMode::Aot => aot::run_aot(tcx, metadata, need_metadata_module),
CodegenMode::Jit | CodegenMode::JitLazy => {
let is_executable = tcx
.sess
.crate_types()
.contains(&rustc_session::config::CrateType::Executable);
if !is_executable {
tcx.sess.fatal("can't jit non-executable crate");
}
#[cfg(feature = "jit")]
let _: ! = jit::run_jit(tcx, config.codegen_mode);
#[cfg(not(feature = "jit"))]
tcx.sess
.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
}
#[cfg(feature = "jit")]
let _: ! = jit::run_jit(tcx);
#[cfg(not(feature = "jit"))]
tcx.sess
.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
}
aot::run_aot(tcx, metadata, need_metadata_module)
}
fn predefine_mono_items<'tcx>(
@ -63,30 +65,6 @@ fn predefine_mono_items<'tcx>(
});
}
fn codegen_mono_item<'tcx, M: Module>(
cx: &mut crate::CodegenCx<'tcx, M>,
mono_item: MonoItem<'tcx>,
linkage: Linkage,
) {
match mono_item {
MonoItem::Fn(inst) => {
cx.tcx
.sess
.time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage));
}
MonoItem::Static(def_id) => crate::constant::codegen_static(&mut cx.constants_cx, def_id),
MonoItem::GlobalAsm(hir_id) => {
let item = cx.tcx.hir().expect_item(hir_id);
if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
cx.global_asm.push_str(&*asm.as_str());
cx.global_asm.push_str("\n\n");
} else {
bug!("Expected GlobalAsm found {:?}", item);
}
}
}
}
fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
if std::env::var("CG_CLIF_DISPLAY_CG_TIME")
.as_ref()

View File

@ -23,8 +23,8 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) {
let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, a.layout());
let lane_ty = fx.clif_type(lane_layout.ty).unwrap();
let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
let lane_ty = fx.clif_type(lane_ty).unwrap();
assert!(lane_count <= 32);
let mut res = fx.bcx.ins().iconst(types::I32, 0);

View File

@ -171,27 +171,6 @@ macro validate_simd_type($fx:ident, $intrinsic:ident, $span:ident, $ty:expr) {
}
}
fn lane_type_and_count<'tcx>(
tcx: TyCtxt<'tcx>,
layout: TyAndLayout<'tcx>,
) -> (TyAndLayout<'tcx>, u16) {
assert!(layout.ty.is_simd());
let lane_count = match layout.fields {
rustc_target::abi::FieldsShape::Array { stride: _, count } => u16::try_from(count).unwrap(),
_ => unreachable!("lane_type_and_count({:?})", layout),
};
let lane_layout = layout
.field(
&ty::layout::LayoutCx {
tcx,
param_env: ParamEnv::reveal_all(),
},
0,
)
.unwrap();
(lane_layout, lane_count)
}
pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
let (element, count) = match &layout.abi {
Abi::Vector { element, count } => (element.clone(), *count),
@ -218,8 +197,10 @@ fn simd_for_each_lane<'tcx, M: Module>(
) {
let layout = val.layout();
let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
let lane_layout = fx.layout_of(lane_ty);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
let ret_lane_layout = fx.layout_of(ret_lane_ty);
assert_eq!(lane_count, ret_lane_count);
for lane_idx in 0..lane_count {
@ -248,8 +229,10 @@ fn simd_pair_for_each_lane<'tcx, M: Module>(
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
let lane_layout = fx.layout_of(lane_ty);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
let ret_lane_layout = fx.layout_of(ret_lane_ty);
assert_eq!(lane_count, ret_lane_count);
for lane in 0..lane_count {
@ -269,13 +252,14 @@ fn simd_reduce<'tcx, M: Module>(
ret: CPlace<'tcx>,
f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, TyAndLayout<'tcx>, Value, Value) -> Value,
) {
let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
let (lane_count, lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
let lane_layout = fx.layout_of(lane_ty);
assert_eq!(lane_layout, ret.layout());
let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
for lane_idx in 1..lane_count {
let lane = val
.value_field(fx, mir::Field::new(lane_idx.into()))
.value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
.load_scalar(fx);
res_val = f(fx, lane_layout, res_val, lane);
}
@ -289,14 +273,14 @@ fn simd_reduce_bool<'tcx, M: Module>(
ret: CPlace<'tcx>,
f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, Value, Value) -> Value,
) {
let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
assert!(ret.layout().ty.is_bool());
let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean
for lane_idx in 1..lane_count {
let lane = val
.value_field(fx, mir::Field::new(lane_idx.into()))
.value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
.load_scalar(fx);
let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
res_val = f(fx, res_val, lane);
@ -460,9 +444,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
"abort" => {
trap_abort(fx, "Called intrinsic::abort.");
}
"unreachable" => {
trap_unreachable(fx, "[corruption] Called intrinsic::unreachable.");
}
"transmute" => {
crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
}
@ -575,12 +556,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
}
};
discriminant_value, (c ptr) {
let pointee_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), pointee_layout);
let discr = crate::discriminant::codegen_get_discriminant(fx, val, ret.layout());
ret.write_cvalue(fx, discr);
};
size_of_val, <T> (c ptr) {
let layout = fx.layout_of(T);
let size = if layout.is_unsized() {
@ -641,22 +616,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
);
ret.write_cvalue(fx, res);
};
_ if intrinsic.starts_with("wrapping_"), (c x, c y) {
assert_eq!(x.layout().ty, y.layout().ty);
let bin_op = match intrinsic {
"wrapping_add" => BinOp::Add,
"wrapping_sub" => BinOp::Sub,
"wrapping_mul" => BinOp::Mul,
_ => unreachable!("intrinsic {}", intrinsic),
};
let res = crate::num::codegen_int_binop(
fx,
bin_op,
x,
y,
);
ret.write_cvalue(fx, res);
};
_ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) {
assert_eq!(lhs.layout().ty, rhs.layout().ty);
let bin_op = match intrinsic {
@ -916,7 +875,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
dest.write_cvalue(fx, val);
};
size_of | pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
let const_val =
fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
let val = crate::constant::codegen_const_value(

View File

@ -73,11 +73,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout);
let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(lane_type, ret_lane_type);
assert_eq!(n, ret_lane_count);
assert_eq!(lane_ty, ret_lane_ty);
assert_eq!(u64::from(n), ret_lane_count);
let total_len = lane_count * 2;
@ -105,14 +105,14 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
};
for &idx in &indexes {
assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
}
for (out_idx, in_idx) in indexes.into_iter().enumerate() {
let in_lane = if in_idx < lane_count {
let in_lane = if u64::from(in_idx) < lane_count {
x.value_field(fx, mir::Field::new(in_idx.into()))
} else {
y.value_field(fx, mir::Field::new((in_idx - lane_count).into()))
y.value_field(fx, mir::Field::new(usize::from(in_idx) - usize::try_from(lane_count).unwrap()))
};
let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
out_lane.write_cvalue(fx, in_lane);
@ -131,7 +131,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
};
let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout());
let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
}
@ -160,7 +160,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
};
let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout());
let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
}
@ -212,12 +212,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
assert_eq!(a.layout(), c.layout());
let layout = a.layout();
let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(lane_count, ret_lane_count);
let ret_lane_layout = fx.layout_of(ret_lane_ty);
for lane in 0..lane_count {
let lane = mir::Field::new(lane.into());
let lane = mir::Field::new(lane.try_into().unwrap());
let a_lane = a.value_field(fx, lane).load_scalar(fx);
let b_lane = b.value_field(fx, lane).load_scalar(fx);
let c_lane = c.value_field(fx, lane).load_scalar(fx);

View File

@ -5,7 +5,8 @@
associated_type_bounds,
never_type,
try_blocks,
hash_drain_filter
hash_drain_filter,
str_split_once
)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
@ -34,6 +35,7 @@ extern crate rustc_target;
extern crate rustc_driver;
use std::any::Any;
use std::str::FromStr;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
@ -141,8 +143,8 @@ struct CodegenCx<'tcx, M: Module> {
}
impl<'tcx, M: Module> CodegenCx<'tcx, M> {
fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool) -> Self {
let unwind_context = UnwindContext::new(tcx, module.isa());
fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool, pic_eh_frame: bool) -> Self {
let unwind_context = UnwindContext::new(tcx, module.isa(), pic_eh_frame);
let debug_context = if debug_info {
Some(DebugContext::new(tcx, module.isa()))
} else {
@ -172,12 +174,55 @@ impl<'tcx, M: Module> CodegenCx<'tcx, M> {
}
#[derive(Copy, Clone, Debug)]
pub enum CodegenMode {
Aot,
Jit,
JitLazy,
}
impl Default for CodegenMode {
fn default() -> Self {
CodegenMode::Aot
}
}
impl FromStr for CodegenMode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"aot" => Ok(CodegenMode::Aot),
"jit" => Ok(CodegenMode::Jit),
"jit-lazy" => Ok(CodegenMode::JitLazy),
_ => Err(format!("Unknown codegen mode `{}`", s)),
}
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct BackendConfig {
pub use_jit: bool,
pub codegen_mode: CodegenMode,
}
impl BackendConfig {
fn from_opts(opts: &[String]) -> Result<Self, String> {
let mut config = BackendConfig::default();
for opt in opts {
if let Some((name, value)) = opt.split_once('=') {
match name {
"mode" => config.codegen_mode = value.parse()?,
_ => return Err(format!("Unknown option `{}`", name)),
}
} else {
return Err(format!("Invalid option `{}`", opt));
}
}
Ok(config)
}
}
pub struct CraneliftCodegenBackend {
pub config: BackendConfig,
pub config: Option<BackendConfig>,
}
impl CodegenBackend for CraneliftCodegenBackend {
@ -204,7 +249,13 @@ impl CodegenBackend for CraneliftCodegenBackend {
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<dyn Any> {
let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);
let config = if let Some(config) = self.config {
config
} else {
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
.unwrap_or_else(|err| tcx.sess.fatal(&err))
};
let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config);
rustc_symbol_mangling::test::report_symbol_names(tcx);
@ -250,17 +301,13 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
sess.target.llvm_target.parse().unwrap()
}
fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
use target_lexicon::BinaryFormat;
let target_triple = crate::target_triple(sess);
let mut flags_builder = settings::builder();
if enable_pic {
flags_builder.enable("is_pic").unwrap();
} else {
flags_builder.set("is_pic", "false").unwrap();
}
flags_builder.enable("is_pic").unwrap();
flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
flags_builder
.set(
@ -283,8 +330,6 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
flags_builder.set("enable_simd", "true").unwrap();
// FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
/*
use rustc_session::config::OptLevel;
match sess.opts.optimize {
OptLevel::No => {
@ -297,7 +342,7 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
OptLevel::Size | OptLevel::SizeMin => {
sess.warn("Optimizing for size is not supported. Just ignoring the request");
}
}*/
}
let flags = settings::Flags::new(flags_builder);
@ -311,7 +356,5 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
Box::new(CraneliftCodegenBackend {
config: BackendConfig { use_jit: false },
})
Box::new(CraneliftCodegenBackend { config: None })
}

View File

@ -73,7 +73,7 @@ pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -
})()
.unwrap_or_else(|| {
match bcx.func.dfg.value_type(arg) {
types::I8 | types::I32 => {
types::I8 | types::I16 => {
// WORKAROUND for brz.i8 and brnz.i8 not yet being implemented
bcx.ins().uextend(types::I32, arg)
}
@ -81,3 +81,40 @@ pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -
}
})
}
/// Returns whether the branch is statically known to be taken or `None` if it isn't statically known.
pub(crate) fn maybe_known_branch_taken(
bcx: &FunctionBuilder<'_>,
arg: Value,
test_zero: bool,
) -> Option<bool> {
let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
arg_inst
} else {
return None;
};
match bcx.func.dfg[arg_inst] {
InstructionData::UnaryBool {
opcode: Opcode::Bconst,
imm,
} => {
if test_zero {
Some(!imm)
} else {
Some(imm)
}
}
InstructionData::UnaryImm {
opcode: Opcode::Iconst,
imm,
} => {
if test_zero {
Some(imm.bits() == 0)
} else {
Some(imm.bits() != 0)
}
}
_ => None,
}
}

View File

@ -53,6 +53,7 @@
//! ```
use std::fmt;
use std::io::Write;
use cranelift_codegen::{
entity::SecondaryMap,
@ -200,32 +201,24 @@ impl<M: Module> FunctionCx<'_, '_, M> {
}
}
pub(crate) fn write_clif_file<'tcx>(
tcx: TyCtxt<'tcx>,
postfix: &str,
isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
instance: Instance<'tcx>,
context: &cranelift_codegen::Context,
mut clif_comments: &CommentWriter,
) {
use std::io::Write;
if !cfg!(debug_assertions)
&& !tcx
pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
cfg!(debug_assertions)
|| tcx
.sess
.opts
.output_types
.contains_key(&OutputType::LlvmAssembly)
{
}
pub(crate) fn write_ir_file<'tcx>(
tcx: TyCtxt<'tcx>,
name: &str,
write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
) {
if !should_write_ir(tcx) {
return;
}
let value_ranges = isa.map(|isa| {
context
.build_value_labels_ranges(isa)
.expect("value location ranges")
});
let clif_output_dir = tcx.output_filenames(LOCAL_CRATE).with_extension("clif");
match std::fs::create_dir(&clif_output_dir) {
@ -234,41 +227,58 @@ pub(crate) fn write_clif_file<'tcx>(
res @ Err(_) => res.unwrap(),
}
let clif_file_name = clif_output_dir.join(format!(
"{}.{}.clif",
tcx.symbol_name(instance).name,
postfix
));
let mut clif = String::new();
cranelift_codegen::write::decorate_function(
&mut clif_comments,
&mut clif,
&context.func,
&DisplayFunctionAnnotations {
isa: Some(&*crate::build_isa(
tcx.sess, true, /* PIC doesn't matter here */
)),
value_ranges: value_ranges.as_ref(),
},
)
.unwrap();
let clif_file_name = clif_output_dir.join(name);
let res: std::io::Result<()> = try {
let mut file = std::fs::File::create(clif_file_name)?;
let target_triple = crate::target_triple(tcx.sess);
writeln!(file, "test compile")?;
writeln!(file, "set is_pic")?;
writeln!(file, "set enable_simd")?;
writeln!(file, "target {} haswell", target_triple)?;
writeln!(file)?;
file.write_all(clif.as_bytes())?;
write(&mut file)?;
};
if let Err(err) = res {
tcx.sess.warn(&format!("err writing clif file: {}", err));
tcx.sess.warn(&format!("error writing ir file: {}", err));
}
}
pub(crate) fn write_clif_file<'tcx>(
tcx: TyCtxt<'tcx>,
postfix: &str,
isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
instance: Instance<'tcx>,
context: &cranelift_codegen::Context,
mut clif_comments: &CommentWriter,
) {
write_ir_file(
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: Some(&*crate::build_isa(tcx.sess)),
value_ranges: value_ranges.as_ref(),
},
)
.unwrap();
writeln!(file, "test compile")?;
writeln!(file, "set is_pic")?;
writeln!(file, "set enable_simd")?;
writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
writeln!(file)?;
file.write_all(clif.as_bytes())?;
Ok(())
},
);
}
impl<M: Module> fmt::Debug for FunctionCx<'_, '_, M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{:?}", self.instance.substs)?;

View File

@ -158,7 +158,8 @@ fn build_vtable<'tcx>(
)
.unwrap();
fx.cx.module.define_data(data_id, &data_ctx).unwrap();
// FIXME don't duplicate definitions in lazy jit mode
let _ = fx.cx.module.define_data(data_id, &data_ctx);
data_id
}

View File

@ -298,21 +298,19 @@ impl CodegenBackend for LlvmCodegenBackend {
codegen_results: CodegenResults,
outputs: &OutputFilenames,
) -> Result<(), ErrorReported> {
use crate::back::archive::LlvmArchiveBuilder;
use rustc_codegen_ssa::back::link::link_binary;
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
sess.time("link_crate", || {
use crate::back::archive::LlvmArchiveBuilder;
use rustc_codegen_ssa::back::link::link_binary;
let target_cpu = crate::llvm_util::target_cpu(sess);
link_binary::<LlvmArchiveBuilder<'_>>(
sess,
&codegen_results,
outputs,
&codegen_results.crate_name.as_str(),
target_cpu,
);
});
let target_cpu = crate::llvm_util::target_cpu(sess);
link_binary::<LlvmArchiveBuilder<'_>>(
sess,
&codegen_results,
outputs,
&codegen_results.crate_name.as_str(),
target_cpu,
);
Ok(())
}

View File

@ -46,7 +46,6 @@ use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, EntryFnType};
use rustc_session::utils::NativeLibKind;
use rustc_session::Session;
use rustc_symbol_mangling::test as symbol_names_test;
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
use std::cmp;
@ -486,8 +485,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
ongoing_codegen.codegen_finished(tcx);
finalize_tcx(tcx);
ongoing_codegen.check_for_errors(tcx.sess);
return ongoing_codegen;
@ -688,14 +685,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
total_codegen_time.into_inner(),
);
rustc_incremental::assert_module_sources::assert_module_sources(tcx);
symbol_names_test::report_symbol_names(tcx);
ongoing_codegen.check_for_errors(tcx.sess);
finalize_tcx(tcx);
ongoing_codegen.into_inner()
}
@ -746,18 +737,6 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
}
}
fn finalize_tcx(tcx: TyCtxt<'_>) {
tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
// We assume that no queries are run past here. If there are new queries
// after this point, they'll show up as "<unknown>" in self-profiling data.
{
let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
tcx.alloc_self_profile_query_strings();
}
}
impl CrateInfo {
pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
let mut info = CrateInfo {

View File

@ -112,12 +112,12 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
};
// Allow uses of projections that are ZSTs or from scalar fields.
let is_consume = match context {
let is_consume = matches!(
context,
PlaceContext::NonMutatingUse(
NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
) => true,
_ => false,
};
)
);
if is_consume {
let base_ty =
mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx());

View File

@ -132,10 +132,7 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
[segment]
if segment
.res
.map(|res| match res {
Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
_ => false,
})
.map(|res| matches!(res, Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)))
.unwrap_or(false) =>
{
self.types.push(path.span);

View File

@ -93,10 +93,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
/// True for free regions other than `'static`.
pub fn is_free(&self, r: Region<'_>) -> bool {
match *r {
ty::ReEarlyBound(_) | ty::ReFree(_) => true,
_ => false,
}
matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_))
}
/// True if `r` is a free region or static of the sort that this

View File

@ -393,10 +393,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
match *b_data {
VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
_ => true,
}
!matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue)
});
}
}
@ -972,11 +969,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
VerifyBound::IsEmpty => {
if let ty::ReEmpty(_) = min {
true
} else {
false
}
matches!(min, ty::ReEmpty(_))
}
VerifyBound::AnyBound(bs) => {

View File

@ -1013,6 +1013,23 @@ pub fn start_codegen<'tcx>(
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
});
// Don't run these test assertions when not doing codegen. Compiletest tries to build
// build-fail tests in check mode first and expects it to not give an error in that case.
if tcx.sess.opts.output_types.should_codegen() {
rustc_incremental::assert_module_sources::assert_module_sources(tcx);
rustc_symbol_mangling::test::report_symbol_names(tcx);
}
tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
// We assume that no queries are run past here. If there are new queries
// after this point, they'll show up as "<unknown>" in self-profiling data.
{
let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
tcx.alloc_self_profile_query_strings();
}
info!("Post-codegen\n{:?}", tcx.debug_stats());
if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {

View File

@ -403,6 +403,7 @@ impl Linker {
return Ok(());
}
let _timer = sess.prof.verbose_generic_activity("link_crate");
self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs)
}
}

View File

@ -42,37 +42,25 @@ trait MaybeFnLike {
impl MaybeFnLike for hir::Item<'_> {
fn is_fn_like(&self) -> bool {
match self.kind {
hir::ItemKind::Fn(..) => true,
_ => false,
}
matches!(self.kind, hir::ItemKind::Fn(..))
}
}
impl MaybeFnLike for hir::ImplItem<'_> {
fn is_fn_like(&self) -> bool {
match self.kind {
hir::ImplItemKind::Fn(..) => true,
_ => false,
}
matches!(self.kind, hir::ImplItemKind::Fn(..))
}
}
impl MaybeFnLike for hir::TraitItem<'_> {
fn is_fn_like(&self) -> bool {
match self.kind {
hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true,
_ => false,
}
matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)))
}
}
impl MaybeFnLike for hir::Expr<'_> {
fn is_fn_like(&self) -> bool {
match self.kind {
hir::ExprKind::Closure(..) => true,
_ => false,
}
matches!(self.kind, hir::ExprKind::Closure(..))
}
}

View File

@ -118,17 +118,11 @@ impl CoverageKind {
}
pub fn is_counter(&self) -> bool {
match self {
Self::Counter { .. } => true,
_ => false,
}
matches!(self, Self::Counter { .. })
}
pub fn is_expression(&self) -> bool {
match self {
Self::Expression { .. } => true,
_ => false,
}
matches!(self, Self::Expression { .. })
}
pub fn is_unreachable(&self) -> bool {

View File

@ -576,11 +576,13 @@ rustc_queries! {
desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
}
query impl_trait_ref(key: DefId) -> Option<ty::TraitRef<'tcx>> {
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) }
/// Given an `impl_id`, return the trait it implements.
/// Return `None` if this is an inherent impl.
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
}
query impl_polarity(key: DefId) -> ty::ImplPolarity {
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) }
query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
}
query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
@ -917,8 +919,10 @@ rustc_queries! {
}
TypeChecking {
query trait_of_item(def_id: DefId) -> Option<DefId> {
desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) }
/// Given an `associated_item`, find the trait it belongs to.
/// Return `None` if the `DefId` is not an associated item.
query trait_of_item(associated_item: DefId) -> Option<DefId> {
desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
}
}
@ -948,20 +952,29 @@ rustc_queries! {
}
TypeChecking {
query all_local_trait_impls(key: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
/// Return all `impl` blocks in the current crate.
///
/// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number.
/// Passing in any other crate will cause an ICE.
///
/// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
desc { "local trait impls" }
}
query trait_impls_of(key: DefId) -> ty::trait_def::TraitImpls {
/// Given a trait `trait_id`, return all known `impl` blocks.
query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
storage(ArenaCacheSelector<'tcx>)
desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) }
desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
}
query specialization_graph_of(key: DefId) -> specialization_graph::Graph {
query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
storage(ArenaCacheSelector<'tcx>)
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) }
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
cache_on_disk_if { true }
}
query object_safety_violations(key: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
}
/// Gets the ParameterEnvironment for a given item; this environment
@ -969,6 +982,7 @@ rustc_queries! {
/// type-checking etc, and it does not normalize specializable
/// associated types. This is almost always what you want,
/// unless you are doing MIR optimizations, in which case you
/// might want to use `reveal_all()` method to change modes.
query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
}
@ -1229,10 +1243,15 @@ rustc_queries! {
}
TypeChecking {
/// Given a crate and a trait, look up all impls of that trait in the crate.
/// Return `(impl_id, self_ty)`.
query implementations_of_trait(_: (CrateNum, DefId))
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up implementations of a trait in a crate" }
}
/// Given a crate, look up all trait impls in that crate.
/// Return `(impl_id, self_ty)`.
query all_trait_implementations(_: CrateNum)
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up all (?) trait implementations" }

View File

@ -647,14 +647,11 @@ impl<T> Trait<T> for X {
let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
// We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
let callable_scope = match body_owner {
Some(
let callable_scope = matches!(body_owner, Some(
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
| hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
) => true,
_ => false,
};
));
let impl_comparison = matches!(
cause_code,
ObligationCauseCode::CompareImplMethodObligation { .. }

View File

@ -40,11 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
let expr_is_block_or_scope = match expr.kind {
ExprKind::Block { .. } => true,
ExprKind::Scope { .. } => true,
_ => false,
};
let expr_is_block_or_scope = matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
let schedule_drop = move |this: &mut Self| {
if let Some(drop_scope) = scope {

View File

@ -501,10 +501,9 @@ impl<'a> Parser<'a> {
pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
match &expr.kind {
ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
ast::ExprKind::Lit(_) => true,
_ => false,
},
ast::ExprKind::Unary(ast::UnOp::Neg, expr) => {
matches!(expr.kind, ast::ExprKind::Lit(_))
}
// We can only resolve single-segment paths at the moment, because multi-segment paths
// require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
ast::ExprKind::Path(None, path)

View File

@ -23,18 +23,18 @@ use rustc_span::symbol::{sym, Symbol};
// function, then we should explore its block to check for codes that
// may need to be marked as live.
fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
match tcx.hir().find(hir_id) {
matches!(
tcx.hir().find(hir_id),
Some(
Node::Item(..)
| Node::ImplItem(..)
| Node::ForeignItem(..)
| Node::TraitItem(..)
| Node::Variant(..)
| Node::AnonConst(..)
| Node::Pat(..),
) => true,
_ => false,
}
| Node::ImplItem(..)
| Node::ForeignItem(..)
| Node::TraitItem(..)
| Node::Variant(..)
| Node::AnonConst(..)
| Node::Pat(..),
)
)
}
struct MarkSymbolVisitor<'tcx> {
@ -500,16 +500,16 @@ struct DeadVisitor<'tcx> {
impl DeadVisitor<'tcx> {
fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool {
let should_warn = match item.kind {
let should_warn = matches!(
item.kind,
hir::ItemKind::Static(..)
| hir::ItemKind::Const(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..) => true,
_ => false,
};
| hir::ItemKind::Const(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..)
);
should_warn && !self.symbol_is_live(item.hir_id)
}

View File

@ -367,10 +367,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
let is_shorthand = match param.pat.kind {
rustc_hir::PatKind::Struct(..) => true,
_ => false,
};
let is_shorthand = matches!(param.pat.kind, rustc_hir::PatKind::Struct(..));
param.pat.each_binding(|_bm, hir_id, _x, ident| {
let var = if is_shorthand {
Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true })

View File

@ -842,11 +842,9 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
let macro_module_def_id =
ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id())
.unwrap();
// FIXME(#71104) Should really be using just `as_local_hir_id` but
// some `DefId` do not seem to have a corresponding HirId.
let hir_id = macro_module_def_id
.as_local()
.and_then(|def_id| self.tcx.hir().opt_local_def_id_to_hir_id(def_id));
.map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
let mut module_id = match hir_id {
Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id,
// `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).

View File

@ -1653,17 +1653,14 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
for missing in &self.missing_named_lifetime_spots {
match missing {
MissingLifetimeSpot::Generics(generics) => {
let (span, sugg) = if let Some(param) =
generics.params.iter().find(|p| match p.kind {
hir::GenericParamKind::Type {
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
..
} => false,
hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Elided,
} => false,
_ => true,
}) {
let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
!matches!(p.kind, hir::GenericParamKind::Type {
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
..
} | hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Elided,
})
}) {
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
} else {
suggests_in_band = true;

View File

@ -2416,7 +2416,10 @@ impl<'a> Resolver<'a> {
} else if i == 0 {
if ident
.name
.with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase()))
.as_str()
.chars()
.next()
.map_or(false, |c| c.is_ascii_uppercase())
{
(format!("use of undeclared type `{}`", ident), None)
} else {

View File

@ -1451,12 +1451,6 @@ impl Symbol {
with_interner(|interner| interner.intern(string))
}
/// Access the symbol's chars. This is a slowish operation because it
/// requires locking the symbol interner.
pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
with_interner(|interner| f(interner.get(self)))
}
/// Convert to a `SymbolStr`. This is a slowish operation because it
/// requires locking the symbol interner.
pub fn as_str(self) -> SymbolStr {
@ -1484,19 +1478,19 @@ impl Symbol {
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.with(|str| fmt::Debug::fmt(&str, f))
fmt::Debug::fmt(&self.as_str(), f)
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.with(|str| fmt::Display::fmt(&str, f))
fmt::Display::fmt(&self.as_str(), f)
}
}
impl<S: Encoder> Encodable<S> for Symbol {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
self.with(|string| s.emit_str(string))
s.emit_str(&self.as_str())
}
}

View File

@ -35,10 +35,7 @@ pub enum AutoTraitResult<A> {
#[allow(dead_code)]
impl<A> AutoTraitResult<A> {
fn is_auto(&self) -> bool {
match *self {
AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
_ => false,
}
matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
}
}
@ -601,10 +598,7 @@ impl AutoTraitFinder<'tcx> {
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
match *p.ty().skip_binder().kind() {
ty::Projection(proj) if proj == p.skip_binder().projection_ty => true,
_ => false,
}
matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
}
fn evaluate_nested_obligations(

View File

@ -193,10 +193,8 @@ fn overlap_within_probe(
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) {
Some(true) => true,
_ => false,
};
let involves_placeholder =
matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
}

View File

@ -861,10 +861,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
let arg_length = arguments.len();
let distinct = match &other[..] {
&[ArgKind::Tuple(..)] => true,
_ => false,
};
let distinct = matches!(other, &[ArgKind::Tuple(..)]);
match (arg_length, arguments.get(0)) {
(1, Some(&ArgKind::Tuple(_, ref fields))) => {
format!("a single {}-tuple as argument", fields.len())
@ -1201,12 +1198,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
normalized_ty, data.ty
);
let is_normalized_ty_expected = match &obligation.cause.code {
ObligationCauseCode::ItemObligation(_)
let is_normalized_ty_expected = !matches!(obligation.cause.code, ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ObjectCastObligation(_) => false,
_ => true,
};
| ObligationCauseCode::ObjectCastObligation(_));
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected,

View File

@ -323,9 +323,8 @@ pub fn normalize_param_env_or_error<'tcx>(
// This works fairly well because trait matching does not actually care about param-env
// TypeOutlives predicates - these are normally used by regionck.
let outlives_predicates: Vec<_> = predicates
.drain_filter(|predicate| match predicate.skip_binders() {
ty::PredicateAtom::TypeOutlives(..) => true,
_ => false,
.drain_filter(|predicate| {
matches!(predicate.skip_binders(), ty::PredicateAtom::TypeOutlives(..))
})
.collect();

View File

@ -526,18 +526,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
generics: &ty::Generics,
) -> bool {
let explicit = !seg.infer_args;
let impl_trait =
generics.params.iter().any(|param| match param.kind {
ty::GenericParamDefKind::Type {
synthetic:
Some(
hir::SyntheticTyParamKind::ImplTrait
| hir::SyntheticTyParamKind::FromAttr,
),
..
} => true,
_ => false,
});
let impl_trait = generics.params.iter().any(|param| {
matches!(param.kind, ty::GenericParamDefKind::Type {
synthetic:
Some(
hir::SyntheticTyParamKind::ImplTrait
| hir::SyntheticTyParamKind::FromAttr,
),
..
})
});
if explicit && impl_trait {
let spans = seg

View File

@ -543,10 +543,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
if let Some(ty) = prohibit_opaque.break_value() {
let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
hir::OpaqueTyOrigin::AsyncFn => true,
_ => false,
},
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
}
_ => unreachable!(),
};
@ -1321,10 +1320,7 @@ pub fn check_enum<'tcx>(
}
if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
let is_unit = |var: &hir::Variant<'_>| match var.data {
hir::VariantData::Unit(..) => true,
_ => false,
};
let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
let has_non_units = vs.iter().any(|var| !is_unit(var));

View File

@ -325,10 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
}
let is_closure = match arg.kind {
ExprKind::Closure(..) => true,
_ => false,
};
let is_closure = matches!(arg.kind, ExprKind::Closure(..));
if is_closure != check_closures {
continue;

View File

@ -354,10 +354,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
hir_id: hir::HirId,
) {
assert!(
match fk {
intravisit::FnKind::Closure(..) => true,
_ => false,
},
matches!(fk, intravisit::FnKind::Closure(..)),
"visit_fn invoked for something other than a closure"
);

View File

@ -156,10 +156,10 @@ crate fn placeholder_type_error(
if let Some(span) = span {
sugg.push((span, format!("<{}>", type_name)));
}
} else if let Some(arg) = generics.iter().find(|arg| match arg.name {
hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
_ => false,
}) {
} else if let Some(arg) = generics
.iter()
.find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. })))
{
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
sugg.push((arg.span, (*type_name).to_string()));
@ -1544,12 +1544,27 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
let mut diag = bad_placeholder_type(tcx, visitor.0);
let ret_ty = fn_sig.output();
if ret_ty != tcx.ty_error() {
diag.span_suggestion(
ty.span,
"replace with the correct return type",
ret_ty.to_string(),
Applicability::MaybeIncorrect,
);
if !ret_ty.is_closure() {
let ret_ty_str = match ret_ty.kind() {
// Suggest a function pointer return type instead of a unique function definition
// (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
// syntax)
ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
_ => ret_ty.to_string(),
};
diag.span_suggestion(
ty.span,
"replace with the correct return type",
ret_ty_str,
Applicability::MaybeIncorrect,
);
} else {
// We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
// to prevent the user from getting a papercut while trying to use the unique closure
// syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
}
}
diag.emit();
ty::Binder::bind(fn_sig)

View File

@ -595,10 +595,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
let upvars = self.tcx().upvars_mentioned(self.body_owner);
// For purposes of this function, generator and closures are equivalent.
let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() {
ty::Closure(..) | ty::Generator(..) => true,
_ => false,
};
let body_owner_is_closure = matches!(
self.tcx().type_of(self.body_owner.to_def_id()).kind(),
ty::Closure(..) | ty::Generator(..)
);
if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
{

View File

@ -81,15 +81,18 @@ impl<K, V> Root<K, V> {
// the appended elements even if advancing the iterator panicks.
*length += 1;
}
self.fix_right_edge();
self.fix_right_border_of_plentiful();
}
fn fix_right_edge(&mut self) {
// Handle underfull nodes, start from the top.
/// Stock up any underfull nodes on the right border of the tree.
/// The other nodes, those that are not the root nor a rightmost edge,
/// must have MIN_LEN elements to spare.
fn fix_right_border_of_plentiful(&mut self) {
let mut cur_node = self.borrow_mut();
while let Internal(internal) = cur_node.force() {
// Check if right-most child is underfull.
let mut last_kv = internal.last_kv().consider_for_balancing();
debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2);
let right_child_len = last_kv.right_child_len();
if right_child_len < MIN_LEN {
// We need to steal.

View File

@ -1821,7 +1821,6 @@ fn test_append_ord_chaos() {
}
fn rand_data(len: usize) -> Vec<(u32, u32)> {
assert!(len * 2 <= 70029); // from that point on numbers repeat
let mut rng = DeterministicRng::new();
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))
}
@ -1886,6 +1885,25 @@ fn test_split_off_tiny_right_height_2() {
assert_eq!(*right.last_key_value().unwrap().0, last);
}
#[test]
fn test_split_off_halfway() {
let mut rng = DeterministicRng::new();
for &len in &[NODE_CAPACITY, 25, 50, 75, 100] {
let mut data = Vec::from_iter((0..len).map(|_| (rng.next(), ())));
// Insertion in non-ascending order creates some variation in node length.
let mut map = BTreeMap::from_iter(data.iter().copied());
data.sort();
let small_keys = data.iter().take(len / 2).map(|kv| kv.0);
let large_keys = data.iter().skip(len / 2).map(|kv| kv.0);
let split_key = large_keys.clone().next().unwrap();
let right = map.split_off(&split_key);
map.check();
right.check();
assert!(map.keys().copied().eq(small_keys));
assert!(right.keys().copied().eq(large_keys));
}
}
#[test]
fn test_split_off_large_random_sorted() {
// Miri is too slow

View File

@ -38,6 +38,7 @@ pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
#[cfg(test)]
/// XorShiftRng
struct DeterministicRng {
count: usize,
x: u32,
y: u32,
z: u32,
@ -47,11 +48,13 @@ struct DeterministicRng {
#[cfg(test)]
impl DeterministicRng {
fn new() -> Self {
DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
}
/// Guarantees that the first 70029 results are unique.
/// Guarantees that each returned number is unique.
fn next(&mut self) -> u32 {
self.count += 1;
assert!(self.count <= 70029);
let x = self.x;
let t = x ^ (x << 11);
self.x = self.y;

View File

@ -696,8 +696,10 @@ fn test_first_last() {
assert_eq!(a.pop_last(), None);
}
// Unlike the function with the same name in map/tests, returns no values.
// Which also means it returns different predetermined pseudo-random keys,
// and the test cases using this function explore slightly different trees.
fn rand_data(len: usize) -> Vec<u32> {
assert!(len <= 70029); // from that point on numbers repeat
let mut rng = DeterministicRng::new();
Vec::from_iter((0..len).map(|_| rng.next()))
}

View File

@ -53,6 +53,9 @@ impl<K, V> Root<K, V> {
}
}
/// Stock up or merge away any underfull nodes on the right border of the
/// tree. The other nodes, those that are not the root nor a rightmost edge,
/// must already have at least MIN_LEN elements.
fn fix_right_border(&mut self) {
self.fix_top();
@ -72,6 +75,7 @@ impl<K, V> Root<K, V> {
}
cur_node = last_kv.into_right_child();
}
debug_assert!(cur_node.len() > MIN_LEN);
}
}
@ -98,6 +102,7 @@ impl<K, V> Root<K, V> {
}
cur_node = first_kv.into_left_child();
}
debug_assert!(cur_node.len() > MIN_LEN);
}
}

View File

@ -500,18 +500,17 @@ impl Step for Rustc {
let target = self.target;
builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
// This is the intended out directory for compiler documentation.
let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, builder.config.build);
if !builder.config.compiler_docs {
builder.info("\tskipping - compiler/librustdoc docs disabled");
return;
}
// This is the intended out directory for compiler documentation.
let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
// Build rustc.
let compiler = builder.compiler(stage, builder.config.build);
builder.ensure(compile::Rustc { compiler, target });
// This uses a shared directory so that librustdoc documentation gets
@ -521,6 +520,10 @@ impl Step for Rustc {
// merging the search index, or generating local (relative) links.
let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
t!(symlink_dir_force(&builder.config, &out, &out_dir));
// Cargo puts proc macros in `target/doc` even if you pass `--target`
// explicitly (https://github.com/rust-lang/cargo/issues/7677).
let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc");
t!(symlink_dir_force(&builder.config, &out, &proc_macro_out_dir));
// Build cargo command.
let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");

View File

@ -112,7 +112,7 @@ impl<'a> Tarball<'a> {
fn new_inner(builder: &'a Builder<'a>, component: &str, target: Option<String>) -> Self {
let pkgname = crate::dist::pkgname(builder, component);
let mut temp_dir = builder.out.join("tmp").join("tarball");
let mut temp_dir = builder.out.join("tmp").join("tarball").join(component);
if let Some(target) = &target {
temp_dir = temp_dir.join(target);
}

View File

@ -0,0 +1,27 @@
// Functions with a type placeholder `_` as the return type should
// show a function pointer suggestion when given a function item
// and suggest how to return closures correctly from a function.
// This is a regression test of #80179
fn returns_i32() -> i32 {
0
}
fn returns_fn_ptr() -> _ {
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
//~| NOTE not allowed in type signatures
//~| HELP replace with the correct return type
//~| SUGGESTION fn() -> i32
returns_i32
}
fn returns_closure() -> _ {
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
//~| NOTE not allowed in type signatures
//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
//~| NOTE for more information on `Fn` traits and closure types, see
// https://doc.rust-lang.org/book/ch13-01-closures.html
|| 0
}
fn main() {}

View File

@ -0,0 +1,21 @@
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/issue-80179.rs:10:24
|
LL | fn returns_fn_ptr() -> _ {
| ^
| |
| not allowed in type signatures
| help: replace with the correct return type: `fn() -> i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/issue-80179.rs:18:25
|
LL | fn returns_closure() -> _ {
| ^ not allowed in type signatures
|
= help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0121`.