mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
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:
commit
2987785df3
134
RELEASES.md
134
RELEASES.md
@ -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/
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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(..)
|
||||
)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
}
|
||||
_ => {
|
||||
|
@ -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();
|
||||
|
@ -580,10 +580,7 @@ pub mod printf {
|
||||
}
|
||||
|
||||
fn is_flag(c: &char) -> bool {
|
||||
match c {
|
||||
'0' | '-' | '+' | ' ' | '#' | '\'' => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'')
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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]
|
||||
|
@ -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() {
|
||||
|
@ -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",
|
||||
]
|
||||
|
@ -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" }
|
||||
|
@ -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!");
|
||||
});
|
||||
|
@ -1 +1 @@
|
||||
nightly-2020-11-27
|
||||
nightly-2020-12-23
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
)
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
});
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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(..) {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) => {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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(..))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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" }
|
||||
|
@ -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 { .. }
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 })
|
||||
|
@ -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).
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
27
src/test/ui/fn/issue-80179.rs
Normal file
27
src/test/ui/fn/issue-80179.rs
Normal 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() {}
|
21
src/test/ui/fn/issue-80179.stderr
Normal file
21
src/test/ui/fn/issue-80179.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user