Merge from rustc
This commit is contained in:
commit
d11a2bdc1d
1255 changed files with 19259 additions and 11266 deletions
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
|
|
@ -361,8 +361,8 @@ jobs:
|
|||
os: macos-13
|
||||
- name: dist-aarch64-apple
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
|
||||
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
SELECT_XCODE: /Applications/Xcode_13.4.1.app
|
||||
USE_XCODE_CLANG: 1
|
||||
|
|
@ -372,20 +372,8 @@ jobs:
|
|||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_OVERFLOW_CHECKS: 1
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: macos-13-xlarge
|
||||
- name: aarch64-apple
|
||||
env:
|
||||
SCRIPT: "./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
|
||||
RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
SELECT_XCODE: /Applications/Xcode_13.4.1.app
|
||||
USE_XCODE_CLANG: 1
|
||||
MACOSX_DEPLOYMENT_TARGET: 11.0
|
||||
MACOSX_STD_DEPLOYMENT_TARGET: 11.0
|
||||
NO_LLVM_ASSERTIONS: 1
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_OVERFLOW_CHECKS: 1
|
||||
os: macos-13-xlarge
|
||||
JEMALLOC_SYS_WITH_LG_PAGE: 14
|
||||
os: macos-13
|
||||
- name: x86_64-msvc
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
|
||||
|
|
|
|||
47
Cargo.lock
47
Cargo.lock
|
|
@ -285,9 +285,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
|
|
@ -537,7 +537,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"clippy_config",
|
||||
|
|
@ -565,7 +565,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"rustc-semver",
|
||||
"serde",
|
||||
|
|
@ -588,7 +588,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.15.4",
|
||||
|
|
@ -613,7 +613,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"clippy_config",
|
||||
|
|
@ -984,7 +984,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"quote",
|
||||
|
|
@ -3370,7 +3370,7 @@ dependencies = [
|
|||
name = "rustc_abi"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"rand",
|
||||
"rand_xoshiro",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -3401,7 +3401,7 @@ dependencies = [
|
|||
name = "rustc_ast"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"memchr",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
|
|
@ -3552,7 +3552,7 @@ dependencies = [
|
|||
name = "rustc_codegen_llvm"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"itertools",
|
||||
"libc",
|
||||
"measureme",
|
||||
|
|
@ -3587,7 +3587,7 @@ name = "rustc_codegen_ssa"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ar_archive_writer",
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"cc",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
|
|
@ -3654,7 +3654,7 @@ name = "rustc_data_structures"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"elsa",
|
||||
"ena",
|
||||
"indexmap",
|
||||
|
|
@ -4121,7 +4121,7 @@ dependencies = [
|
|||
name = "rustc_metadata"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"libloading 0.7.4",
|
||||
"odht",
|
||||
"rustc_ast",
|
||||
|
|
@ -4151,7 +4151,7 @@ dependencies = [
|
|||
name = "rustc_middle"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"derive_more",
|
||||
"either",
|
||||
"field-offset",
|
||||
|
|
@ -4286,7 +4286,7 @@ dependencies = [
|
|||
name = "rustc_parse"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4424,7 +4424,7 @@ dependencies = [
|
|||
name = "rustc_resolve"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"pulldown-cmark",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
|
|
@ -4463,7 +4463,7 @@ dependencies = [
|
|||
name = "rustc_session"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"getopts",
|
||||
"libc",
|
||||
"rustc_ast",
|
||||
|
|
@ -4521,7 +4521,7 @@ dependencies = [
|
|||
name = "rustc_symbol_mangling"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"punycode",
|
||||
"rustc-demangle",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4539,7 +4539,7 @@ dependencies = [
|
|||
name = "rustc_target"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"object",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4563,6 +4563,7 @@ checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
|
|||
name = "rustc_trait_selection"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4637,7 +4638,7 @@ dependencies = [
|
|||
name = "rustc_type_ir"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"derivative",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
|
|
@ -4767,7 +4768,7 @@ version = "0.38.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
|
|
@ -5205,9 +5206,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.29.2"
|
||||
version = "0.29.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9557d0845b86eea8182f7b10dff120214fb6cd9fd937b6f4917714e546a38695"
|
||||
checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "1.2.1"
|
||||
bitflags = "2.4.1"
|
||||
rand = { version = "0.8.4", default-features = false, optional = true }
|
||||
rand_xoshiro = { version = "0.6.0", optional = true }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
|
|
|
|||
|
|
@ -29,10 +29,12 @@ pub use layout::LayoutCalculator;
|
|||
/// instead of implementing everything in `rustc_middle`.
|
||||
pub trait HashStableContext {}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
pub struct ReprFlags(u8);
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
pub struct ReprFlags: u8 {
|
||||
impl ReprFlags: u8 {
|
||||
const IS_C = 1 << 0;
|
||||
const IS_SIMD = 1 << 1;
|
||||
const IS_TRANSPARENT = 1 << 2;
|
||||
|
|
@ -42,11 +44,12 @@ bitflags! {
|
|||
// the seed stored in `ReprOptions.layout_seed`
|
||||
const RANDOMIZE_LAYOUT = 1 << 4;
|
||||
// Any of these flags being set prevent field reordering optimisation.
|
||||
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits
|
||||
| ReprFlags::IS_SIMD.bits
|
||||
| ReprFlags::IS_LINEAR.bits;
|
||||
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits()
|
||||
| ReprFlags::IS_SIMD.bits()
|
||||
| ReprFlags::IS_LINEAR.bits();
|
||||
}
|
||||
}
|
||||
rustc_data_structures::external_bitflags_debug! { ReprFlags }
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "1.2.1"
|
||||
bitflags = "2.4.1"
|
||||
memchr = "2.5.0"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
|
|
|
|||
|
|
@ -2171,9 +2171,10 @@ pub enum InlineAsmRegOrRegClass {
|
|||
RegClass(Symbol),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct InlineAsmOptions(u16);
|
||||
bitflags::bitflags! {
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct InlineAsmOptions: u16 {
|
||||
impl InlineAsmOptions: u16 {
|
||||
const PURE = 1 << 0;
|
||||
const NOMEM = 1 << 1;
|
||||
const READONLY = 1 << 2;
|
||||
|
|
@ -2186,6 +2187,12 @@ bitflags::bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for InlineAsmOptions {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
bitflags::parser::to_writer(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
|
||||
pub enum InlineAsmTemplatePiece {
|
||||
String(String),
|
||||
|
|
@ -2481,15 +2488,6 @@ pub enum Const {
|
|||
No,
|
||||
}
|
||||
|
||||
impl From<BoundConstness> for Const {
|
||||
fn from(constness: BoundConstness) -> Self {
|
||||
match constness {
|
||||
BoundConstness::Maybe(span) => Self::Yes(span),
|
||||
BoundConstness::Never => Self::No,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Item defaultness.
|
||||
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
|
|
@ -2543,6 +2541,8 @@ impl BoundPolarity {
|
|||
pub enum BoundConstness {
|
||||
/// `Type: Trait`
|
||||
Never,
|
||||
/// `Type: const Trait`
|
||||
Always(Span),
|
||||
/// `Type: ~const Trait`
|
||||
Maybe(Span),
|
||||
}
|
||||
|
|
@ -2551,6 +2551,7 @@ impl BoundConstness {
|
|||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Never => "",
|
||||
Self::Always(_) => "const",
|
||||
Self::Maybe(_) => "~const",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -528,15 +528,6 @@ impl Token {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the token can appear at the start of a generic bound.
|
||||
pub fn can_begin_bound(&self) -> bool {
|
||||
self.is_path_start()
|
||||
|| self.is_lifetime()
|
||||
|| self.is_keyword(kw::For)
|
||||
|| self == &Question
|
||||
|| self == &OpenDelim(Delimiter::Parenthesis)
|
||||
}
|
||||
|
||||
/// Returns `true` if the token can appear at the start of an item.
|
||||
pub fn can_begin_item(&self) -> bool {
|
||||
match self.kind {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
|||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::{cmp, fmt, iter, mem};
|
||||
use std::{cmp, fmt, iter};
|
||||
|
||||
/// When the main Rust parser encounters a syntax-extension invocation, it
|
||||
/// parses the arguments to the invocation as a token tree. This is a very
|
||||
|
|
@ -81,14 +81,6 @@ impl TokenTree {
|
|||
}
|
||||
}
|
||||
|
||||
/// Modify the `TokenTree`'s span in-place.
|
||||
pub fn set_span(&mut self, span: Span) {
|
||||
match self {
|
||||
TokenTree::Token(token, _) => token.span = span,
|
||||
TokenTree::Delimited(dspan, ..) => *dspan = DelimSpan::from_single(span),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `TokenTree::Token` with alone spacing.
|
||||
pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree {
|
||||
TokenTree::Token(Token::new(kind, span), Spacing::Alone)
|
||||
|
|
@ -461,19 +453,6 @@ impl TokenStream {
|
|||
t1.next().is_none() && t2.next().is_none()
|
||||
}
|
||||
|
||||
/// Applies the supplied function to each `TokenTree` and its index in `self`, returning a new `TokenStream`
|
||||
///
|
||||
/// It is equivalent to `TokenStream::new(self.trees().cloned().enumerate().map(|(i, tt)| f(i, tt)).collect())`.
|
||||
pub fn map_enumerated_owned(
|
||||
mut self,
|
||||
mut f: impl FnMut(usize, TokenTree) -> TokenTree,
|
||||
) -> TokenStream {
|
||||
let owned = Lrc::make_mut(&mut self.0); // clone if necessary
|
||||
// rely on vec's in-place optimizations to avoid another allocation
|
||||
*owned = mem::take(owned).into_iter().enumerate().map(|(i, tree)| f(i, tree)).collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Create a token stream containing a single token with alone spacing. The
|
||||
/// spacing used for the final token in a constructed stream doesn't matter
|
||||
/// because it's never used. In practice we arbitrarily use
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ ast_lowering_functional_record_update_destructuring_assignment =
|
|||
functional record updates are not allowed in destructuring assignments
|
||||
.suggestion = consider removing the trailing pattern
|
||||
|
||||
ast_lowering_generic_param_default_in_binder =
|
||||
defaults for generic parameters are not allowed in `for<...>` binders
|
||||
|
||||
ast_lowering_generic_type_with_parentheses =
|
||||
parenthesized type parameters may only be used with a `Fn` trait
|
||||
.label = only `Fn` traits may use parentheses
|
||||
|
|
|
|||
|
|
@ -395,3 +395,10 @@ pub enum BadReturnTypeNotation {
|
|||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_generic_param_default_in_binder)]
|
||||
pub(crate) struct GenericParamDefaultInBinder {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,14 +183,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
||||
hir::MatchSource::Normal,
|
||||
),
|
||||
ExprKind::Gen(capture_clause, block, GenBlockKind::Async) => self.make_async_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
|
||||
ExprKind::Closure(box Closure {
|
||||
binder,
|
||||
|
|
@ -226,6 +218,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
*fn_arg_span,
|
||||
),
|
||||
},
|
||||
ExprKind::Gen(capture_clause, block, genblock_kind) => {
|
||||
let desugaring_kind = match genblock_kind {
|
||||
GenBlockKind::Async => hir::CoroutineDesugaring::Async,
|
||||
GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,
|
||||
GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,
|
||||
};
|
||||
self.make_desugared_coroutine_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
desugaring_kind,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
)
|
||||
}
|
||||
ExprKind::Block(blk, opt_label) => {
|
||||
let opt_label = self.lower_label(*opt_label);
|
||||
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
|
||||
|
|
@ -313,23 +321,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
rest,
|
||||
)
|
||||
}
|
||||
ExprKind::Gen(capture_clause, block, GenBlockKind::Gen) => self.make_gen_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Gen(capture_clause, block, GenBlockKind::AsyncGen) => self
|
||||
.make_async_gen_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err => {
|
||||
hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
|
||||
|
|
@ -555,7 +546,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
||||
let pat = self.lower_pat(&arm.pat);
|
||||
let mut guard = arm.guard.as_ref().map(|cond| {
|
||||
let guard = arm.guard.as_ref().map(|cond| {
|
||||
if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind {
|
||||
hir::Guard::IfLet(self.arena.alloc(hir::Let {
|
||||
hir_id: self.next_id(),
|
||||
|
|
@ -587,10 +578,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
} else if let Some(body) = &arm.body {
|
||||
self.dcx().emit_err(NeverPatternWithBody { span: body.span });
|
||||
guard = None;
|
||||
} else if let Some(g) = &arm.guard {
|
||||
self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
|
||||
guard = None;
|
||||
}
|
||||
|
||||
// We add a fake `loop {}` arm body so that it typecks to `!`.
|
||||
|
|
@ -612,113 +601,71 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::Arm { hir_id, pat, guard, body, span }
|
||||
}
|
||||
|
||||
/// Lower an `async` construct to a coroutine that implements `Future`.
|
||||
/// Lower/desugar a coroutine construct.
|
||||
///
|
||||
/// In particular, this creates the correct async resume argument and `_task_context`.
|
||||
///
|
||||
/// This results in:
|
||||
///
|
||||
/// ```text
|
||||
/// static move? |_task_context| -> <ret_ty> {
|
||||
/// static move? |<_task_context?>| -> <return_ty> {
|
||||
/// <body>
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn make_async_expr(
|
||||
pub(super) fn make_desugared_coroutine_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
ret_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
|
||||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
|
||||
let input_ty = hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::Path(resume_ty),
|
||||
span: unstable_span,
|
||||
};
|
||||
|
||||
// The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: arena_vec![self; input_ty],
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
|
||||
let (pat, task_context_hid) = self.pat_ident_binding_mode(
|
||||
span,
|
||||
Ident::with_dummy_span(sym::_task_context),
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let param = hir::Param {
|
||||
hir_id: self.next_id(),
|
||||
pat,
|
||||
ty_span: self.lower_span(span),
|
||||
span: self.lower_span(span),
|
||||
};
|
||||
let params = arena_vec![self; param];
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
async_coroutine_source,
|
||||
));
|
||||
|
||||
let old_ctx = this.task_context;
|
||||
this.task_context = Some(task_context_hid);
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
(params, res)
|
||||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(hir::Movability::Static),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Lower a `gen` construct to a generator that implements `Iterator`.
|
||||
///
|
||||
/// This results in:
|
||||
///
|
||||
/// ```text
|
||||
/// static move? |()| -> () {
|
||||
/// <body>
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn make_gen_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
_yield_ty: Option<hir::FnRetTy<'hir>>,
|
||||
return_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
desugaring_kind: hir::CoroutineDesugaring,
|
||||
coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
|
||||
let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
|
||||
|
||||
// The `async` desugaring takes a resume argument and maintains a `task_context`,
|
||||
// whereas a generator does not.
|
||||
let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
|
||||
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
|
||||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
|
||||
let input_ty = hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::Path(resume_ty),
|
||||
span: unstable_span,
|
||||
};
|
||||
let inputs = arena_vec![self; input_ty];
|
||||
|
||||
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
|
||||
let (pat, task_context_hid) = self.pat_ident_binding_mode(
|
||||
span,
|
||||
Ident::with_dummy_span(sym::_task_context),
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let param = hir::Param {
|
||||
hir_id: self.next_id(),
|
||||
pat,
|
||||
ty_span: self.lower_span(span),
|
||||
span: self.lower_span(span),
|
||||
};
|
||||
let params = arena_vec![self; param];
|
||||
|
||||
(inputs, params, Some(task_context_hid))
|
||||
}
|
||||
hir::CoroutineDesugaring::Gen => (&[], &[], None),
|
||||
};
|
||||
|
||||
let output =
|
||||
return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
|
||||
// The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: &[],
|
||||
inputs,
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
|
|
@ -726,100 +673,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
coroutine_source,
|
||||
));
|
||||
|
||||
let res = body(this);
|
||||
(&[], res)
|
||||
});
|
||||
|
||||
// `static |()| -> () { body }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(Movability::Movable),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Lower a `async gen` construct to a generator that implements `AsyncIterator`.
|
||||
///
|
||||
/// This results in:
|
||||
///
|
||||
/// ```text
|
||||
/// static move? |_task_context| -> () {
|
||||
/// <body>
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn make_async_gen_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
_yield_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
|
||||
|
||||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
|
||||
let input_ty = hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::Path(resume_ty),
|
||||
span: unstable_span,
|
||||
};
|
||||
|
||||
// The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: arena_vec![self; input_ty],
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
|
||||
let (pat, task_context_hid) = self.pat_ident_binding_mode(
|
||||
span,
|
||||
Ident::with_dummy_span(sym::_task_context),
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let param = hir::Param {
|
||||
hir_id: self.next_id(),
|
||||
pat,
|
||||
ty_span: self.lower_span(span),
|
||||
span: self.lower_span(span),
|
||||
};
|
||||
let params = arena_vec![self; param];
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
async_coroutine_source,
|
||||
));
|
||||
this.coroutine_kind = Some(coroutine_kind);
|
||||
|
||||
let old_ctx = this.task_context;
|
||||
this.task_context = Some(task_context_hid);
|
||||
if task_context.is_some() {
|
||||
this.task_context = task_context;
|
||||
}
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
|
||||
(params, res)
|
||||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
// `static |<_task_context?>| -> <return_ty> { <body> }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
|
|
@ -829,7 +695,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(hir::Movability::Static),
|
||||
kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
|
|
@ -898,7 +764,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let is_async_gen = match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
|
||||
Some(hir::CoroutineKind::Coroutine)
|
||||
Some(hir::CoroutineKind::Coroutine(_))
|
||||
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
|
||||
| None => {
|
||||
return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||
|
|
@ -1086,7 +952,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) -> hir::ExprKind<'hir> {
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let (body_id, coroutine_option) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let mut coroutine_kind = None;
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
let e = this.lower_expr_mut(body);
|
||||
|
|
@ -1094,7 +960,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
e
|
||||
});
|
||||
let coroutine_option =
|
||||
this.coroutine_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
(body_id, coroutine_option)
|
||||
});
|
||||
|
||||
|
|
@ -1111,26 +977,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
body: body_id,
|
||||
fn_decl_span: self.lower_span(fn_decl_span),
|
||||
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
||||
movability: coroutine_option,
|
||||
kind: closure_kind,
|
||||
constness: self.lower_constness(constness),
|
||||
});
|
||||
|
||||
hir::ExprKind::Closure(c)
|
||||
}
|
||||
|
||||
fn coroutine_movability_for_fn(
|
||||
fn closure_movability_for_fn(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
fn_decl_span: Span,
|
||||
coroutine_kind: Option<hir::CoroutineKind>,
|
||||
movability: Movability,
|
||||
) -> Option<hir::Movability> {
|
||||
) -> hir::ClosureKind {
|
||||
match coroutine_kind {
|
||||
Some(hir::CoroutineKind::Coroutine) => {
|
||||
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||
if decl.inputs.len() > 1 {
|
||||
self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
|
||||
}
|
||||
Some(movability)
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability))
|
||||
}
|
||||
Some(
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||
|
|
@ -1143,7 +1009,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
if movability == Movability::Static {
|
||||
self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
|
||||
}
|
||||
None
|
||||
hir::ClosureKind::Closure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1204,11 +1070,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
None
|
||||
};
|
||||
|
||||
let async_body = this.make_async_expr(
|
||||
let async_body = this.make_desugared_coroutine_expr(
|
||||
capture_clause,
|
||||
inner_closure_id,
|
||||
async_ret_ty,
|
||||
body.span,
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
);
|
||||
|
|
@ -1235,7 +1102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
body,
|
||||
fn_decl_span: self.lower_span(fn_decl_span),
|
||||
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
||||
movability: None,
|
||||
kind: hir::ClosureKind::Closure,
|
||||
constness: hir::Constness::NotConst,
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
|
|
@ -1655,7 +1522,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.dcx().emit_err(AsyncCoroutinesNotSupported { span }),
|
||||
);
|
||||
}
|
||||
Some(hir::CoroutineKind::Coroutine) | None => {
|
||||
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||
if !self.tcx.features().coroutines {
|
||||
rustc_session::parse::feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
|
|
@ -1665,7 +1532,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
.emit();
|
||||
}
|
||||
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine);
|
||||
false
|
||||
}
|
||||
None => {
|
||||
if !self.tcx.features().coroutines {
|
||||
rustc_session::parse::feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::coroutines,
|
||||
span,
|
||||
"yield syntax is experimental",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
|
||||
false
|
||||
}
|
||||
};
|
||||
|
|
@ -2115,11 +1994,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
lang_item: hir::LangItem,
|
||||
name: Symbol,
|
||||
) -> hir::Expr<'hir> {
|
||||
let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span));
|
||||
let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
|
||||
self.arena.alloc(self.ty(
|
||||
span,
|
||||
hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))),
|
||||
)),
|
||||
self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))),
|
||||
self.arena.alloc(hir::PathSegment::new(
|
||||
Ident::new(name, span),
|
||||
self.next_id(),
|
||||
|
|
|
|||
|
|
@ -339,9 +339,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
|
||||
let constness = match *constness {
|
||||
Const::Yes(span) => BoundConstness::Maybe(span),
|
||||
Const::No => BoundConstness::Never,
|
||||
};
|
||||
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
*constness,
|
||||
constness,
|
||||
trait_ref,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
|
|
@ -952,11 +957,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
params: &'hir [hir::Param<'hir>],
|
||||
value: hir::Expr<'hir>,
|
||||
) -> hir::BodyId {
|
||||
let body = hir::Body {
|
||||
coroutine_kind: self.coroutine_kind,
|
||||
params,
|
||||
value: self.arena.alloc(value),
|
||||
};
|
||||
let body = hir::Body { params, value: self.arena.alloc(value) };
|
||||
let id = body.id();
|
||||
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
||||
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
|
||||
|
|
@ -1208,33 +1209,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
this.expr_block(body)
|
||||
};
|
||||
// FIXME(gen_blocks): Consider unifying the `make_*_expr` functions.
|
||||
let coroutine_expr = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => this.make_async_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
CoroutineKind::Gen { .. } => this.make_gen_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
CoroutineKind::AsyncGen { .. } => this.make_async_gen_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
let desugaring_kind = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
|
||||
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
|
||||
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
|
||||
};
|
||||
let coroutine_expr = this.make_desugared_coroutine_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
desugaring_kind,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
);
|
||||
|
||||
let hir_id = this.lower_node_id(closure_id);
|
||||
this.maybe_forward_track_caller(body.span, fn_id, hir_id);
|
||||
|
|
@ -1253,11 +1241,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
coroutine_kind: Option<CoroutineKind>,
|
||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header);
|
||||
// Don't pass along the user-provided constness of trait associated functions; we don't want to
|
||||
// synthesize a host effect param for them. We reject `const` on them during AST validation.
|
||||
let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No };
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||
});
|
||||
let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(let_chains)]
|
||||
#![recursion_limit = "256"]
|
||||
|
|
@ -770,6 +771,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.resolver.get_import_res(id).present_items()
|
||||
}
|
||||
|
||||
fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> {
|
||||
hir::QPath::Resolved(None, self.make_lang_item_path(lang_item, span, None))
|
||||
}
|
||||
|
||||
fn make_lang_item_path(
|
||||
&mut self,
|
||||
lang_item: hir::LangItem,
|
||||
|
|
@ -787,7 +792,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir_id: self.next_id(),
|
||||
res,
|
||||
args,
|
||||
infer_args: false,
|
||||
infer_args: args.is_none(),
|
||||
}]),
|
||||
})
|
||||
}
|
||||
|
|
@ -1324,7 +1329,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: t.span,
|
||||
},
|
||||
itctx,
|
||||
ast::Const::No,
|
||||
ast::BoundConstness::Never,
|
||||
);
|
||||
let bounds = this.arena.alloc_from_iter([bound]);
|
||||
let lifetime_bound = this.elided_dyn_bound(t.span);
|
||||
|
|
@ -1429,19 +1434,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
|
||||
let bounds =
|
||||
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
|
||||
GenericBound::Trait(
|
||||
ty,
|
||||
TraitBoundModifiers {
|
||||
polarity: BoundPolarity::Positive | BoundPolarity::Negative(_),
|
||||
constness,
|
||||
},
|
||||
) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())),
|
||||
// We can safely ignore constness here, since AST validation
|
||||
// will take care of invalid modifier combinations.
|
||||
GenericBound::Trait(
|
||||
_,
|
||||
TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. },
|
||||
) => None,
|
||||
// We can safely ignore constness here since AST validation
|
||||
// takes care of rejecting invalid modifier combinations and
|
||||
// const trait bounds in trait object types.
|
||||
GenericBound::Trait(ty, modifiers) => match modifiers.polarity {
|
||||
BoundPolarity::Positive | BoundPolarity::Negative(_) => {
|
||||
Some(this.lower_poly_trait_ref(
|
||||
ty,
|
||||
itctx,
|
||||
// Still, don't pass along the constness here; we don't want to
|
||||
// synthesize any host effect args, it'd only cause problems.
|
||||
ast::BoundConstness::Never,
|
||||
))
|
||||
}
|
||||
BoundPolarity::Maybe(_) => None,
|
||||
},
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
lifetime_bound = Some(this.lower_lifetime(lifetime));
|
||||
|
|
@ -2111,7 +2118,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param: &GenericParam,
|
||||
source: hir::GenericParamSource,
|
||||
) -> hir::GenericParam<'hir> {
|
||||
let (name, kind) = self.lower_generic_param_kind(param);
|
||||
let (name, kind) = self.lower_generic_param_kind(param, source);
|
||||
|
||||
let hir_id = self.lower_node_id(param.id);
|
||||
self.lower_attrs(hir_id, ¶m.attrs);
|
||||
|
|
@ -2130,6 +2137,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_generic_param_kind(
|
||||
&mut self,
|
||||
param: &GenericParam,
|
||||
source: hir::GenericParamSource,
|
||||
) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
|
||||
match ¶m.kind {
|
||||
GenericParamKind::Lifetime => {
|
||||
|
|
@ -2148,22 +2156,51 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
(param_name, kind)
|
||||
}
|
||||
GenericParamKind::Type { default, .. } => {
|
||||
let kind = hir::GenericParamKind::Type {
|
||||
default: default.as_ref().map(|x| {
|
||||
// Not only do we deny type param defaults in binders but we also map them to `None`
|
||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||
let default = default
|
||||
.as_ref()
|
||||
.filter(|_| match source {
|
||||
hir::GenericParamSource::Generics => true,
|
||||
hir::GenericParamSource::Binder => {
|
||||
self.dcx().emit_err(errors::GenericParamDefaultInBinder {
|
||||
span: param.span(),
|
||||
});
|
||||
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|def| {
|
||||
self.lower_ty(
|
||||
x,
|
||||
def,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
)
|
||||
}),
|
||||
synthetic: false,
|
||||
};
|
||||
});
|
||||
|
||||
let kind = hir::GenericParamKind::Type { default, synthetic: false };
|
||||
|
||||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||
let ty = self
|
||||
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
|
||||
let default = default.as_ref().map(|def| self.lower_anon_const(def));
|
||||
|
||||
// Not only do we deny const param defaults in binders but we also map them to `None`
|
||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||
let default = default
|
||||
.as_ref()
|
||||
.filter(|_| match source {
|
||||
hir::GenericParamSource::Generics => true,
|
||||
hir::GenericParamSource::Binder => {
|
||||
self.dcx().emit_err(errors::GenericParamDefaultInBinder {
|
||||
span: param.span(),
|
||||
});
|
||||
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|def| self.lower_anon_const(def));
|
||||
|
||||
(
|
||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||
hir::GenericParamKind::Const { ty, default, is_host_effect: false },
|
||||
|
|
@ -2174,7 +2211,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
fn lower_trait_ref(
|
||||
&mut self,
|
||||
constness: ast::Const,
|
||||
constness: ast::BoundConstness,
|
||||
p: &TraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::TraitRef<'hir> {
|
||||
|
|
@ -2197,7 +2234,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
p: &PolyTraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: ast::Const,
|
||||
constness: ast::BoundConstness,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
let bound_generic_params =
|
||||
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
|
||||
|
|
@ -2322,9 +2359,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
modifiers: TraitBoundModifiers,
|
||||
) -> hir::TraitBoundModifier {
|
||||
// Invalid modifier combinations will cause an error during AST validation.
|
||||
// Arbitrarily pick a placeholder for them to make compilation proceed.
|
||||
match (modifiers.constness, modifiers.polarity) {
|
||||
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
|
||||
(BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
|
||||
if self.tcx.features().negative_bounds {
|
||||
hir::TraitBoundModifier::Negative
|
||||
|
|
@ -2332,15 +2371,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::TraitBoundModifier::None
|
||||
}
|
||||
}
|
||||
(BoundConstness::Maybe(_), BoundPolarity::Positive) => {
|
||||
hir::TraitBoundModifier::MaybeConst
|
||||
}
|
||||
// Invalid modifier combinations will cause an error during AST validation.
|
||||
// Arbitrarily pick a placeholder for compilation to proceed.
|
||||
(BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => {
|
||||
hir::TraitBoundModifier::MaybeConst
|
||||
}
|
||||
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
|
||||
(BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2558,45 +2590,62 @@ struct GenericArgsCtor<'hir> {
|
|||
}
|
||||
|
||||
impl<'hir> GenericArgsCtor<'hir> {
|
||||
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
|
||||
fn push_constness(
|
||||
&mut self,
|
||||
lcx: &mut LoweringContext<'_, 'hir>,
|
||||
constness: ast::BoundConstness,
|
||||
) {
|
||||
if !lcx.tcx.features().effects {
|
||||
return;
|
||||
}
|
||||
|
||||
// if bound is non-const, don't add host effect param
|
||||
let ast::Const::Yes(span) = constness else { return };
|
||||
let (span, body) = match constness {
|
||||
BoundConstness::Never => return,
|
||||
BoundConstness::Always(span) => {
|
||||
let span = lcx.lower_span(span);
|
||||
|
||||
let span = lcx.lower_span(span);
|
||||
let body = hir::ExprKind::Lit(
|
||||
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
|
||||
);
|
||||
|
||||
let id = lcx.next_node_id();
|
||||
let hir_id = lcx.next_id();
|
||||
(span, body)
|
||||
}
|
||||
BoundConstness::Maybe(span) => {
|
||||
let span = lcx.lower_span(span);
|
||||
|
||||
let Some(host_param_id) = lcx.host_param_id else {
|
||||
lcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
"no host param id for call in const yet no errors reported",
|
||||
);
|
||||
return;
|
||||
};
|
||||
let Some(host_param_id) = lcx.host_param_id else {
|
||||
lcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
"no host param id for call in const yet no errors reported",
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
let body = lcx.lower_body(|lcx| {
|
||||
(&[], {
|
||||
let hir_id = lcx.next_id();
|
||||
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
|
||||
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
let body = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
lcx.arena.alloc(hir::Path {
|
||||
span,
|
||||
res,
|
||||
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
|
||||
name: sym::host,
|
||||
span,
|
||||
}, hir_id, res)],
|
||||
segments: arena_vec![
|
||||
lcx;
|
||||
hir::PathSegment::new(
|
||||
Ident { name: sym::host, span },
|
||||
hir_id,
|
||||
res
|
||||
)
|
||||
],
|
||||
}),
|
||||
));
|
||||
lcx.expr(span, expr_kind)
|
||||
})
|
||||
});
|
||||
|
||||
(span, body)
|
||||
}
|
||||
};
|
||||
let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
|
||||
|
||||
let id = lcx.next_node_id();
|
||||
let hir_id = lcx.next_id();
|
||||
|
||||
let def_id = lcx.create_def(
|
||||
lcx.current_hir_id_owner.def_id,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
// constness of the impl/bound if this is a trait path
|
||||
constness: Option<ast::Const>,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
|
|
@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param_mode: ParamMode,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: Option<ast::Const>,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
|
||||
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadi
|
|||
.const = `const` because of this
|
||||
.variadic = C-variadic because of this
|
||||
|
||||
ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
|
||||
|
||||
ast_passes_const_without_body =
|
||||
free constant item without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
|
@ -231,8 +233,21 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here
|
|||
.item = this item cannot have `~const` trait bounds
|
||||
|
||||
ast_passes_trait_fn_const =
|
||||
functions in traits cannot be declared const
|
||||
.label = functions in traits cannot be const
|
||||
functions in {$in_impl ->
|
||||
[true] trait impls
|
||||
*[false] traits
|
||||
} cannot be declared const
|
||||
.label = functions in {$in_impl ->
|
||||
[true] trait impls
|
||||
*[false] traits
|
||||
} cannot be const
|
||||
.const_context_label = this declares all associated functions implicitly const
|
||||
.remove_const_sugg = remove the `const`{$requires_multiple_changes ->
|
||||
[true] {" ..."}
|
||||
*[false] {""}
|
||||
}
|
||||
.make_impl_const_sugg = ... and declare the impl to be const instead
|
||||
.make_trait_const_sugg = ... and declare the trait to be a `#[const_trait]` instead
|
||||
|
||||
ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,21 @@ enum DisallowTildeConstContext<'a> {
|
|||
Item,
|
||||
}
|
||||
|
||||
enum TraitOrTraitImpl<'a> {
|
||||
Trait { span: Span, constness: Option<Span> },
|
||||
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef },
|
||||
}
|
||||
|
||||
impl<'a> TraitOrTraitImpl<'a> {
|
||||
fn constness(&self) -> Option<Span> {
|
||||
match self {
|
||||
Self::Trait { constness: Some(span), .. }
|
||||
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AstValidator<'a> {
|
||||
session: &'a Session,
|
||||
features: &'a Features,
|
||||
|
|
@ -53,11 +68,7 @@ struct AstValidator<'a> {
|
|||
/// The span of the `extern` in an `extern { ... }` block, if any.
|
||||
extern_mod: Option<&'a Item>,
|
||||
|
||||
/// Are we inside a trait impl?
|
||||
in_trait_impl: bool,
|
||||
|
||||
/// Are we inside a const trait defn or impl?
|
||||
in_const_trait_or_impl: bool,
|
||||
outer_trait_or_trait_impl: Option<TraitOrTraitImpl<'a>>,
|
||||
|
||||
has_proc_macro_decls: bool,
|
||||
|
||||
|
|
@ -78,24 +89,28 @@ struct AstValidator<'a> {
|
|||
impl<'a> AstValidator<'a> {
|
||||
fn with_in_trait_impl(
|
||||
&mut self,
|
||||
is_in: bool,
|
||||
constness: Option<Const>,
|
||||
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old = mem::replace(&mut self.in_trait_impl, is_in);
|
||||
let old_const = mem::replace(
|
||||
&mut self.in_const_trait_or_impl,
|
||||
matches!(constness, Some(Const::Yes(_))),
|
||||
let old = mem::replace(
|
||||
&mut self.outer_trait_or_trait_impl,
|
||||
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
|
||||
constness,
|
||||
polarity,
|
||||
trait_ref,
|
||||
}),
|
||||
);
|
||||
f(self);
|
||||
self.in_trait_impl = old;
|
||||
self.in_const_trait_or_impl = old_const;
|
||||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const);
|
||||
fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(
|
||||
&mut self.outer_trait_or_trait_impl,
|
||||
Some(TraitOrTraitImpl::Trait { span, constness }),
|
||||
);
|
||||
f(self);
|
||||
self.in_const_trait_or_impl = old;
|
||||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
|
|
@ -291,10 +306,48 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||
if let Const::Yes(span) = constness {
|
||||
self.dcx().emit_err(errors::TraitFnConst { span });
|
||||
}
|
||||
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) {
|
||||
let Const::Yes(span) = constness else {
|
||||
return;
|
||||
};
|
||||
|
||||
let make_impl_const_sugg = if self.features.const_trait_impl
|
||||
&& let TraitOrTraitImpl::TraitImpl {
|
||||
constness: Const::No,
|
||||
polarity: ImplPolarity::Positive,
|
||||
trait_ref,
|
||||
} = parent
|
||||
{
|
||||
Some(trait_ref.path.span.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let make_trait_const_sugg = if self.features.const_trait_impl
|
||||
&& let TraitOrTraitImpl::Trait { span, constness: None } = parent
|
||||
{
|
||||
Some(span.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let parent_constness = parent.constness();
|
||||
self.dcx().emit_err(errors::TraitFnConst {
|
||||
span,
|
||||
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
|
||||
const_context_label: parent_constness,
|
||||
remove_const_sugg: (
|
||||
self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span),
|
||||
match parent_constness {
|
||||
Some(_) => rustc_errors::Applicability::MachineApplicable,
|
||||
None => rustc_errors::Applicability::MaybeIncorrect,
|
||||
},
|
||||
),
|
||||
requires_multiple_changes: make_impl_const_sugg.is_some()
|
||||
|| make_trait_const_sugg.is_some(),
|
||||
make_impl_const_sugg,
|
||||
make_trait_const_sugg,
|
||||
});
|
||||
}
|
||||
|
||||
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||
|
|
@ -817,7 +870,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
self.with_in_trait_impl(true, Some(*constness), |this| {
|
||||
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
|
||||
this.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::TraitImpl,
|
||||
|
|
@ -963,8 +1016,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
|
||||
let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait);
|
||||
self.with_in_trait(is_const_trait, |this| {
|
||||
let is_const_trait =
|
||||
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
|
||||
self.with_in_trait(item.span, is_const_trait, |this| {
|
||||
if *is_auto == IsAuto::Yes {
|
||||
// Auto traits cannot have generics, super traits nor contain items.
|
||||
this.deny_generic_params(generics, item.ident.span);
|
||||
|
|
@ -977,8 +1031,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
// context for the supertraits.
|
||||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
let disallowed =
|
||||
(!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span));
|
||||
let disallowed = is_const_trait
|
||||
.is_none()
|
||||
.then(|| DisallowTildeConstContext::Trait(item.span));
|
||||
this.with_tilde_const(disallowed, |this| {
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
||||
|
|
@ -1207,6 +1262,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
|
||||
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
|
||||
}
|
||||
(BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
|
||||
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
|
||||
}
|
||||
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
|
||||
if let Some(reason) = &self.disallow_tilde_const =>
|
||||
{
|
||||
|
|
@ -1237,8 +1295,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
(
|
||||
_,
|
||||
BoundConstness::Maybe(_),
|
||||
BoundPolarity::Maybe(_) | BoundPolarity::Negative(_),
|
||||
BoundConstness::Always(_) | BoundConstness::Maybe(_),
|
||||
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
|
||||
) => {
|
||||
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
|
||||
span: bound.span(),
|
||||
|
|
@ -1339,7 +1397,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
let tilde_const_allowed =
|
||||
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|
||||
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl);
|
||||
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
|
||||
&& self
|
||||
.outer_trait_or_trait_impl
|
||||
.as_ref()
|
||||
.and_then(TraitOrTraitImpl::constness)
|
||||
.is_some();
|
||||
|
||||
let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
|
||||
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
|
||||
|
|
@ -1350,7 +1413,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_nomangle_item_asciionly(item.ident, item.span);
|
||||
}
|
||||
|
||||
if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
|
||||
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
||||
self.check_defaultness(item.span, item.kind.defaultness());
|
||||
}
|
||||
|
||||
|
|
@ -1398,10 +1461,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
);
|
||||
}
|
||||
|
||||
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
|
||||
if let Some(parent) = &self.outer_trait_or_trait_impl {
|
||||
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
self.check_trait_fn_not_const(sig.header.constness, parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1411,7 +1474,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
match &item.kind {
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
|
||||
if self.in_const_trait_or_impl
|
||||
if self
|
||||
.outer_trait_or_trait_impl
|
||||
.as_ref()
|
||||
.and_then(TraitOrTraitImpl::constness)
|
||||
.is_some()
|
||||
|| ctxt == AssocCtxt::Trait
|
||||
|| matches!(sig.header.constness, Const::Yes(_)) =>
|
||||
{
|
||||
|
|
@ -1427,8 +1494,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
}
|
||||
_ => self
|
||||
.with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1544,8 +1610,7 @@ pub fn check_crate(
|
|||
session,
|
||||
features,
|
||||
extern_mod: None,
|
||||
in_trait_impl: false,
|
||||
in_const_trait_or_impl: false,
|
||||
outer_trait_or_trait_impl: None,
|
||||
has_proc_macro_decls: false,
|
||||
outer_impl_trait: None,
|
||||
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_ast::ParamKindOrd;
|
||||
use rustc_errors::AddToDiagnostic;
|
||||
use rustc_errors::{AddToDiagnostic, Applicability};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
|
|
@ -49,6 +49,24 @@ pub struct TraitFnConst {
|
|||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub in_impl: bool,
|
||||
#[label(ast_passes_const_context_label)]
|
||||
pub const_context_label: Option<Span>,
|
||||
#[suggestion(ast_passes_remove_const_sugg, code = "")]
|
||||
pub remove_const_sugg: (Span, Applicability),
|
||||
pub requires_multiple_changes: bool,
|
||||
#[suggestion(
|
||||
ast_passes_make_impl_const_sugg,
|
||||
code = "const ",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub make_impl_const_sugg: Option<Span>,
|
||||
#[suggestion(
|
||||
ast_passes_make_trait_const_sugg,
|
||||
code = "#[const_trait]\n",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub make_trait_const_sugg: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -540,6 +558,13 @@ pub struct OptionalTraitObject {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_const_bound_trait_object)]
|
||||
pub struct ConstBoundTraitObject {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_tilde_const_disallowed)]
|
||||
pub struct TildeConstDisallowed {
|
||||
|
|
|
|||
|
|
@ -1096,14 +1096,22 @@ impl<'a> State<'a> {
|
|||
ast::StmtKind::Item(item) => self.print_item(item),
|
||||
ast::StmtKind::Expr(expr) => {
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.print_expr_outer_attr_style(
|
||||
expr,
|
||||
false,
|
||||
FixupContext { stmt: true, ..FixupContext::default() },
|
||||
);
|
||||
if classify::expr_requires_semi_to_be_stmt(expr) {
|
||||
self.word(";");
|
||||
}
|
||||
}
|
||||
ast::StmtKind::Semi(expr) => {
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.print_expr_outer_attr_style(
|
||||
expr,
|
||||
false,
|
||||
FixupContext { stmt: true, ..FixupContext::default() },
|
||||
);
|
||||
self.word(";");
|
||||
}
|
||||
ast::StmtKind::Empty => {
|
||||
|
|
@ -1155,7 +1163,11 @@ impl<'a> State<'a> {
|
|||
ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
|
||||
self.maybe_print_comment(st.span.lo());
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.print_expr_outer_attr_style(
|
||||
expr,
|
||||
false,
|
||||
FixupContext { stmt: true, ..FixupContext::default() },
|
||||
);
|
||||
self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
|
||||
}
|
||||
_ => self.print_stmt(st),
|
||||
|
|
@ -1561,7 +1573,7 @@ impl<'a> State<'a> {
|
|||
GenericBound::Trait(tref, modifier) => {
|
||||
match modifier.constness {
|
||||
ast::BoundConstness::Never => {}
|
||||
ast::BoundConstness::Maybe(_) => {
|
||||
ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
|
||||
self.word_space(modifier.constness.as_str());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use ast::ForLoopKind;
|
|||
use itertools::{Itertools, Position};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::{self as ast, BlockCheckMode};
|
||||
|
|
@ -15,6 +16,61 @@ use std::fmt::Write;
|
|||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct FixupContext {
|
||||
/// Print expression such that it can be parsed back as a statement
|
||||
/// consisting of the original expression.
|
||||
///
|
||||
/// The effect of this is for binary operators in statement position to set
|
||||
/// `leftmost_subexpression_in_stmt` when printing their left-hand operand.
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// (match x {}) - 1; // match needs parens when LHS of binary operator
|
||||
///
|
||||
/// match x {}; // not when its own statement
|
||||
/// ```
|
||||
pub stmt: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// (match x {}) - 1; // subexpression needs parens
|
||||
///
|
||||
/// let _ = match x {} - 1; // no parens
|
||||
/// ```
|
||||
///
|
||||
/// There are 3 distinguishable contexts in which `print_expr` might be
|
||||
/// called with the expression `$match` as its argument, where `$match`
|
||||
/// represents an expression of kind `ExprKind::Match`:
|
||||
///
|
||||
/// - stmt=false leftmost_subexpression_in_stmt=false
|
||||
///
|
||||
/// Example: `let _ = $match - 1;`
|
||||
///
|
||||
/// No parentheses required.
|
||||
///
|
||||
/// - stmt=false leftmost_subexpression_in_stmt=true
|
||||
///
|
||||
/// Example: `$match - 1;`
|
||||
///
|
||||
/// Must parenthesize `($match)`, otherwise parsing back the output as a
|
||||
/// statement would terminate the statement after the closing brace of
|
||||
/// the match, parsing `-1;` as a separate statement.
|
||||
///
|
||||
/// - stmt=true leftmost_subexpression_in_stmt=false
|
||||
///
|
||||
/// Example: `$match;`
|
||||
///
|
||||
/// No parentheses required.
|
||||
pub leftmost_subexpression_in_stmt: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// if let _ = (Struct {}) {} // needs parens
|
||||
///
|
||||
/// match () {
|
||||
/// () if let _ = Struct {} => {} // no parens
|
||||
/// }
|
||||
/// ```
|
||||
pub parenthesize_exterior_struct_lit: bool,
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +78,11 @@ pub(crate) struct FixupContext {
|
|||
/// in a targetted fashion where needed.
|
||||
impl Default for FixupContext {
|
||||
fn default() -> Self {
|
||||
FixupContext { parenthesize_exterior_struct_lit: false }
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
parenthesize_exterior_struct_lit: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +136,8 @@ impl<'a> State<'a> {
|
|||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
/// `if cond { ... }`.
|
||||
fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
|
||||
let fixup = FixupContext { parenthesize_exterior_struct_lit: true };
|
||||
let fixup =
|
||||
FixupContext { parenthesize_exterior_struct_lit: true, ..FixupContext::default() };
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup)
|
||||
}
|
||||
|
||||
|
|
@ -99,26 +160,25 @@ impl<'a> State<'a> {
|
|||
&mut self,
|
||||
expr: &ast::Expr,
|
||||
needs_par: bool,
|
||||
fixup: FixupContext,
|
||||
mut fixup: FixupContext,
|
||||
) {
|
||||
if needs_par {
|
||||
self.popen();
|
||||
|
||||
// If we are surrounding the whole cond in parentheses, such as:
|
||||
//
|
||||
// if (return Struct {}) {}
|
||||
//
|
||||
// then there is no need for parenthesizing the individual struct
|
||||
// expressions within. On the other hand if the whole cond is not
|
||||
// parenthesized, then print_expr must parenthesize exterior struct
|
||||
// literals.
|
||||
//
|
||||
// if x == (Struct {}) {}
|
||||
//
|
||||
fixup = FixupContext::default();
|
||||
}
|
||||
|
||||
// If we are surrounding the whole cond in parentheses, such as:
|
||||
//
|
||||
// if (return Struct {}) {}
|
||||
//
|
||||
// then there is no need for parenthesizing the individual struct
|
||||
// expressions within. On the other hand if the whole cond is not
|
||||
// parenthesized, then print_expr must parenthesize exterior struct
|
||||
// literals.
|
||||
//
|
||||
// if x == (Struct {}) {}
|
||||
//
|
||||
let fixup = FixupContext {
|
||||
parenthesize_exterior_struct_lit: fixup.parenthesize_exterior_struct_lit && !needs_par,
|
||||
};
|
||||
self.print_expr(expr, fixup);
|
||||
|
||||
if needs_par {
|
||||
|
|
@ -234,7 +294,32 @@ impl<'a> State<'a> {
|
|||
_ => parser::PREC_POSTFIX,
|
||||
};
|
||||
|
||||
self.print_expr_maybe_paren(func, prec, fixup);
|
||||
// Independent of parenthesization related to precedence, we must
|
||||
// parenthesize `func` if this is a statement context in which without
|
||||
// parentheses, a statement boundary would occur inside `func` or
|
||||
// immediately after `func`.
|
||||
//
|
||||
// Suppose `func` represents `match () { _ => f }`. We must produce:
|
||||
//
|
||||
// (match () { _ => f })();
|
||||
//
|
||||
// instead of:
|
||||
//
|
||||
// match () { _ => f } ();
|
||||
//
|
||||
// because the latter is valid syntax but with the incorrect meaning.
|
||||
// It's a match-expression followed by tuple-expression, not a function
|
||||
// call.
|
||||
self.print_expr_maybe_paren(
|
||||
func,
|
||||
prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +330,17 @@ impl<'a> State<'a> {
|
|||
base_args: &[P<ast::Expr>],
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
// Unlike in `print_expr_call`, no change to fixup here because
|
||||
// statement boundaries never occur in front of a `.` (or `?`) token.
|
||||
//
|
||||
// match () { _ => f }.method();
|
||||
//
|
||||
// Parenthesizing only for precedence and not with regard to statement
|
||||
// boundaries, `$receiver.method()` can be parsed back as a statement
|
||||
// containing an expression if and only if `$receiver` can be parsed as
|
||||
// a statement containing an expression.
|
||||
self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup);
|
||||
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
if let Some(args) = &segment.args {
|
||||
|
|
@ -289,22 +384,36 @@ impl<'a> State<'a> {
|
|||
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
}
|
||||
// For a binary expression like `(match () { _ => a }) OP b`, the parens are required
|
||||
// otherwise the parser would interpret `match () { _ => a }` as a statement,
|
||||
// with the remaining `OP b` not making sense. So we force parens.
|
||||
(&ast::ExprKind::Match(..), _) => parser::PREC_FORCE_PAREN,
|
||||
_ => left_prec,
|
||||
};
|
||||
|
||||
self.print_expr_maybe_paren(lhs, left_prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
lhs,
|
||||
left_prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
|
||||
self.space();
|
||||
self.word_space(op.node.as_str());
|
||||
self.print_expr_maybe_paren(rhs, right_prec, fixup)
|
||||
|
||||
self.print_expr_maybe_paren(
|
||||
rhs,
|
||||
right_prec,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_PREFIX,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(
|
||||
|
|
@ -322,7 +431,11 @@ impl<'a> State<'a> {
|
|||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_PREFIX,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) {
|
||||
|
|
@ -333,7 +446,7 @@ impl<'a> State<'a> {
|
|||
&mut self,
|
||||
expr: &ast::Expr,
|
||||
is_inline: bool,
|
||||
fixup: FixupContext,
|
||||
mut fixup: FixupContext,
|
||||
) {
|
||||
self.maybe_print_comment(expr.span.lo());
|
||||
|
||||
|
|
@ -345,7 +458,27 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
|
||||
// The Match subexpression in `match x {} - 1` must be parenthesized if
|
||||
// it is the leftmost subexpression in a statement:
|
||||
//
|
||||
// (match x {}) - 1;
|
||||
//
|
||||
// But not otherwise:
|
||||
//
|
||||
// let _ = match x {} - 1;
|
||||
//
|
||||
// Same applies to a small set of other expression kinds which eagerly
|
||||
// terminate a statement which opens with them.
|
||||
let needs_par =
|
||||
fixup.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr);
|
||||
if needs_par {
|
||||
self.popen();
|
||||
fixup = FixupContext::default();
|
||||
}
|
||||
|
||||
self.ann.pre(self, AnnNode::Expr(expr));
|
||||
|
||||
match &expr.kind {
|
||||
ast::ExprKind::Array(exprs) => {
|
||||
self.print_expr_vec(exprs);
|
||||
|
|
@ -386,7 +519,16 @@ impl<'a> State<'a> {
|
|||
}
|
||||
ast::ExprKind::Cast(expr, ty) => {
|
||||
let prec = AssocOp::As.precedence() as i8;
|
||||
self.print_expr_maybe_paren(expr, prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.space();
|
||||
self.word_space("as");
|
||||
self.print_type(ty);
|
||||
|
|
@ -508,31 +650,71 @@ impl<'a> State<'a> {
|
|||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Await(expr, _) => {
|
||||
// Same fixups as ExprKind::MethodCall.
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word(".await");
|
||||
}
|
||||
ast::ExprKind::Assign(lhs, rhs, _) => {
|
||||
// Same fixups as ExprKind::Binary.
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
lhs,
|
||||
prec + 1,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
rhs,
|
||||
prec,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
// Same fixups as ExprKind::Binary.
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
lhs,
|
||||
prec + 1,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.space();
|
||||
self.word(op.node.as_str());
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
rhs,
|
||||
prec,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
// Same fixups as ExprKind::MethodCall.
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word(".");
|
||||
self.print_ident(*ident);
|
||||
}
|
||||
ast::ExprKind::Index(expr, index, _) => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
// Same fixups as ExprKind::Call.
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_POSTFIX,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.word("[");
|
||||
self.print_expr(index, FixupContext::default());
|
||||
self.word("]");
|
||||
|
|
@ -544,14 +726,31 @@ impl<'a> State<'a> {
|
|||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = AssocOp::LOr.precedence() as i8;
|
||||
if let Some(e) = start {
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
e,
|
||||
fake_prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
match limits {
|
||||
ast::RangeLimits::HalfOpen => self.word(".."),
|
||||
ast::RangeLimits::Closed => self.word("..="),
|
||||
}
|
||||
if let Some(e) = end {
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
e,
|
||||
fake_prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Underscore => self.word("_"),
|
||||
|
|
@ -565,7 +764,15 @@ impl<'a> State<'a> {
|
|||
}
|
||||
if let Some(expr) = opt_expr {
|
||||
self.space();
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Continue(opt_label) => {
|
||||
|
|
@ -579,7 +786,15 @@ impl<'a> State<'a> {
|
|||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yeet(result) => {
|
||||
|
|
@ -588,13 +803,25 @@ impl<'a> State<'a> {
|
|||
self.word("yeet");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(result, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
result,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: This should have its own syntax, distinct from a macro invocation.
|
||||
|
|
@ -644,10 +871,19 @@ impl<'a> State<'a> {
|
|||
|
||||
if let Some(expr) = e {
|
||||
self.space();
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Try(e) => {
|
||||
// Same fixups as ExprKind::MethodCall.
|
||||
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup);
|
||||
self.word("?")
|
||||
}
|
||||
|
|
@ -663,7 +899,13 @@ impl<'a> State<'a> {
|
|||
self.pclose()
|
||||
}
|
||||
}
|
||||
|
||||
self.ann.post(self, AnnNode::Expr(expr));
|
||||
|
||||
if needs_par {
|
||||
self.pclose();
|
||||
}
|
||||
|
||||
self.end();
|
||||
}
|
||||
|
||||
|
|
@ -704,7 +946,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
_ => {
|
||||
self.end(); // Close the ibox for the pattern.
|
||||
self.print_expr(body, FixupContext::default());
|
||||
self.print_expr(body, FixupContext { stmt: true, ..FixupContext::default() });
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
span: Span,
|
||||
use_spans: UseSpans<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
// We need all statements in the body where the binding was assigned to to later find all
|
||||
// We need all statements in the body where the binding was assigned to later find all
|
||||
// the branching code paths where the binding *wasn't* assigned to.
|
||||
let inits = &self.move_data.init_path_map[mpi];
|
||||
let move_path = &self.move_data.move_paths[mpi];
|
||||
|
|
@ -848,8 +848,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => MoveUseInCoroutine { var_span },
|
||||
None => MoveUseInClosure { var_span },
|
||||
hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => MoveUseInClosure { var_span },
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -893,10 +893,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let place = &borrow.borrowed_place;
|
||||
let desc_place = self.describe_any_place(place.as_ref());
|
||||
match kind {
|
||||
Some(_) => {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }
|
||||
}
|
||||
None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true },
|
||||
hir::ClosureKind::Closure => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1040,12 +1042,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUsePlaceCoroutine {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: true,
|
||||
},
|
||||
None => BorrowUsePlaceClosure {
|
||||
hir::ClosureKind::Closure => BorrowUsePlaceClosure {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: true,
|
||||
|
|
@ -1124,12 +1126,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUsePlaceCoroutine {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
None => {
|
||||
hir::ClosureKind::Closure => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
|
||||
}
|
||||
}
|
||||
|
|
@ -1144,10 +1146,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let borrow_place = &issued_borrow.borrowed_place;
|
||||
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
|
||||
match kind {
|
||||
Some(_) => {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
|
||||
}
|
||||
None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span },
|
||||
hir::ClosureKind::Closure => {
|
||||
FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
@ -1159,8 +1163,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => SecondBorrowUsePlaceCoroutine { place: desc_place, var_span },
|
||||
None => SecondBorrowUsePlaceClosure { place: desc_place, var_span },
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
SecondBorrowUsePlaceClosure { place: desc_place, var_span }
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
@ -1651,7 +1659,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||
if e.span.contains(self.capture_span) {
|
||||
if let hir::ExprKind::Closure(&hir::Closure {
|
||||
movability: None,
|
||||
kind: hir::ClosureKind::Closure,
|
||||
body,
|
||||
fn_arg_span,
|
||||
fn_decl: hir::FnDecl { inputs, .. },
|
||||
|
|
@ -1686,7 +1694,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&& let Some(init) = local.init
|
||||
{
|
||||
if let hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }),
|
||||
kind:
|
||||
hir::ExprKind::Closure(&hir::Closure {
|
||||
kind: hir::ClosureKind::Closure,
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = init
|
||||
&& init.span.contains(self.capture_span)
|
||||
|
|
@ -2537,7 +2549,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
CoroutineKind::Coroutine => "coroutine",
|
||||
CoroutineKind::Coroutine(_) => "coroutine",
|
||||
},
|
||||
None => "closure",
|
||||
};
|
||||
|
|
@ -2838,8 +2850,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUseInCoroutine { var_span },
|
||||
None => BorrowUseInClosure { var_span },
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -2854,8 +2866,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUseInCoroutine { var_span },
|
||||
None => BorrowUseInClosure { var_span },
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -3055,7 +3067,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
// Define a fallback for when we can't match a closure.
|
||||
let fallback = || {
|
||||
let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id());
|
||||
if is_closure {
|
||||
None
|
||||
} else {
|
||||
|
|
@ -3265,7 +3277,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
|
||||
let is_closure = self.infcx.tcx.is_closure(did.to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id());
|
||||
let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did);
|
||||
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
ty::Array(ty, _) | ty::Slice(ty) => {
|
||||
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
|
||||
}
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _, _) => {
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
|
||||
// We won't be borrowck'ing here if the closure came from another crate,
|
||||
// so it's safe to call `expect_local`.
|
||||
//
|
||||
|
|
@ -505,7 +505,7 @@ pub(super) enum UseSpans<'tcx> {
|
|||
/// The access is caused by capturing a variable for a closure.
|
||||
ClosureUse {
|
||||
/// This is true if the captured variable was from a coroutine.
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
/// The span of the args of the closure, including the `move` keyword if
|
||||
/// it's present.
|
||||
args_span: Span,
|
||||
|
|
@ -572,9 +572,13 @@ impl UseSpans<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(coroutines): Make this just return the `ClosureKind` directly?
|
||||
pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
|
||||
match self {
|
||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind,
|
||||
UseSpans::ClosureUse {
|
||||
closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||
..
|
||||
} => Some(coroutine_kind),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -599,9 +603,9 @@ impl UseSpans<'_> {
|
|||
) {
|
||||
use crate::InitializationRequiringAction::*;
|
||||
use CaptureVarPathUseCause::*;
|
||||
if let UseSpans::ClosureUse { coroutine_kind, path_span, .. } = self {
|
||||
match coroutine_kind {
|
||||
Some(_) => {
|
||||
if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
|
||||
match closure_kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
|
|
@ -609,7 +613,7 @@ impl UseSpans<'_> {
|
|||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
});
|
||||
}
|
||||
None => {
|
||||
hir::ClosureKind::Closure => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
|
|
@ -627,9 +631,9 @@ impl UseSpans<'_> {
|
|||
dcx: Option<&rustc_errors::DiagCtxt>,
|
||||
err: &mut Diagnostic,
|
||||
kind: Option<rustc_middle::mir::BorrowKind>,
|
||||
f: impl FnOnce(Option<CoroutineKind>, Span) -> CaptureVarCause,
|
||||
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
||||
) {
|
||||
if let UseSpans::ClosureUse { coroutine_kind, capture_kind_span, path_span, .. } = self {
|
||||
if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
|
||||
if capture_kind_span != path_span {
|
||||
err.subdiagnostic(match kind {
|
||||
Some(kd) => match kd {
|
||||
|
|
@ -645,7 +649,7 @@ impl UseSpans<'_> {
|
|||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
});
|
||||
};
|
||||
let diag = f(coroutine_kind, path_span);
|
||||
let diag = f(closure_kind, path_span);
|
||||
match dcx {
|
||||
Some(hd) => err.eager_subdiagnostic(hd, diag),
|
||||
None => err.subdiagnostic(diag),
|
||||
|
|
@ -656,7 +660,9 @@ impl UseSpans<'_> {
|
|||
/// Returns `false` if this place is not used in a closure.
|
||||
pub(super) fn for_closure(&self) -> bool {
|
||||
match *self {
|
||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_none(),
|
||||
UseSpans::ClosureUse { closure_kind, .. } => {
|
||||
matches!(closure_kind, hir::ClosureKind::Closure)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -664,7 +670,10 @@ impl UseSpans<'_> {
|
|||
/// Returns `false` if this place is not used in a coroutine.
|
||||
pub(super) fn for_coroutine(&self) -> bool {
|
||||
match *self {
|
||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_some(),
|
||||
// FIXME(coroutines): Do we want this to apply to synthetic coroutines?
|
||||
UseSpans::ClosureUse { closure_kind, .. } => {
|
||||
matches!(closure_kind, hir::ClosureKind::Coroutine(..))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -783,15 +792,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
||||
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
|
||||
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) =
|
||||
**kind
|
||||
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind
|
||||
{
|
||||
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
|
||||
let def_id = def_id.expect_local();
|
||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
||||
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||
self.closure_span(def_id, moved_place, places)
|
||||
{
|
||||
return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
|
||||
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -803,11 +811,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
| FakeReadCause::ForLet(Some(closure_def_id)) => {
|
||||
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
|
||||
let places = &[Operand::Move(place)];
|
||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
||||
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||
self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
|
||||
{
|
||||
return ClosureUse {
|
||||
coroutine_kind,
|
||||
closure_kind,
|
||||
args_span,
|
||||
capture_kind_span,
|
||||
path_span,
|
||||
|
|
@ -919,7 +927,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
|
||||
let (&def_id, is_coroutine) = match kind {
|
||||
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
||||
box AggregateKind::Coroutine(def_id, _, _) => (def_id, true),
|
||||
box AggregateKind::Coroutine(def_id, _) => (def_id, true),
|
||||
_ => continue,
|
||||
};
|
||||
let def_id = def_id.expect_local();
|
||||
|
|
@ -928,10 +936,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
|
||||
def_id, is_coroutine, places
|
||||
);
|
||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
||||
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||
self.closure_span(def_id, Place::from(target).as_ref(), places)
|
||||
{
|
||||
return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
|
||||
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
||||
} else {
|
||||
return OtherUse(use_span);
|
||||
}
|
||||
|
|
@ -953,7 +961,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
def_id: LocalDefId,
|
||||
target_place: PlaceRef<'tcx>,
|
||||
places: &IndexSlice<FieldIdx, Operand<'tcx>>,
|
||||
) -> Option<(Span, Option<CoroutineKind>, Span, Span)> {
|
||||
) -> Option<(Span, hir::ClosureKind, Span, Span)> {
|
||||
debug!(
|
||||
"closure_span: def_id={:?} target_place={:?} places={:?}",
|
||||
def_id, target_place, places
|
||||
|
|
@ -961,7 +969,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
|
||||
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
|
||||
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {
|
||||
for (captured_place, place) in
|
||||
self.infcx.tcx.closure_captures(def_id).iter().zip(places)
|
||||
{
|
||||
|
|
@ -970,12 +978,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if target_place == place.as_ref() =>
|
||||
{
|
||||
debug!("closure_span: found captured local {:?}", place);
|
||||
let body = self.infcx.tcx.hir().body(body);
|
||||
let coroutine_kind = body.coroutine_kind();
|
||||
|
||||
return Some((
|
||||
fn_decl_span,
|
||||
coroutine_kind,
|
||||
kind,
|
||||
captured_place.get_capture_kind_span(self.infcx.tcx),
|
||||
captured_place.get_path_span(self.infcx.tcx),
|
||||
));
|
||||
|
|
@ -1242,8 +1247,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// another message for the same span
|
||||
if !is_loop_message {
|
||||
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
|
||||
Some(_) => CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial },
|
||||
None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial },
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1030,8 +1030,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let hir = self.infcx.tcx.hir();
|
||||
if let InstanceDef::Item(def_id) = source.instance
|
||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
||||
&& let ExprKind::Closure(closure) = kind
|
||||
&& closure.movability == None
|
||||
&& let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
|
||||
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
|
||||
{
|
||||
let mut cur_expr = expr;
|
||||
|
|
|
|||
|
|
@ -1041,13 +1041,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
hir::ExprKind::Closure(hir::Closure {
|
||||
capture_clause: hir::CaptureBy::Ref,
|
||||
body,
|
||||
kind,
|
||||
..
|
||||
}) => {
|
||||
let body = map.body(*body);
|
||||
if !matches!(
|
||||
body.coroutine_kind,
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _))
|
||||
kind,
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
_
|
||||
),)
|
||||
) {
|
||||
closure_span = Some(expr.span.shrink_to_lo());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -674,7 +674,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
|
||||
let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) {
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }),
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, kind, fn_decl_span, .. }),
|
||||
..
|
||||
}) => {
|
||||
let (mut span, mut hir_ty) = match fn_decl.output {
|
||||
|
|
@ -683,62 +683,86 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
}
|
||||
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
|
||||
};
|
||||
let mir_description = match hir.body(body).coroutine_kind {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, src)) => {
|
||||
match src {
|
||||
hir::CoroutineSource::Block => " of async block",
|
||||
hir::CoroutineSource::Closure => " of async closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
.fn_decl()
|
||||
.expect("coroutine lowered from async fn should be in fn")
|
||||
.output;
|
||||
span = output.span();
|
||||
if let hir::FnRetTy::Return(ret) = output {
|
||||
hir_ty = Some(self.get_future_inner_return_ty(*ret));
|
||||
}
|
||||
" of async function"
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, src)) => {
|
||||
match src {
|
||||
hir::CoroutineSource::Block => " of gen block",
|
||||
hir::CoroutineSource::Closure => " of gen closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
.fn_decl()
|
||||
.expect("coroutine lowered from gen fn should be in fn")
|
||||
.output;
|
||||
span = output.span();
|
||||
" of gen function"
|
||||
}
|
||||
let mir_description = match kind {
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Block,
|
||||
)) => " of async block",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of async closure",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
.fn_decl()
|
||||
.expect("coroutine lowered from async fn should be in fn")
|
||||
.output;
|
||||
span = output.span();
|
||||
if let hir::FnRetTy::Return(ret) = output {
|
||||
hir_ty = Some(self.get_future_inner_return_ty(*ret));
|
||||
}
|
||||
" of async function"
|
||||
}
|
||||
|
||||
Some(hir::CoroutineKind::Desugared(
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Block,
|
||||
)) => " of gen block",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of gen closure",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
.fn_decl()
|
||||
.expect("coroutine lowered from gen fn should be in fn")
|
||||
.output;
|
||||
span = output.span();
|
||||
" of gen function"
|
||||
}
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
src,
|
||||
)) => match src {
|
||||
hir::CoroutineSource::Block => " of async gen block",
|
||||
hir::CoroutineSource::Closure => " of async gen closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
.fn_decl()
|
||||
.expect("coroutine lowered from async gen fn should be in fn")
|
||||
.output;
|
||||
span = output.span();
|
||||
" of async gen function"
|
||||
}
|
||||
},
|
||||
Some(hir::CoroutineKind::Coroutine) => " of coroutine",
|
||||
None => " of closure",
|
||||
hir::CoroutineSource::Block,
|
||||
)) => " of async gen block",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of async gen closure",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
.fn_decl()
|
||||
.expect("coroutine lowered from async gen fn should be in fn")
|
||||
.output;
|
||||
span = output.span();
|
||||
" of async gen function"
|
||||
}
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => {
|
||||
" of coroutine"
|
||||
}
|
||||
hir::ClosureKind::Closure => " of closure",
|
||||
};
|
||||
(span, mir_description, hir_ty)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,11 +274,12 @@ fn do_mir_borrowck<'tcx>(
|
|||
// The first argument is the coroutine type passed by value
|
||||
if let Some(local) = body.local_decls.raw.get(1)
|
||||
// Get the interior types and args which typeck computed
|
||||
&& let ty::Coroutine(_, _, hir::Movability::Static) = local.ty.kind()
|
||||
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
|
||||
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
|
||||
{
|
||||
false
|
||||
} else {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
for (idx, move_data) in promoted_move_data {
|
||||
|
|
@ -1306,7 +1307,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// moved into the closure and subsequently used by the closure,
|
||||
// in order to populate our used_mut set.
|
||||
match **aggregate_kind {
|
||||
AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) => {
|
||||
AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => {
|
||||
let def_id = def_id.expect_local();
|
||||
let BorrowCheckResult { used_mut_upvars, .. } =
|
||||
self.infcx.tcx.mir_borrowck(def_id);
|
||||
|
|
@ -1612,7 +1613,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::Coroutine(_, _, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
|
|
@ -1636,7 +1637,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
}
|
||||
ty::Closure(_, _) | ty::Coroutine(_, _, _) | ty::Tuple(_) => (),
|
||||
ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
#[instrument(skip(self, body), level = "debug")]
|
||||
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
if !self.tcx().is_closure(mir_def_id.to_def_id()) {
|
||||
if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
|
||||
|
|
|
|||
|
|
@ -762,7 +762,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
let (variant, args) = match base_ty {
|
||||
PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
|
||||
ty::Adt(adt_def, args) => (adt_def.variant(variant_index), args),
|
||||
ty::Coroutine(def_id, args, _) => {
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let mut variants = args.as_coroutine().state_tys(def_id, tcx);
|
||||
let Some(mut variant) = variants.nth(variant_index.into()) else {
|
||||
bug!(
|
||||
|
|
@ -790,7 +790,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
}),
|
||||
};
|
||||
}
|
||||
ty::Coroutine(_, args, _) => {
|
||||
ty::Coroutine(_, args) => {
|
||||
// Only prefix fields (upvars and current state) are
|
||||
// accessible without a variant index.
|
||||
return match args.as_coroutine().prefix_tys().get(field.index()) {
|
||||
|
|
@ -1784,7 +1784,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
AggregateKind::Coroutine(_, args, _) => {
|
||||
AggregateKind::Coroutine(_, args) => {
|
||||
// It doesn't make sense to look at a field beyond the prefix;
|
||||
// these require a variant index, and are not initialized in
|
||||
// aggregate rvalues.
|
||||
|
|
@ -2392,7 +2392,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
AggregateKind::Array(_) => None,
|
||||
AggregateKind::Tuple => None,
|
||||
AggregateKind::Closure(_, _) => None,
|
||||
AggregateKind::Coroutine(_, _, _) => None,
|
||||
AggregateKind::Coroutine(_, _) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -2620,7 +2620,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// desugaring. A closure gets desugared to a struct, and
|
||||
// these extra requirements are basically like where
|
||||
// clauses on the struct.
|
||||
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args, _) => {
|
||||
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => {
|
||||
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::BodyOwnerKind;
|
||||
|
|
@ -94,7 +93,7 @@ pub enum DefiningTy<'tcx> {
|
|||
/// The MIR is a coroutine. The signature is that coroutines take
|
||||
/// no parameters and return the result of
|
||||
/// `ClosureArgs::coroutine_return_ty`.
|
||||
Coroutine(DefId, GenericArgsRef<'tcx>, hir::Movability),
|
||||
Coroutine(DefId, GenericArgsRef<'tcx>),
|
||||
|
||||
/// The MIR is a fn item with the given `DefId` and args. The signature
|
||||
/// of the function can be bound then with the `fn_sig` query.
|
||||
|
|
@ -118,7 +117,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
|||
pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
|
||||
match self {
|
||||
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
|
||||
DefiningTy::Coroutine(_, args, _) => args.as_coroutine().upvar_tys(),
|
||||
DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
|
||||
ty::List::empty()
|
||||
}
|
||||
|
|
@ -354,7 +353,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));
|
||||
});
|
||||
}
|
||||
DefiningTy::Coroutine(def_id, args, _) => {
|
||||
DefiningTy::Coroutine(def_id, args) => {
|
||||
let v = with_no_trimmed_paths!(
|
||||
args[tcx.generics_of(def_id).parent_count..]
|
||||
.iter()
|
||||
|
|
@ -527,7 +526,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
debug!("build: local regions = {}..{}", first_local_index, num_universals);
|
||||
|
||||
let yield_ty = match defining_ty {
|
||||
DefiningTy::Coroutine(_, args, _) => Some(args.as_coroutine().yield_ty()),
|
||||
DefiningTy::Coroutine(_, args) => Some(args.as_coroutine().yield_ty()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
|
@ -562,9 +561,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
|
||||
match *defining_ty.kind() {
|
||||
ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args),
|
||||
ty::Coroutine(def_id, args, movability) => {
|
||||
DefiningTy::Coroutine(def_id, args, movability)
|
||||
}
|
||||
ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args),
|
||||
ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args),
|
||||
_ => span_bug!(
|
||||
tcx.def_span(self.mir_def),
|
||||
|
|
@ -620,7 +617,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
let fr_args = match defining_ty {
|
||||
DefiningTy::Closure(_, args)
|
||||
| DefiningTy::Coroutine(_, args, _)
|
||||
| DefiningTy::Coroutine(_, args)
|
||||
| DefiningTy::InlineConst(_, args) => {
|
||||
// In the case of closures, we rely on the fact that
|
||||
// the first N elements in the ClosureArgs are
|
||||
|
|
@ -685,11 +682,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
DefiningTy::Coroutine(def_id, args, movability) => {
|
||||
DefiningTy::Coroutine(def_id, args) => {
|
||||
assert_eq!(self.mir_def.to_def_id(), def_id);
|
||||
let resume_ty = args.as_coroutine().resume_ty();
|
||||
let output = args.as_coroutine().return_ty();
|
||||
let coroutine_ty = Ty::new_coroutine(tcx, def_id, args, movability);
|
||||
let coroutine_ty = Ty::new_coroutine(tcx, def_id, args);
|
||||
let inputs_and_output =
|
||||
self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]);
|
||||
ty::Binder::dummy(inputs_and_output)
|
||||
|
|
|
|||
|
|
@ -175,14 +175,10 @@ jobs:
|
|||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo bin dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-bin-dir-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Install hyperfine
|
||||
run: cargo install hyperfine || true
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y hyperfine
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.sh prepare
|
||||
|
|
@ -257,14 +253,14 @@ jobs:
|
|||
|
||||
- name: Upload prebuilt cg_clif
|
||||
if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
|
||||
path: cg_clif.tar.xz
|
||||
|
||||
- name: Upload prebuilt cg_clif (cross compile)
|
||||
if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
|
||||
path: cg_clif.tar.xz
|
||||
|
|
@ -283,7 +279,7 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Download all built artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts/
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ jobs:
|
|||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Install ripgrep
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y ripgrep
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.sh prepare
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2023-12-24"
|
||||
channel = "nightly-2023-12-31"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
|
||||
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as
|
||||
# the LLVM backend isn't compiled in here.
|
||||
export CG_CLIF_FORCE_GNU_AS=1
|
||||
|
||||
|
|
@ -11,20 +11,19 @@ export CG_CLIF_FORCE_GNU_AS=1
|
|||
CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
|
||||
|
||||
echo "[SETUP] Rust fork"
|
||||
git clone https://github.com/rust-lang/rust.git --filter=tree:0 || true
|
||||
git clone --quiet https://github.com/rust-lang/rust.git --filter=tree:0 || true
|
||||
pushd rust
|
||||
git fetch
|
||||
git checkout -- .
|
||||
git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
|
||||
git checkout --no-progress -- .
|
||||
git checkout --no-progress "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
|
||||
|
||||
git submodule update --quiet --init src/tools/cargo library/backtrace library/stdarch
|
||||
|
||||
git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \
|
||||
am ../patches/*-stdlib-*.patch
|
||||
|
||||
cat > config.toml <<EOF
|
||||
change-id = 115898
|
||||
|
||||
[llvm]
|
||||
ninja = false
|
||||
change-id = 999999
|
||||
|
||||
[build]
|
||||
rustc = "$(pwd)/../dist/bin/rustc-clif"
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ fn dep_symbol_lookup_fn(
|
|||
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
|
||||
Linkage::Static => {
|
||||
let name = crate_info.crate_name[&cnum];
|
||||
let mut err = sess.struct_err(format!("Can't load static lib {}", name));
|
||||
let mut err = sess.dcx().struct_err(format!("Can't load static lib {}", name));
|
||||
err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
|
||||
err.emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@ pub(crate) fn compile_global_asm(
|
|||
}
|
||||
} else {
|
||||
let mut child = Command::new(std::env::current_exe().unwrap())
|
||||
// Avoid a warning about the jobserver fd not being passed
|
||||
.env_remove("CARGO_MAKEFLAGS")
|
||||
.arg("--target")
|
||||
.arg(&config.target)
|
||||
.arg("--crate-type")
|
||||
|
|
|
|||
|
|
@ -974,8 +974,8 @@ pub(crate) fn assert_assignable<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
(&ty::Coroutine(def_id_a, args_a, mov_a), &ty::Coroutine(def_id_b, args_b, mov_b))
|
||||
if def_id_a == def_id_b && mov_a == mov_b =>
|
||||
(&ty::Coroutine(def_id_a, args_a), &ty::Coroutine(def_id_b, args_b))
|
||||
if def_id_a == def_id_b =>
|
||||
{
|
||||
let mut types_a = args_a.types();
|
||||
let mut types_b = args_b.types();
|
||||
|
|
|
|||
|
|
@ -634,6 +634,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
|||
}
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
|
|
@ -704,7 +705,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
},
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::S390x(
|
||||
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr
|
||||
) => cx.type_i32(),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1296,7 +1296,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
// Atomic Operations
|
||||
fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
|
||||
fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> (RValue<'gcc>, RValue<'gcc>) {
|
||||
let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
|
||||
self.llbb().add_assignment(None, expected, cmp);
|
||||
// NOTE: gcc doesn't support a failure memory model that is stronger than the success
|
||||
|
|
@ -1310,20 +1310,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
};
|
||||
let success = self.compare_exchange(dst, expected, src, order, failure_order, weak);
|
||||
|
||||
let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false);
|
||||
let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result");
|
||||
let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align.
|
||||
// NOTE: since success contains the call to the intrinsic, it must be added to the basic block before
|
||||
// expected so that we store expected after the call.
|
||||
let success_var = self.current_func().new_local(None, self.bool_type, "success");
|
||||
self.llbb().add_assignment(None, success_var, success);
|
||||
|
||||
let value_type = result.to_rvalue().get_type();
|
||||
if let Some(struct_type) = value_type.is_struct() {
|
||||
self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align);
|
||||
// NOTE: since success contains the call to the intrinsic, it must be stored before
|
||||
// expected so that we store expected after the call.
|
||||
self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align);
|
||||
}
|
||||
// TODO(antoyo): handle when value is not a struct.
|
||||
|
||||
result.to_rvalue()
|
||||
(expected.to_rvalue(), success_var.to_rvalue())
|
||||
}
|
||||
|
||||
fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
|
|||
write!(&mut name, "::{}", def.variant(index).name).unwrap();
|
||||
}
|
||||
}
|
||||
if let (&ty::Coroutine(_, _, _), &Variants::Single { index }) =
|
||||
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
|
||||
(layout.ty.kind(), &layout.variants)
|
||||
{
|
||||
write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ test = false
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "1.0"
|
||||
bitflags = "2.4.1"
|
||||
itertools = "0.11"
|
||||
libc = "0.2"
|
||||
measureme = "10.0.0"
|
||||
|
|
|
|||
|
|
@ -690,6 +690,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
|
|||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
|
||||
|
|
@ -867,7 +868,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
|
|||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(),
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(),
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::S390x(
|
||||
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
|
||||
) => cx.type_i32(),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
|
|||
// `+multivalue` feature because the purpose of the wasm abi is to match
|
||||
// the WebAssembly specification, which has this feature. This won't be
|
||||
// needed when LLVM enables this `multivalue` feature by default.
|
||||
if !cx.tcx.is_closure(instance.def_id()) {
|
||||
if !cx.tcx.is_closure_or_coroutine(instance.def_id()) {
|
||||
let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi();
|
||||
if abi == Abi::Wasm {
|
||||
function_features.push("+multivalue".to_string());
|
||||
|
|
|
|||
|
|
@ -1072,7 +1072,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
order: rustc_codegen_ssa::common::AtomicOrdering,
|
||||
failure_order: rustc_codegen_ssa::common::AtomicOrdering,
|
||||
weak: bool,
|
||||
) -> &'ll Value {
|
||||
) -> (&'ll Value, &'ll Value) {
|
||||
let weak = if weak { llvm::True } else { llvm::False };
|
||||
unsafe {
|
||||
let value = llvm::LLVMBuildAtomicCmpXchg(
|
||||
|
|
@ -1085,7 +1085,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
llvm::False, // SingleThreaded
|
||||
);
|
||||
llvm::LLVMSetWeak(value, weak);
|
||||
value
|
||||
let val = self.extract_value(value, 0);
|
||||
let success = self.extract_value(value, 1);
|
||||
(val, success)
|
||||
}
|
||||
}
|
||||
fn atomic_rmw(
|
||||
|
|
|
|||
|
|
@ -58,11 +58,6 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
return;
|
||||
}
|
||||
|
||||
// The entries of the map are only used to get a list of all files with
|
||||
// coverage info. In the end the list of files is passed into
|
||||
// `GlobalFileTable::new()` which internally do `.sort_unstable_by()`, so
|
||||
// the iteration order here does not matter.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
let function_coverage_entries = function_coverage_map
|
||||
.into_iter()
|
||||
.map(|(instance, function_coverage)| (instance, function_coverage.into_finished()))
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::{
|
|||
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
|
||||
StaticMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_llvm::RustString;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::coverage::CoverageKind;
|
||||
|
|
@ -30,7 +30,7 @@ const VAR_ALIGN_BYTES: usize = 8;
|
|||
pub struct CrateCoverageContext<'ll, 'tcx> {
|
||||
/// Coverage data for each instrumented function identified by DefId.
|
||||
pub(crate) function_coverage_map:
|
||||
RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
|
||||
RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
}
|
||||
|
||||
|
|
@ -44,8 +44,8 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
|||
|
||||
pub fn take_function_coverage_map(
|
||||
&self,
|
||||
) -> FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> {
|
||||
self.function_coverage_map.replace(FxHashMap::default())
|
||||
) -> FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> {
|
||||
self.function_coverage_map.replace(FxIndexMap::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1066,7 +1066,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
|
|||
closure_or_coroutine_di_node: &'ll DIType,
|
||||
) -> SmallVec<&'ll DIType> {
|
||||
let (&def_id, up_var_tys) = match closure_or_coroutine_ty.kind() {
|
||||
ty::Coroutine(def_id, args, _) => (def_id, args.as_coroutine().prefix_tys()),
|
||||
ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().prefix_tys()),
|
||||
ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()),
|
||||
_ => {
|
||||
bug!(
|
||||
|
|
|
|||
|
|
@ -679,7 +679,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
|
|||
};
|
||||
|
||||
let (coroutine_def_id, coroutine_args) = match coroutine_type_and_layout.ty.kind() {
|
||||
&ty::Coroutine(def_id, args, _) => (def_id, args.as_coroutine()),
|
||||
&ty::Coroutine(def_id, args) => (def_id, args.as_coroutine()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ pub fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
let variant_layout = coroutine_type_and_layout.for_variant(cx, variant_index);
|
||||
|
||||
let coroutine_args = match coroutine_type_and_layout.ty.kind() {
|
||||
ty::Coroutine(_, args, _) => args.as_coroutine(),
|
||||
ty::Coroutine(_, args) => args.as_coroutine(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
|
|||
unique_type_id: UniqueTypeId<'tcx>,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
let coroutine_type = unique_type_id.expect_ty();
|
||||
let &ty::Coroutine(coroutine_def_id, _, _) = coroutine_type.kind() else {
|
||||
let &ty::Coroutine(coroutine_def_id, _) = coroutine_type.kind() else {
|
||||
bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ pub mod debuginfo {
|
|||
// These values **must** match with LLVMRustDIFlags!!
|
||||
bitflags! {
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct DIFlags: u32 {
|
||||
const FlagZero = 0;
|
||||
const FlagPrivate = 1;
|
||||
|
|
@ -751,7 +751,7 @@ pub mod debuginfo {
|
|||
// These values **must** match with LLVMRustDISPFlags!!
|
||||
bitflags! {
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct DISPFlags: u32 {
|
||||
const SPFlagZero = 0;
|
||||
const SPFlagVirtual = 1;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ fn uncached_llvm_type<'a, 'tcx>(
|
|||
write!(&mut name, "::{}", def.variant(index).name).unwrap();
|
||||
}
|
||||
}
|
||||
if let (&ty::Coroutine(_, _, _), &Variants::Single { index }) =
|
||||
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
|
||||
(layout.ty.kind(), &layout.variants)
|
||||
{
|
||||
write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
ar_archive_writer = "0.1.5"
|
||||
bitflags = "1.2.1"
|
||||
bitflags = "2.4.1"
|
||||
cc = "1.0.69"
|
||||
itertools = "0.11"
|
||||
jobserver = "0.1.27"
|
||||
|
|
|
|||
|
|
@ -1186,15 +1186,22 @@ mod win {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
|
||||
// On macOS the runtimes are distributed as dylibs which should be linked to
|
||||
// both executables and dynamic shared objects. Everywhere else the runtimes
|
||||
// are currently distributed as static libraries which should be linked to
|
||||
// executables only.
|
||||
fn add_sanitizer_libraries(
|
||||
sess: &Session,
|
||||
flavor: LinkerFlavor,
|
||||
crate_type: CrateType,
|
||||
linker: &mut dyn Linker,
|
||||
) {
|
||||
// On macOS and Windows using MSVC the runtimes are distributed as dylibs
|
||||
// which should be linked to both executables and dynamic libraries.
|
||||
// Everywhere else the runtimes are currently distributed as static
|
||||
// libraries which should be linked to executables only.
|
||||
let needs_runtime = !sess.target.is_like_android
|
||||
&& match crate_type {
|
||||
CrateType::Executable => true,
|
||||
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
|
||||
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
|
||||
sess.target.is_like_osx || sess.target.is_like_msvc
|
||||
}
|
||||
CrateType::Rlib | CrateType::Staticlib => false,
|
||||
};
|
||||
|
||||
|
|
@ -1204,26 +1211,31 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
|
|||
|
||||
let sanitizer = sess.opts.unstable_opts.sanitizer;
|
||||
if sanitizer.contains(SanitizerSet::ADDRESS) {
|
||||
link_sanitizer_runtime(sess, linker, "asan");
|
||||
link_sanitizer_runtime(sess, flavor, linker, "asan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::LEAK) {
|
||||
link_sanitizer_runtime(sess, linker, "lsan");
|
||||
link_sanitizer_runtime(sess, flavor, linker, "lsan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::MEMORY) {
|
||||
link_sanitizer_runtime(sess, linker, "msan");
|
||||
link_sanitizer_runtime(sess, flavor, linker, "msan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::THREAD) {
|
||||
link_sanitizer_runtime(sess, linker, "tsan");
|
||||
link_sanitizer_runtime(sess, flavor, linker, "tsan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::HWADDRESS) {
|
||||
link_sanitizer_runtime(sess, linker, "hwasan");
|
||||
link_sanitizer_runtime(sess, flavor, linker, "hwasan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::SAFESTACK) {
|
||||
link_sanitizer_runtime(sess, linker, "safestack");
|
||||
link_sanitizer_runtime(sess, flavor, linker, "safestack");
|
||||
}
|
||||
}
|
||||
|
||||
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
|
||||
fn link_sanitizer_runtime(
|
||||
sess: &Session,
|
||||
flavor: LinkerFlavor,
|
||||
linker: &mut dyn Linker,
|
||||
name: &str,
|
||||
) {
|
||||
fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
|
||||
let session_tlib =
|
||||
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
|
||||
|
|
@ -1254,6 +1266,10 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
|
|||
let rpath = path.to_str().expect("non-utf8 component in path");
|
||||
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
|
||||
linker.link_dylib(&filename, false, true);
|
||||
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
|
||||
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
|
||||
// compatible ASAN library.
|
||||
linker.arg("/INFERASANLIBS");
|
||||
} else {
|
||||
let filename = format!("librustc{channel}_rt.{name}.a");
|
||||
let path = find_sanitizer_runtime(sess, &filename).join(&filename);
|
||||
|
|
@ -2076,7 +2092,7 @@ fn linker_with_args<'a>(
|
|||
);
|
||||
|
||||
// Sanitizer libraries.
|
||||
add_sanitizer_libraries(sess, crate_type, cmd);
|
||||
add_sanitizer_libraries(sess, flavor, crate_type, cmd);
|
||||
|
||||
// Object code from the current crate.
|
||||
// Take careful note of the ordering of the arguments we pass to the linker
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
||||
sym::track_caller => {
|
||||
let is_closure = tcx.is_closure(did.to_def_id());
|
||||
let is_closure = tcx.is_closure_or_coroutine(did.to_def_id());
|
||||
|
||||
if !is_closure
|
||||
&& let Some(fn_sig) = fn_sig()
|
||||
|
|
@ -277,7 +277,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
sym::target_feature => {
|
||||
if !tcx.is_closure(did.to_def_id())
|
||||
if !tcx.is_closure_or_coroutine(did.to_def_id())
|
||||
&& let Some(fn_sig) = fn_sig()
|
||||
&& fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal
|
||||
{
|
||||
|
|
@ -531,7 +531,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// would result in this closure being compiled without the inherited target features, but this
|
||||
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
|
||||
if tcx.features().target_feature_11
|
||||
&& tcx.is_closure(did.to_def_id())
|
||||
&& tcx.is_closure_or_coroutine(did.to_def_id())
|
||||
&& codegen_fn_attrs.inline != InlineAttr::Always
|
||||
{
|
||||
let owner_id = tcx.parent(did.to_def_id());
|
||||
|
|
|
|||
|
|
@ -585,7 +585,7 @@ fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
|
|||
Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Fn)) => {
|
||||
"async_gen_fn"
|
||||
}
|
||||
Some(CoroutineKind::Coroutine) => "coroutine",
|
||||
Some(CoroutineKind::Coroutine(_)) => "coroutine",
|
||||
None => "closure",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ pub enum ModuleKind {
|
|||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct MemFlags: u8 {
|
||||
const VOLATILE = 1 << 0;
|
||||
const NONTEMPORAL = 1 << 1;
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
cmp = bx.ptrtoint(cmp, bx.type_isize());
|
||||
src = bx.ptrtoint(src, bx.type_isize());
|
||||
}
|
||||
let pair = bx.atomic_cmpxchg(
|
||||
let (val, success) = bx.atomic_cmpxchg(
|
||||
dst,
|
||||
cmp,
|
||||
src,
|
||||
|
|
@ -343,8 +343,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
parse_ordering(bx, failure),
|
||||
weak,
|
||||
);
|
||||
let val = bx.extract_value(pair, 0);
|
||||
let success = bx.extract_value(pair, 1);
|
||||
let val = bx.from_immediate(val);
|
||||
let success = bx.from_immediate(success);
|
||||
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
order: AtomicOrdering,
|
||||
failure_order: AtomicOrdering,
|
||||
weak: bool,
|
||||
) -> Self::Value;
|
||||
) -> (Self::Value, Self::Value);
|
||||
fn atomic_rmw(
|
||||
&mut self,
|
||||
op: AtomicRmwBinOp,
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
ty::Adt(adt, _) => {
|
||||
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
|
||||
}
|
||||
ty::Coroutine(def_id, args, _) => {
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let args = args.as_coroutine();
|
||||
args.discriminants(def_id, *self.tcx).find(|(_, var)| var.val == discr_bits)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
|||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::Coroutine(_, _, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// Now we know we are projecting to a field, so figure out which one.
|
||||
match layout.ty.kind() {
|
||||
// coroutines and closures.
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _, _) => {
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
|
||||
let mut name = None;
|
||||
// FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
|
||||
// https://github.com/rust-lang/project-rfc-2229/issues/46
|
||||
|
|
|
|||
|
|
@ -938,8 +938,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
||||
|
||||
TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => {
|
||||
self.check_op(ops::Coroutine(hir::CoroutineKind::Coroutine))
|
||||
TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine(
|
||||
self.tcx
|
||||
.coroutine_kind(self.body.source.def_id())
|
||||
.expect("Only expected to have a yield in a coroutine"),
|
||||
)),
|
||||
|
||||
TerminatorKind::CoroutineDrop => {
|
||||
span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
"We should not encounter TerminatorKind::CoroutineDrop after coroutine transform"
|
||||
);
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
|
|||
|
||||
pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
|
||||
let did = self.def_id().to_def_id();
|
||||
if self.tcx.is_closure(did) {
|
||||
if self.tcx.is_closure_or_coroutine(did) {
|
||||
let ty = self.tcx.type_of(did).instantiate_identity();
|
||||
let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") };
|
||||
args.as_closure().sig()
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
};
|
||||
check_equal(self, location, f_ty);
|
||||
}
|
||||
&ty::Coroutine(def_id, args, _) => {
|
||||
&ty::Coroutine(def_id, args) => {
|
||||
let f_ty = if let Some(var) = parent_ty.variant_index {
|
||||
let gen_body = if def_id == self.body.source.def_id() {
|
||||
self.body
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
|
|||
| ty::FnDef(def_id, args)
|
||||
| ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
|
||||
| ty::Closure(def_id, args)
|
||||
| ty::Coroutine(def_id, args, _) => self.print_def_path(def_id, args),
|
||||
| ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
|
||||
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
|
||||
|
||||
ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
arrayvec = { version = "0.7", default-features = false }
|
||||
bitflags = "1.2.1"
|
||||
bitflags = "2.4.1"
|
||||
elsa = "=1.7.1"
|
||||
ena = "0.14.2"
|
||||
indexmap = { version = "2.0.0" }
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl Hash64 {
|
|||
pub const ZERO: Hash64 = Hash64 { inner: 0 };
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn new(n: u64) -> Self {
|
||||
pub fn new(n: u64) -> Self {
|
||||
Self { inner: n }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,3 +150,14 @@ pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl
|
|||
// See comments in src/librustc_middle/lib.rs
|
||||
#[doc(hidden)]
|
||||
pub fn __noop_fix_for_27438() {}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! external_bitflags_debug {
|
||||
($Name:ident) => {
|
||||
impl ::std::fmt::Debug for $Name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::bitflags::parser::to_writer(self, f)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ use parking_lot::RwLock;
|
|||
use smallvec::SmallVec;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy)]
|
||||
struct EventFilter: u16 {
|
||||
const GENERIC_ACTIVITIES = 1 << 0;
|
||||
const QUERY_PROVIDERS = 1 << 1;
|
||||
|
|
@ -114,14 +115,14 @@ bitflags::bitflags! {
|
|||
const INCR_RESULT_HASHING = 1 << 8;
|
||||
const ARTIFACT_SIZES = 1 << 9;
|
||||
|
||||
const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
|
||||
Self::QUERY_PROVIDERS.bits |
|
||||
Self::QUERY_BLOCKED.bits |
|
||||
Self::INCR_CACHE_LOADS.bits |
|
||||
Self::INCR_RESULT_HASHING.bits |
|
||||
Self::ARTIFACT_SIZES.bits;
|
||||
const DEFAULT = Self::GENERIC_ACTIVITIES.bits() |
|
||||
Self::QUERY_PROVIDERS.bits() |
|
||||
Self::QUERY_BLOCKED.bits() |
|
||||
Self::INCR_CACHE_LOADS.bits() |
|
||||
Self::INCR_RESULT_HASHING.bits() |
|
||||
Self::ARTIFACT_SIZES.bits();
|
||||
|
||||
const ARGS = Self::QUERY_KEYS.bits | Self::FUNCTION_ARGS.bits;
|
||||
const ARGS = Self::QUERY_KEYS.bits() | Self::FUNCTION_ARGS.bits();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#![feature(lazy_cell)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(panic_update_hook)]
|
||||
#![feature(result_flattening)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
|
@ -1249,8 +1250,7 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuarantee
|
|||
/// Variant of `catch_fatal_errors` for the `interface::Result` return type
|
||||
/// that also computes the exit code.
|
||||
pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
|
||||
let result = catch_fatal_errors(f).and_then(|result| result);
|
||||
match result {
|
||||
match catch_fatal_errors(f).flatten() {
|
||||
Ok(()) => EXIT_SUCCESS,
|
||||
Err(_) => EXIT_FAILURE,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ impl<'a> pprust_ast::PpAnn for AstHygieneAnn<'a> {
|
|||
}
|
||||
pprust_ast::AnnNode::Crate(_) => {
|
||||
s.s.hardbreak();
|
||||
let verbose = self.sess.verbose();
|
||||
let verbose = self.sess.verbose_internals();
|
||||
s.synth_comment(rustc_span::hygiene::debug_hygiene_data(verbose));
|
||||
s.s.hardbreak_if_not_bol();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ Erroneous code example:
|
|||
trait Foo {
|
||||
const fn bar() -> u32; // error!
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
const fn bar() -> u32 { 0 } // error!
|
||||
}
|
||||
```
|
||||
|
||||
Trait methods cannot be declared `const` by design. For more information, see
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ Example of erroneous code:
|
|||
|
||||
#[allow(non_snake_case)]
|
||||
fn main() {
|
||||
let MyNumber = 2; // error: allow(non_snake_case) overruled by outer
|
||||
// forbid(non_snake_case)
|
||||
// error: allow(non_snake_case) incompatible with previous forbid
|
||||
let MyNumber = 2;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan,
|
||||
SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
|
||||
use rustc_error_messages::FluentValue;
|
||||
use rustc_lint_defs::{Applicability, LintExpectationId};
|
||||
|
|
@ -259,7 +259,7 @@ impl Diagnostic {
|
|||
|
||||
pub(crate) fn update_unstable_expectation_id(
|
||||
&mut self,
|
||||
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
|
||||
unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
|
||||
) {
|
||||
if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) =
|
||||
&mut self.level
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub use termcolor::{Color, ColorSpec, WriteColor};
|
|||
use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline};
|
||||
use emitter::{is_case_difference, DynEmitter, Emitter, EmitterWriter};
|
||||
use registry::Registry;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
|
||||
use rustc_data_structures::sync::{Lock, Lrc};
|
||||
use rustc_data_structures::AtomicRef;
|
||||
|
|
@ -1318,7 +1318,7 @@ impl DiagCtxt {
|
|||
|
||||
pub fn update_unstable_expectation_id(
|
||||
&self,
|
||||
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
|
||||
unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
|
||||
) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let diags = std::mem::take(&mut inner.unstable_expect_diagnostics);
|
||||
|
|
@ -1698,7 +1698,7 @@ pub enum Level {
|
|||
/// internal overflows, some file operation errors.
|
||||
///
|
||||
/// Its `EmissionGuarantee` is `FatalAbort`, except in the non-aborting "almost fatal" case
|
||||
/// that is occasionaly used, where it is `FatalError`.
|
||||
/// that is occasionally used, where it is `FatalError`.
|
||||
Fatal,
|
||||
|
||||
/// An error in the code being compiled, which prevents compilation from finishing. This is the
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::mbe::transcribe::transcribe;
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, TransparencyError};
|
||||
|
|
@ -213,7 +213,7 @@ fn expand_macro<'cx>(
|
|||
let arm_span = rhses[i].span();
|
||||
|
||||
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||
let mut tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) {
|
||||
let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) {
|
||||
Ok(tts) => tts,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
|
|
@ -221,37 +221,6 @@ fn expand_macro<'cx>(
|
|||
}
|
||||
};
|
||||
|
||||
// Replace all the tokens for the corresponding positions in the macro, to maintain
|
||||
// proper positions in error reporting, while maintaining the macro_backtrace.
|
||||
if tts.len() == rhs.tts.len() {
|
||||
tts = tts.map_enumerated_owned(|i, mut tt| {
|
||||
let rhs_tt = &rhs.tts[i];
|
||||
let ctxt = tt.span().ctxt();
|
||||
match (&mut tt, rhs_tt) {
|
||||
// preserve the delim spans if able
|
||||
(
|
||||
TokenTree::Delimited(target_sp, ..),
|
||||
mbe::TokenTree::Delimited(source_sp, ..),
|
||||
) => {
|
||||
target_sp.open = source_sp.open.with_ctxt(ctxt);
|
||||
target_sp.close = source_sp.close.with_ctxt(ctxt);
|
||||
}
|
||||
(
|
||||
TokenTree::Delimited(target_sp, ..),
|
||||
mbe::TokenTree::MetaVar(source_sp, ..),
|
||||
) => {
|
||||
target_sp.open = source_sp.with_ctxt(ctxt);
|
||||
target_sp.close = source_sp.with_ctxt(ctxt).shrink_to_hi();
|
||||
}
|
||||
_ => {
|
||||
let sp = rhs_tt.span().with_ctxt(ctxt);
|
||||
tt.set_span(sp);
|
||||
}
|
||||
}
|
||||
tt
|
||||
});
|
||||
}
|
||||
|
||||
if cx.trace_macros() {
|
||||
let msg = format!("to `{}`", pprust::tts_to_string(&tts));
|
||||
trace_macros_note(&mut cx.expansions, sp, msg);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::errors::{
|
|||
NoSyntaxVarsExprRepeat, VarStillRepeating,
|
||||
};
|
||||
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch};
|
||||
use crate::mbe::{self, MetaVarExpr};
|
||||
use crate::mbe::{self, KleeneOp, MetaVarExpr};
|
||||
use rustc_ast::mut_visit::{self, MutVisitor};
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
|
|
@ -42,6 +42,7 @@ enum Frame<'a> {
|
|||
tts: &'a [mbe::TokenTree],
|
||||
idx: usize,
|
||||
sep: Option<Token>,
|
||||
kleene_op: KleeneOp,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +208,7 @@ pub(super) fn transcribe<'a>(
|
|||
|
||||
// Is the repetition empty?
|
||||
if len == 0 {
|
||||
if seq.kleene.op == mbe::KleeneOp::OneOrMore {
|
||||
if seq.kleene.op == KleeneOp::OneOrMore {
|
||||
// FIXME: this really ought to be caught at macro definition
|
||||
// time... It happens when the Kleene operator in the matcher and
|
||||
// the body for the same meta-variable do not match.
|
||||
|
|
@ -227,6 +228,7 @@ pub(super) fn transcribe<'a>(
|
|||
idx: 0,
|
||||
sep: seq.separator.clone(),
|
||||
tts: &delimited.tts,
|
||||
kleene_op: seq.kleene.op,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -243,7 +245,7 @@ pub(super) fn transcribe<'a>(
|
|||
MatchedTokenTree(tt) => {
|
||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||
// without wrapping them into groups.
|
||||
result.push(tt.clone());
|
||||
result.push(maybe_use_metavar_location(cx, &stack, sp, tt));
|
||||
}
|
||||
MatchedNonterminal(nt) => {
|
||||
// Other variables are emitted into the output stream as groups with
|
||||
|
|
@ -308,6 +310,62 @@ pub(super) fn transcribe<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Usually metavariables `$var` produce interpolated tokens, which have an additional place for
|
||||
/// keeping both the original span and the metavariable span. For `tt` metavariables that's not the
|
||||
/// case however, and there's no place for keeping a second span. So we try to give the single
|
||||
/// produced span a location that would be most useful in practice (the hygiene part of the span
|
||||
/// must not be changed).
|
||||
///
|
||||
/// Different locations are useful for different purposes:
|
||||
/// - The original location is useful when we need to report a diagnostic for the original token in
|
||||
/// isolation, without combining it with any surrounding tokens. This case occurs, but it is not
|
||||
/// very common in practice.
|
||||
/// - The metavariable location is useful when we need to somehow combine the token span with spans
|
||||
/// of its surrounding tokens. This is the most common way to use token spans.
|
||||
///
|
||||
/// So this function replaces the original location with the metavariable location in all cases
|
||||
/// except these two:
|
||||
/// - The metavariable is an element of undelimited sequence `$($tt)*`.
|
||||
/// These are typically used for passing larger amounts of code, and tokens in that code usually
|
||||
/// combine with each other and not with tokens outside of the sequence.
|
||||
/// - The metavariable span comes from a different crate, then we prefer the more local span.
|
||||
///
|
||||
/// FIXME: Find a way to keep both original and metavariable spans for all tokens without
|
||||
/// regressing compilation time too much. Several experiments for adding such spans were made in
|
||||
/// the past (PR #95580, #118517, #118671) and all showed some regressions.
|
||||
fn maybe_use_metavar_location(
|
||||
cx: &ExtCtxt<'_>,
|
||||
stack: &[Frame<'_>],
|
||||
metavar_span: Span,
|
||||
orig_tt: &TokenTree,
|
||||
) -> TokenTree {
|
||||
let undelimited_seq = matches!(
|
||||
stack.last(),
|
||||
Some(Frame::Sequence {
|
||||
tts: [_],
|
||||
sep: None,
|
||||
kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
|
||||
..
|
||||
})
|
||||
);
|
||||
if undelimited_seq || cx.source_map().is_imported(metavar_span) {
|
||||
return orig_tt.clone();
|
||||
}
|
||||
|
||||
match orig_tt {
|
||||
TokenTree::Token(Token { kind, span }, spacing) => {
|
||||
let span = metavar_span.with_ctxt(span.ctxt());
|
||||
TokenTree::Token(Token { kind: kind.clone(), span }, *spacing)
|
||||
}
|
||||
TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
|
||||
let open = metavar_span.shrink_to_lo().with_ctxt(dspan.open.ctxt());
|
||||
let close = metavar_span.shrink_to_hi().with_ctxt(dspan.close.ctxt());
|
||||
let dspan = DelimSpan::from_pair(open, close);
|
||||
TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lookup the meta-var named `ident` and return the matched token tree from the invocation using
|
||||
/// the set of matches `interpolations`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ const GATED_CFGS: &[GatedCfg] = &[
|
|||
(sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)),
|
||||
(sym::version, sym::cfg_version, cfg_fn!(cfg_version)),
|
||||
(sym::relocation_model, sym::cfg_relocation_model, cfg_fn!(cfg_relocation_model)),
|
||||
(sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)),
|
||||
(sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)),
|
||||
];
|
||||
|
||||
/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
|
||||
|
|
|
|||
|
|
@ -371,6 +371,8 @@ declare_features! (
|
|||
(unstable, cfg_relocation_model, "1.73.0", Some(114929)),
|
||||
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
|
||||
(unstable, cfg_sanitize, "1.41.0", Some(39699)),
|
||||
/// Allows `cfg(sanitizer_cfi_generalize_pointers)` and `cfg(sanitizer_cfi_normalize_integers)`.
|
||||
(unstable, cfg_sanitizer_cfi, "CURRENT_RUSTC_VERSION", Some(89653)),
|
||||
/// Allows `cfg(target_abi = "...")`.
|
||||
(unstable, cfg_target_abi, "1.55.0", Some(80970)),
|
||||
/// Allows `cfg(target(abi = "..."))`.
|
||||
|
|
@ -523,7 +525,7 @@ declare_features! (
|
|||
/// Allows the `#[must_not_suspend]` attribute.
|
||||
(unstable, must_not_suspend, "1.57.0", Some(83310)),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
(unstable, naked_functions, "1.9.0", Some(32408)),
|
||||
(unstable, naked_functions, "1.9.0", Some(90957)),
|
||||
/// Allows specifying the as-needed link modifier
|
||||
(unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)),
|
||||
/// Allow negative trait implementations.
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_span::def_id::{DefIndex, DefPathHash};
|
||||
use rustc_data_structures::stable_hasher::Hash64;
|
||||
use rustc_span::def_id::DefIndex;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Config;
|
||||
|
||||
impl odht::Config for Config {
|
||||
type Key = DefPathHash;
|
||||
// This hash-map is single-crate, so we only need to key by the local hash.
|
||||
type Key = Hash64;
|
||||
type Value = DefIndex;
|
||||
|
||||
type EncodedKey = [u8; 16];
|
||||
type EncodedKey = [u8; 8];
|
||||
type EncodedValue = [u8; 4];
|
||||
|
||||
type H = odht::UnHashFn;
|
||||
|
||||
#[inline]
|
||||
fn encode_key(k: &DefPathHash) -> [u8; 16] {
|
||||
k.0.to_le_bytes()
|
||||
fn encode_key(k: &Hash64) -> [u8; 8] {
|
||||
k.as_u64().to_le_bytes()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -24,8 +25,8 @@ impl odht::Config for Config {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_key(k: &[u8; 16]) -> DefPathHash {
|
||||
DefPathHash(Fingerprint::from_le_bytes(*k))
|
||||
fn decode_key(k: &[u8; 8]) -> Hash64 {
|
||||
Hash64::new(u64::from_le_bytes(*k))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -20,27 +20,42 @@ use std::hash::Hash;
|
|||
/// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
|
||||
/// stores the `DefIndex` of its parent.
|
||||
/// There is one `DefPathTable` for each crate.
|
||||
#[derive(Clone, Default, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct DefPathTable {
|
||||
stable_crate_id: StableCrateId,
|
||||
index_to_key: IndexVec<DefIndex, DefKey>,
|
||||
def_path_hashes: IndexVec<DefIndex, DefPathHash>,
|
||||
// We do only store the local hash, as all the definitions are from the current crate.
|
||||
def_path_hashes: IndexVec<DefIndex, Hash64>,
|
||||
def_path_hash_to_index: DefPathHashMap,
|
||||
}
|
||||
|
||||
impl DefPathTable {
|
||||
fn new(stable_crate_id: StableCrateId) -> DefPathTable {
|
||||
DefPathTable {
|
||||
stable_crate_id,
|
||||
index_to_key: Default::default(),
|
||||
def_path_hashes: Default::default(),
|
||||
def_path_hash_to_index: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
|
||||
// Assert that all DefPathHashes correctly contain the local crate's StableCrateId.
|
||||
debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id());
|
||||
let local_hash = def_path_hash.local_hash();
|
||||
|
||||
let index = {
|
||||
let index = DefIndex::from(self.index_to_key.len());
|
||||
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
|
||||
self.index_to_key.push(key);
|
||||
index
|
||||
};
|
||||
self.def_path_hashes.push(def_path_hash);
|
||||
self.def_path_hashes.push(local_hash);
|
||||
debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
|
||||
|
||||
// Check for hash collisions of DefPathHashes. These should be
|
||||
// exceedingly rare.
|
||||
if let Some(existing) = self.def_path_hash_to_index.insert(&def_path_hash, &index) {
|
||||
if let Some(existing) = self.def_path_hash_to_index.insert(&local_hash, &index) {
|
||||
let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx));
|
||||
let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx));
|
||||
|
||||
|
|
@ -58,13 +73,6 @@ impl DefPathTable {
|
|||
);
|
||||
}
|
||||
|
||||
// Assert that all DefPathHashes correctly contain the local crate's
|
||||
// StableCrateId
|
||||
#[cfg(debug_assertions)]
|
||||
if let Some(root) = self.def_path_hashes.get(CRATE_DEF_INDEX) {
|
||||
assert!(def_path_hash.stable_crate_id() == root.stable_crate_id());
|
||||
}
|
||||
|
||||
index
|
||||
}
|
||||
|
||||
|
|
@ -73,19 +81,19 @@ impl DefPathTable {
|
|||
self.index_to_key[index]
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
#[inline(always)]
|
||||
pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
|
||||
let hash = self.def_path_hashes[index];
|
||||
debug!("def_path_hash({:?}) = {:?}", index, hash);
|
||||
hash
|
||||
DefPathHash::new(self.stable_crate_id, hash)
|
||||
}
|
||||
|
||||
pub fn enumerated_keys_and_path_hashes(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + ExactSizeIterator + '_ {
|
||||
) -> impl Iterator<Item = (DefIndex, &DefKey, DefPathHash)> + ExactSizeIterator + '_ {
|
||||
self.index_to_key
|
||||
.iter_enumerated()
|
||||
.map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
|
||||
.map(move |(index, key)| (index, key, self.def_path_hash(index)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,9 +104,6 @@ impl DefPathTable {
|
|||
pub struct Definitions {
|
||||
table: DefPathTable,
|
||||
next_disambiguator: UnordMap<(LocalDefId, DefPathData), u32>,
|
||||
|
||||
/// The [StableCrateId] of the local crate.
|
||||
stable_crate_id: StableCrateId,
|
||||
}
|
||||
|
||||
/// A unique identifier that we can use to lookup a definition
|
||||
|
|
@ -329,11 +334,11 @@ impl Definitions {
|
|||
let def_path_hash = key.compute_stable_hash(parent_hash);
|
||||
|
||||
// Create the root definition.
|
||||
let mut table = DefPathTable::default();
|
||||
let mut table = DefPathTable::new(stable_crate_id);
|
||||
let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
|
||||
assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
|
||||
|
||||
Definitions { table, next_disambiguator: Default::default(), stable_crate_id }
|
||||
Definitions { table, next_disambiguator: Default::default() }
|
||||
}
|
||||
|
||||
/// Adds a definition with a parent definition.
|
||||
|
|
@ -375,10 +380,10 @@ impl Definitions {
|
|||
hash: DefPathHash,
|
||||
err: &mut dyn FnMut() -> !,
|
||||
) -> LocalDefId {
|
||||
debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
|
||||
debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id);
|
||||
self.table
|
||||
.def_path_hash_to_index
|
||||
.get(&hash)
|
||||
.get(&hash.local_hash())
|
||||
.map(|local_def_index| LocalDefId { local_def_index })
|
||||
.unwrap_or_else(|| err())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,9 +420,15 @@ pub enum GenericArgsParentheses {
|
|||
/// A modifier on a trait bound.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub enum TraitBoundModifier {
|
||||
/// `Type: Trait`
|
||||
None,
|
||||
/// `Type: !Trait`
|
||||
Negative,
|
||||
/// `Type: ?Trait`
|
||||
Maybe,
|
||||
/// `Type: const Trait`
|
||||
Const,
|
||||
/// `Type: ~const Trait`
|
||||
MaybeConst,
|
||||
}
|
||||
|
||||
|
|
@ -945,7 +951,18 @@ pub struct Closure<'hir> {
|
|||
pub fn_decl_span: Span,
|
||||
/// The span of the argument block `|...|`
|
||||
pub fn_arg_span: Option<Span>,
|
||||
pub movability: Option<Movability>,
|
||||
pub kind: ClosureKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum ClosureKind {
|
||||
/// This is a plain closure expression.
|
||||
Closure,
|
||||
/// This is a coroutine expression -- i.e. a closure expression in which
|
||||
/// we've found a `yield`. These can arise either from "plain" coroutine
|
||||
/// usage (e.g. `let x = || { yield (); }`) or from a desugared expression
|
||||
/// (e.g. `async` and `gen` blocks).
|
||||
Coroutine(CoroutineKind),
|
||||
}
|
||||
|
||||
/// A block of statements `{ .. }`, which may have a label (in this case the
|
||||
|
|
@ -1335,17 +1352,12 @@ pub struct BodyId {
|
|||
pub struct Body<'hir> {
|
||||
pub params: &'hir [Param<'hir>],
|
||||
pub value: &'hir Expr<'hir>,
|
||||
pub coroutine_kind: Option<CoroutineKind>,
|
||||
}
|
||||
|
||||
impl<'hir> Body<'hir> {
|
||||
pub fn id(&self) -> BodyId {
|
||||
BodyId { hir_id: self.value.hir_id }
|
||||
}
|
||||
|
||||
pub fn coroutine_kind(&self) -> Option<CoroutineKind> {
|
||||
self.coroutine_kind
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of source expression that caused this coroutine to be created.
|
||||
|
|
@ -1355,7 +1367,18 @@ pub enum CoroutineKind {
|
|||
Desugared(CoroutineDesugaring, CoroutineSource),
|
||||
|
||||
/// A coroutine literal created via a `yield` inside a closure.
|
||||
Coroutine,
|
||||
Coroutine(Movability),
|
||||
}
|
||||
|
||||
impl CoroutineKind {
|
||||
pub fn movability(self) -> Movability {
|
||||
match self {
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, _)
|
||||
| CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => Movability::Static,
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => Movability::Movable,
|
||||
CoroutineKind::Coroutine(mov) => mov,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CoroutineKind {
|
||||
|
|
@ -1365,7 +1388,7 @@ impl fmt::Display for CoroutineKind {
|
|||
d.fmt(f)?;
|
||||
k.fmt(f)
|
||||
}
|
||||
CoroutineKind::Coroutine => f.write_str("coroutine"),
|
||||
CoroutineKind::Coroutine(_) => f.write_str("coroutine"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2087,12 +2110,6 @@ pub enum YieldSource {
|
|||
Yield,
|
||||
}
|
||||
|
||||
impl YieldSource {
|
||||
pub fn is_await(&self) -> bool {
|
||||
matches!(self, YieldSource::Await { .. })
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for YieldSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
|
|
@ -3661,7 +3678,7 @@ mod size_asserts {
|
|||
use super::*;
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(Block<'_>, 48);
|
||||
static_assert_size!(Body<'_>, 32);
|
||||
static_assert_size!(Body<'_>, 24);
|
||||
static_assert_size!(Expr<'_>, 64);
|
||||
static_assert_size!(ExprKind<'_>, 48);
|
||||
static_assert_size!(FnDecl<'_>, 40);
|
||||
|
|
|
|||
|
|
@ -757,7 +757,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
capture_clause: _,
|
||||
fn_decl_span: _,
|
||||
fn_arg_span: _,
|
||||
movability: _,
|
||||
kind: _,
|
||||
constness: _,
|
||||
}) => {
|
||||
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s
|
|||
hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found
|
||||
|
||||
hir_analysis_const_bound_for_non_const_trait =
|
||||
~const can only be applied to `#[const_trait]` traits
|
||||
`{$modifier}` can only be applied to `#[const_trait]` traits
|
||||
|
||||
hir_analysis_const_impl_for_non_const_trait =
|
||||
const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
match ast_bound {
|
||||
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
|
||||
let (constness, polarity) = match modifier {
|
||||
hir::TraitBoundModifier::Const => {
|
||||
(ty::BoundConstness::Const, ty::ImplPolarity::Positive)
|
||||
}
|
||||
hir::TraitBoundModifier::MaybeConst => {
|
||||
(ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -560,11 +560,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
inferred_params: vec![],
|
||||
infer_args,
|
||||
};
|
||||
if let ty::BoundConstness::ConstIfConst = constness
|
||||
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
|
||||
&& generics.has_self
|
||||
&& !tcx.has_attr(def_id, sym::const_trait)
|
||||
{
|
||||
let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span });
|
||||
let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
|
||||
span,
|
||||
modifier: constness.as_str(),
|
||||
});
|
||||
arg_count.correct =
|
||||
Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_attr as attr;
|
|||
use rustc_errors::{ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::def_id::LocalModDefId;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::Node;
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
|
||||
|
|
@ -198,8 +198,8 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
|
||||
/// projections that would result in "inheriting lifetimes".
|
||||
fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
||||
let item = tcx.hir().item(id);
|
||||
fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let item = tcx.hir().expect_item(def_id);
|
||||
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
|
||||
tcx.dcx().span_delayed_bug(item.span, "expected opaque item");
|
||||
return;
|
||||
|
|
@ -440,40 +440,31 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
||||
debug!(
|
||||
"check_item_type(it.def_id={:?}, it.name={})",
|
||||
id.owner_id,
|
||||
tcx.def_path_str(id.owner_id)
|
||||
);
|
||||
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let _indenter = indenter();
|
||||
match tcx.def_kind(id.owner_id) {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Static(..) => {
|
||||
tcx.ensure().typeck(id.owner_id.def_id);
|
||||
maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
|
||||
check_static_inhabited(tcx, id.owner_id.def_id);
|
||||
check_static_linkage(tcx, id.owner_id.def_id);
|
||||
tcx.ensure().typeck(def_id);
|
||||
maybe_check_static_with_link_section(tcx, def_id);
|
||||
check_static_inhabited(tcx, def_id);
|
||||
check_static_linkage(tcx, def_id);
|
||||
}
|
||||
DefKind::Const => {
|
||||
tcx.ensure().typeck(id.owner_id.def_id);
|
||||
tcx.ensure().typeck(def_id);
|
||||
}
|
||||
DefKind::Enum => {
|
||||
check_enum(tcx, id.owner_id.def_id);
|
||||
check_enum(tcx, def_id);
|
||||
}
|
||||
DefKind::Fn => {} // entirely within check_item_body
|
||||
DefKind::Impl { of_trait } => {
|
||||
if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(id.owner_id) {
|
||||
check_impl_items_against_trait(
|
||||
tcx,
|
||||
id.owner_id.def_id,
|
||||
impl_trait_ref.instantiate_identity(),
|
||||
);
|
||||
check_on_unimplemented(tcx, id);
|
||||
if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(def_id) {
|
||||
check_impl_items_against_trait(tcx, def_id, impl_trait_ref.instantiate_identity());
|
||||
check_on_unimplemented(tcx, def_id);
|
||||
}
|
||||
}
|
||||
DefKind::Trait => {
|
||||
let assoc_items = tcx.associated_items(id.owner_id);
|
||||
check_on_unimplemented(tcx, id);
|
||||
let assoc_items = tcx.associated_items(def_id);
|
||||
check_on_unimplemented(tcx, def_id);
|
||||
|
||||
for &assoc_item in assoc_items.in_definition_order() {
|
||||
match assoc_item.kind {
|
||||
|
|
@ -482,12 +473,12 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
forbid_intrinsic_abi(tcx, assoc_item.ident(tcx).span, abi);
|
||||
}
|
||||
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
||||
let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id);
|
||||
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
||||
tcx,
|
||||
assoc_item,
|
||||
assoc_item,
|
||||
ty::TraitRef::new(tcx, id.owner_id.to_def_id(), trait_args),
|
||||
ty::TraitRef::new(tcx, def_id.to_def_id(), trait_args),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -495,13 +486,13 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
}
|
||||
}
|
||||
DefKind::Struct => {
|
||||
check_struct(tcx, id.owner_id.def_id);
|
||||
check_struct(tcx, def_id);
|
||||
}
|
||||
DefKind::Union => {
|
||||
check_union(tcx, id.owner_id.def_id);
|
||||
check_union(tcx, def_id);
|
||||
}
|
||||
DefKind::OpaqueTy => {
|
||||
let origin = tcx.opaque_type_origin(id.owner_id.def_id);
|
||||
let origin = tcx.opaque_type_origin(def_id);
|
||||
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
|
||||
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
|
||||
&& let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
|
||||
|
|
@ -509,16 +500,16 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
{
|
||||
// Skip opaques from RPIT in traits with no default body.
|
||||
} else {
|
||||
check_opaque(tcx, id);
|
||||
check_opaque(tcx, def_id);
|
||||
}
|
||||
}
|
||||
DefKind::TyAlias => {
|
||||
let pty_ty = tcx.type_of(id.owner_id).instantiate_identity();
|
||||
let generics = tcx.generics_of(id.owner_id);
|
||||
let pty_ty = tcx.type_of(def_id).instantiate_identity();
|
||||
let generics = tcx.generics_of(def_id);
|
||||
check_type_params_are_used(tcx, generics, pty_ty);
|
||||
}
|
||||
DefKind::ForeignMod => {
|
||||
let it = tcx.hir().item(id);
|
||||
let it = tcx.hir().expect_item(def_id);
|
||||
let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -589,19 +580,19 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
}
|
||||
}
|
||||
DefKind::GlobalAsm => {
|
||||
let it = tcx.hir().item(id);
|
||||
let it = tcx.hir().expect_item(def_id);
|
||||
let hir::ItemKind::GlobalAsm(asm) = it.kind else {
|
||||
span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
|
||||
};
|
||||
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
|
||||
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: hir::ItemId) {
|
||||
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
// an error would be reported if this fails.
|
||||
let _ = OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
|
||||
let _ = OnUnimplementedDirective::of_item(tcx, def_id.to_def_id());
|
||||
}
|
||||
|
||||
pub(super) fn check_specialization_validity<'tcx>(
|
||||
|
|
@ -1309,16 +1300,6 @@ pub(super) fn check_type_params_are_used<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
||||
let module = tcx.hir_module_items(module_def_id);
|
||||
for id in module.items() {
|
||||
check_item_type(tcx, id);
|
||||
}
|
||||
if module_def_id == LocalModDefId::CRATE_DEF_ID {
|
||||
super::entry::check_for_entry_fn(tcx);
|
||||
}
|
||||
}
|
||||
|
||||
fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed {
|
||||
struct_span_err!(tcx.dcx(), span, E0733, "recursion in an `async fn` requires boxing")
|
||||
.span_label(span, "recursive `async fn`")
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
// If a type in the trait ref is private, then there's also no reason to to do this check.
|
||||
// If a type in the trait ref is private, then there's also no reason to do this check.
|
||||
let impl_def_id = impl_m.container_id(tcx);
|
||||
for arg in impl_trait_ref.args {
|
||||
if let Some(ty) = arg.as_type()
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ pub use check::check_abi;
|
|||
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use check::check_mod_item_types;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
|
||||
|
|
@ -110,7 +109,6 @@ pub fn provide(providers: &mut Providers) {
|
|||
wfcheck::provide(providers);
|
||||
*providers = Providers {
|
||||
adt_destructor,
|
||||
check_mod_item_types,
|
||||
region_scope_tree,
|
||||
collect_return_position_impl_trait_in_trait_tys,
|
||||
compare_impl_const: compare_impl_item::compare_impl_const_raw,
|
||||
|
|
|
|||
|
|
@ -824,10 +824,6 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
|||
resolve_local(self, None, Some(body.value));
|
||||
}
|
||||
|
||||
if body.coroutine_kind.is_some() {
|
||||
self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count);
|
||||
}
|
||||
|
||||
// Restore context we had at the start.
|
||||
self.expr_and_pat_count = outer_ec;
|
||||
self.cx = outer_cx;
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
|
|||
item.name = ? tcx.def_path_str(def_id)
|
||||
);
|
||||
|
||||
match item.kind {
|
||||
let res = match item.kind {
|
||||
// Right now we check that every default trait implementation
|
||||
// has an implementation of itself. Basically, a case like:
|
||||
//
|
||||
|
|
@ -271,7 +271,11 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
|
|||
}
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
};
|
||||
|
||||
crate::check::check::check_item_type(tcx, def_id);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
|
|
@ -1909,7 +1913,11 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error
|
|||
let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
|
||||
res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
|
||||
res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
|
||||
res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)))
|
||||
res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
|
||||
if module == LocalModDefId::CRATE_DEF_ID {
|
||||
super::entry::check_for_entry_fn(tcx);
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> {
|
||||
|
|
|
|||
|
|
@ -1551,10 +1551,14 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
|||
|
||||
fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::CoroutineKind> {
|
||||
match tcx.hir_node_by_def_id(def_id) {
|
||||
Node::Expr(&rustc_hir::Expr {
|
||||
kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
|
||||
Node::Expr(&hir::Expr {
|
||||
kind:
|
||||
hir::ExprKind::Closure(&rustc_hir::Closure {
|
||||
kind: hir::ClosureKind::Coroutine(kind),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) => tcx.hir().body(body).coroutine_kind(),
|
||||
}) => Some(kind),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,7 +315,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
|
||||
if is_host_effect {
|
||||
if let Some(idx) = host_effect_index {
|
||||
bug!("parent also has host effect param? index: {idx}, def: {def_id:?}");
|
||||
tcx.dcx().span_delayed_bug(
|
||||
param.span,
|
||||
format!("parent also has host effect param? index: {idx}, def: {def_id:?}"),
|
||||
);
|
||||
}
|
||||
|
||||
host_effect_index = Some(index as usize);
|
||||
|
|
@ -338,14 +341,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
// cares about anything but the length is instantiation,
|
||||
// and we don't do that for closures.
|
||||
if let Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
|
||||
..
|
||||
kind: hir::ExprKind::Closure(hir::Closure { kind, .. }), ..
|
||||
}) = node
|
||||
{
|
||||
let dummy_args = if gen.is_some() {
|
||||
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
|
||||
} else {
|
||||
&["<closure_kind>", "<closure_signature>", "<upvars>"][..]
|
||||
let dummy_args = match kind {
|
||||
ClosureKind::Closure => &["<closure_kind>", "<closure_signature>", "<upvars>"][..],
|
||||
ClosureKind::Coroutine(_) => {
|
||||
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
|
||||
}
|
||||
};
|
||||
|
||||
params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
|
||||
|
|
|
|||
|
|
@ -408,6 +408,7 @@ pub struct ConstImplForNonConstTrait {
|
|||
pub struct ConstBoundForNonConstTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub modifier: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -200,18 +200,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
|||
})?;
|
||||
}
|
||||
|
||||
let errs = tcx.sess.time("wf_checking", || {
|
||||
tcx.sess.time("wf_checking", || {
|
||||
tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
|
||||
});
|
||||
|
||||
// NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
|
||||
tcx.sess.time("item_types_checking", || {
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
|
||||
});
|
||||
|
||||
// HACK: `check_mod_type_wf` may spuriously emit errors due to `span_delayed_bug`, even if
|
||||
// those errors only actually get emitted in `check_mod_item_types`.
|
||||
errs?;
|
||||
})?;
|
||||
|
||||
if tcx.features().rustc_attrs {
|
||||
tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?;
|
||||
|
|
|
|||
|
|
@ -1407,7 +1407,7 @@ impl<'a> State<'a> {
|
|||
body,
|
||||
fn_decl_span: _,
|
||||
fn_arg_span: _,
|
||||
movability: _,
|
||||
kind: _,
|
||||
def_id: _,
|
||||
}) => {
|
||||
self.print_closure_binder(binder, bound_generic_params);
|
||||
|
|
|
|||
|
|
@ -298,17 +298,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let parent_node = self.tcx.hir_node(parent_hir_id);
|
||||
if let (
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }),
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }),
|
||||
..
|
||||
}),
|
||||
hir::ExprKind::Block(..),
|
||||
) = (parent_node, callee_node)
|
||||
{
|
||||
let fn_decl_span = if hir.body(body).coroutine_kind
|
||||
== Some(hir::CoroutineKind::Desugared(
|
||||
let fn_decl_span = if matches!(
|
||||
kind,
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) {
|
||||
hir::CoroutineSource::Closure
|
||||
),)
|
||||
) {
|
||||
// Actually need to unwrap one more layer of HIR to get to
|
||||
// the _real_ closure...
|
||||
let async_closure = hir.parent_id(parent_hir_id);
|
||||
|
|
|
|||
|
|
@ -539,25 +539,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
match self.expr_ty.kind() {
|
||||
ty::Ref(_, _, mt) => {
|
||||
let mtstr = mt.prefix_str();
|
||||
if self.cast_ty.is_trait() {
|
||||
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
|
||||
Ok(s) => {
|
||||
err.span_suggestion(
|
||||
self.cast_span,
|
||||
"try casting to a reference instead",
|
||||
format!("&{mtstr}{s}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
let msg = format!("did you mean `&{mtstr}{tstr}`?");
|
||||
err.span_help(self.cast_span, msg);
|
||||
}
|
||||
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
|
||||
Ok(s) => {
|
||||
err.span_suggestion(
|
||||
self.cast_span,
|
||||
"try casting to a reference instead",
|
||||
format!("&{mtstr}{s}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
let msg = format!("did you mean `&{mtstr}{tstr}`?");
|
||||
err.span_help(self.cast_span, msg);
|
||||
}
|
||||
} else {
|
||||
let msg =
|
||||
format!("consider using an implicit coercion to `&{mtstr}{tstr}` instead");
|
||||
err.span_help(self.span, msg);
|
||||
}
|
||||
}
|
||||
ty::Adt(def, ..) if def.is_box() => {
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
|
|||
pub(super) fn check_fn<'a, 'tcx>(
|
||||
fcx: &mut FnCtxt<'a, 'tcx>,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
coroutine_types: Option<CoroutineTypes<'tcx>>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
fn_def_id: LocalDefId,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
can_be_coroutine: Option<hir::Movability>,
|
||||
params_can_be_unsized: bool,
|
||||
) -> Option<CoroutineTypes<'tcx>> {
|
||||
let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
|
||||
|
|
@ -49,56 +49,13 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
fcx.param_env,
|
||||
));
|
||||
|
||||
fcx.coroutine_types = coroutine_types;
|
||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
|
||||
|
||||
let span = body.value.span;
|
||||
|
||||
forbid_intrinsic_abi(tcx, span, fn_sig.abi);
|
||||
|
||||
if let Some(kind) = body.coroutine_kind
|
||||
&& can_be_coroutine.is_some()
|
||||
{
|
||||
let yield_ty = match kind {
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||
| hir::CoroutineKind::Coroutine => {
|
||||
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
});
|
||||
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
||||
yield_ty
|
||||
}
|
||||
// HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly
|
||||
// guide inference on the yield type so that we can handle `AsyncIterator`
|
||||
// in this block in projection correctly. In the new trait solver, it is
|
||||
// not a problem.
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
|
||||
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
});
|
||||
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
||||
|
||||
Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, Some(span))),
|
||||
tcx.mk_args(&[Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(tcx.require_lang_item(hir::LangItem::Option, Some(span))),
|
||||
tcx.mk_args(&[yield_ty.into()]),
|
||||
)
|
||||
.into()]),
|
||||
)
|
||||
}
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => Ty::new_unit(tcx),
|
||||
};
|
||||
|
||||
// Resume type defaults to `()` if the coroutine has no argument.
|
||||
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx));
|
||||
|
||||
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
|
||||
}
|
||||
|
||||
GatherLocalsVisitor::new(fcx).visit_body(body);
|
||||
|
||||
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
|
||||
|
|
@ -127,7 +84,8 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
// ty_span == binding_span iff this is a closure parameter with no type ascription,
|
||||
// or if it's an implicit `self` parameter
|
||||
traits::SizedArgumentType(
|
||||
if ty_span == Some(param.span) && tcx.is_closure(fn_def_id.into()) {
|
||||
if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
|
||||
{
|
||||
None
|
||||
} else {
|
||||
ty_span
|
||||
|
|
@ -148,32 +106,6 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType);
|
||||
fcx.check_return_expr(body.value, false);
|
||||
|
||||
// We insert the deferred_coroutine_interiors entry after visiting the body.
|
||||
// This ensures that all nested coroutines appear before the entry of this coroutine.
|
||||
// resolve_coroutine_interiors relies on this property.
|
||||
let coroutine_ty = if let (Some(_), Some(coroutine_kind)) =
|
||||
(can_be_coroutine, body.coroutine_kind)
|
||||
{
|
||||
let interior = fcx
|
||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
|
||||
fcx.deferred_coroutine_interiors.borrow_mut().push((
|
||||
fn_def_id,
|
||||
body.id(),
|
||||
interior,
|
||||
coroutine_kind,
|
||||
));
|
||||
|
||||
let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
|
||||
Some(CoroutineTypes {
|
||||
resume_ty,
|
||||
yield_ty,
|
||||
interior,
|
||||
movability: can_be_coroutine.unwrap(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Finalize the return check by taking the LUB of the return types
|
||||
// we saw and assigning it to the expected return type. This isn't
|
||||
// really expected to fail, since the coercions would have failed
|
||||
|
|
@ -209,7 +141,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
check_lang_start_fn(tcx, fn_sig, fn_def_id);
|
||||
}
|
||||
|
||||
coroutine_ty
|
||||
fcx.coroutine_types
|
||||
}
|
||||
|
||||
fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) {
|
||||
|
|
|
|||
|
|
@ -60,109 +60,175 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
None => (None, None),
|
||||
};
|
||||
let body = self.tcx.hir().body(closure.body);
|
||||
self.check_closure(closure, expr_span, expected_kind, body, expected_sig)
|
||||
|
||||
self.check_closure(closure, expr_span, expected_kind, expected_sig)
|
||||
}
|
||||
|
||||
#[instrument(skip(self, closure, body), level = "debug", ret)]
|
||||
#[instrument(skip(self, closure), level = "debug", ret)]
|
||||
fn check_closure(
|
||||
&self,
|
||||
closure: &hir::Closure<'tcx>,
|
||||
expr_span: Span,
|
||||
opt_kind: Option<ty::ClosureKind>,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
expected_sig: Option<ExpectedSig<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let body = tcx.hir().body(closure.body);
|
||||
|
||||
trace!("decl = {:#?}", closure.fn_decl);
|
||||
let expr_def_id = closure.def_id;
|
||||
debug!(?expr_def_id);
|
||||
|
||||
let ClosureSignatures { bound_sig, liberated_sig } =
|
||||
self.sig_of_closure(expr_def_id, closure.fn_decl, body, expected_sig);
|
||||
self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig);
|
||||
|
||||
debug!(?bound_sig, ?liberated_sig);
|
||||
|
||||
// FIXME: We could probably actually just unify this further --
|
||||
// instead of having a `FnSig` and a `Option<CoroutineTypes>`,
|
||||
// we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`,
|
||||
// similar to how `ty::GenSig` is a distinct data structure.
|
||||
let coroutine_types = match closure.kind {
|
||||
hir::ClosureKind::Closure => None,
|
||||
hir::ClosureKind::Coroutine(kind) => {
|
||||
let yield_ty = match kind {
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||
| hir::CoroutineKind::Coroutine(_) => {
|
||||
let yield_ty = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span: expr_span,
|
||||
});
|
||||
self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
|
||||
yield_ty
|
||||
}
|
||||
// HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly
|
||||
// guide inference on the yield type so that we can handle `AsyncIterator`
|
||||
// in this block in projection correctly. In the new trait solver, it is
|
||||
// not a problem.
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
|
||||
let yield_ty = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span: expr_span,
|
||||
});
|
||||
self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
|
||||
|
||||
Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(
|
||||
tcx.require_lang_item(hir::LangItem::Poll, Some(expr_span)),
|
||||
),
|
||||
tcx.mk_args(&[Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(
|
||||
tcx.require_lang_item(hir::LangItem::Option, Some(expr_span)),
|
||||
),
|
||||
tcx.mk_args(&[yield_ty.into()]),
|
||||
)
|
||||
.into()]),
|
||||
)
|
||||
}
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => {
|
||||
tcx.types.unit
|
||||
}
|
||||
};
|
||||
|
||||
// Resume type defaults to `()` if the coroutine has no argument.
|
||||
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
|
||||
|
||||
Some(CoroutineTypes { resume_ty, yield_ty })
|
||||
}
|
||||
};
|
||||
|
||||
let mut fcx = FnCtxt::new(self, self.param_env, closure.def_id);
|
||||
let coroutine_types = check_fn(
|
||||
check_fn(
|
||||
&mut fcx,
|
||||
liberated_sig,
|
||||
coroutine_types,
|
||||
closure.fn_decl,
|
||||
expr_def_id,
|
||||
body,
|
||||
closure.movability,
|
||||
// Closure "rust-call" ABI doesn't support unsized params
|
||||
false,
|
||||
);
|
||||
|
||||
let parent_args = GenericArgs::identity_for_item(
|
||||
self.tcx,
|
||||
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
|
||||
);
|
||||
let parent_args =
|
||||
GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
|
||||
|
||||
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: self.tcx.def_span(expr_def_id),
|
||||
span: expr_span,
|
||||
});
|
||||
|
||||
if let Some(CoroutineTypes { resume_ty, yield_ty, interior, movability }) = coroutine_types
|
||||
{
|
||||
let coroutine_args = ty::CoroutineArgs::new(
|
||||
self.tcx,
|
||||
ty::CoroutineArgsParts {
|
||||
parent_args,
|
||||
resume_ty,
|
||||
yield_ty,
|
||||
return_ty: liberated_sig.output(),
|
||||
witness: interior,
|
||||
tupled_upvars_ty,
|
||||
},
|
||||
);
|
||||
match closure.kind {
|
||||
hir::ClosureKind::Closure => {
|
||||
assert_eq!(coroutine_types, None);
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
// the `closures` table.
|
||||
let sig = bound_sig.map_bound(|sig| {
|
||||
tcx.mk_fn_sig(
|
||||
[Ty::new_tup(tcx, sig.inputs())],
|
||||
sig.output(),
|
||||
sig.c_variadic,
|
||||
sig.unsafety,
|
||||
sig.abi,
|
||||
)
|
||||
});
|
||||
|
||||
return Ty::new_coroutine(
|
||||
self.tcx,
|
||||
expr_def_id.to_def_id(),
|
||||
coroutine_args.args,
|
||||
movability,
|
||||
);
|
||||
debug!(?sig, ?opt_kind);
|
||||
|
||||
let closure_kind_ty = match opt_kind {
|
||||
Some(kind) => Ty::from_closure_kind(tcx, kind),
|
||||
|
||||
// Create a type variable (for now) to represent the closure kind.
|
||||
// It will be unified during the upvar inference phase (`upvar.rs`)
|
||||
None => self.next_root_ty_var(TypeVariableOrigin {
|
||||
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr_span,
|
||||
}),
|
||||
};
|
||||
|
||||
let closure_args = ty::ClosureArgs::new(
|
||||
tcx,
|
||||
ty::ClosureArgsParts {
|
||||
parent_args,
|
||||
closure_kind_ty,
|
||||
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
|
||||
tupled_upvars_ty,
|
||||
},
|
||||
);
|
||||
|
||||
Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args)
|
||||
}
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else {
|
||||
bug!("expected coroutine to have yield/resume types");
|
||||
};
|
||||
let interior = fcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: body.value.span,
|
||||
});
|
||||
fcx.deferred_coroutine_interiors.borrow_mut().push((
|
||||
expr_def_id,
|
||||
body.id(),
|
||||
interior,
|
||||
));
|
||||
|
||||
let coroutine_args = ty::CoroutineArgs::new(
|
||||
tcx,
|
||||
ty::CoroutineArgsParts {
|
||||
parent_args,
|
||||
resume_ty,
|
||||
yield_ty,
|
||||
return_ty: liberated_sig.output(),
|
||||
witness: interior,
|
||||
tupled_upvars_ty,
|
||||
},
|
||||
);
|
||||
|
||||
Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args)
|
||||
}
|
||||
}
|
||||
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
// the `closures` table.
|
||||
let sig = bound_sig.map_bound(|sig| {
|
||||
self.tcx.mk_fn_sig(
|
||||
[Ty::new_tup(self.tcx, sig.inputs())],
|
||||
sig.output(),
|
||||
sig.c_variadic,
|
||||
sig.unsafety,
|
||||
sig.abi,
|
||||
)
|
||||
});
|
||||
|
||||
debug!(?sig, ?opt_kind);
|
||||
|
||||
let closure_kind_ty = match opt_kind {
|
||||
Some(kind) => Ty::from_closure_kind(self.tcx, kind),
|
||||
|
||||
// Create a type variable (for now) to represent the closure kind.
|
||||
// It will be unified during the upvar inference phase (`upvar.rs`)
|
||||
None => self.next_root_ty_var(TypeVariableOrigin {
|
||||
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr_span,
|
||||
}),
|
||||
};
|
||||
|
||||
let closure_args = ty::ClosureArgs::new(
|
||||
self.tcx,
|
||||
ty::ClosureArgsParts {
|
||||
parent_args,
|
||||
closure_kind_ty,
|
||||
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig),
|
||||
tupled_upvars_ty,
|
||||
},
|
||||
);
|
||||
|
||||
Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_args.args)
|
||||
}
|
||||
|
||||
/// Given the expected type, figures out what it can about this closure we
|
||||
|
|
@ -351,28 +417,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
body: &hir::Body<'_>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
expected_sig: Option<ExpectedSig<'tcx>>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
if let Some(e) = expected_sig {
|
||||
self.sig_of_closure_with_expectation(expr_def_id, decl, body, e)
|
||||
self.sig_of_closure_with_expectation(expr_def_id, decl, closure_kind, e)
|
||||
} else {
|
||||
self.sig_of_closure_no_expectation(expr_def_id, decl, body)
|
||||
self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind)
|
||||
}
|
||||
}
|
||||
|
||||
/// If there is no expected signature, then we will convert the
|
||||
/// types that the user gave into a signature.
|
||||
#[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
|
||||
#[instrument(skip(self, expr_def_id, decl), level = "debug")]
|
||||
fn sig_of_closure_no_expectation(
|
||||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
body: &hir::Body<'_>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
|
||||
let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind);
|
||||
|
||||
self.closure_sigs(expr_def_id, body, bound_sig)
|
||||
self.closure_sigs(expr_def_id, bound_sig)
|
||||
}
|
||||
|
||||
/// Invoked to compute the signature of a closure expression. This
|
||||
|
|
@ -422,24 +488,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// - `expected_sig`: the expected signature (if any). Note that
|
||||
/// this is missing a binder: that is, there may be late-bound
|
||||
/// regions with depth 1, which are bound then by the closure.
|
||||
#[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
|
||||
#[instrument(skip(self, expr_def_id, decl), level = "debug")]
|
||||
fn sig_of_closure_with_expectation(
|
||||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
body: &hir::Body<'_>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
expected_sig: ExpectedSig<'tcx>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
// Watch out for some surprises and just ignore the
|
||||
// expectation if things don't see to match up with what we
|
||||
// expect.
|
||||
if expected_sig.sig.c_variadic() != decl.c_variadic {
|
||||
return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
|
||||
return self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind);
|
||||
} else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 {
|
||||
return self.sig_of_closure_with_mismatched_number_of_arguments(
|
||||
expr_def_id,
|
||||
decl,
|
||||
body,
|
||||
expected_sig,
|
||||
);
|
||||
}
|
||||
|
|
@ -463,16 +528,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// anonymize away, so as not to confuse the user.
|
||||
let bound_sig = self.tcx.anonymize_bound_vars(bound_sig);
|
||||
|
||||
let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig);
|
||||
let closure_sigs = self.closure_sigs(expr_def_id, bound_sig);
|
||||
|
||||
// Up till this point, we have ignored the annotations that the user
|
||||
// gave. This function will check that they unify successfully.
|
||||
// Along the way, it also writes out entries for types that the user
|
||||
// wrote into our typeck results, which are then later used by the privacy
|
||||
// check.
|
||||
match self.merge_supplied_sig_with_expectation(expr_def_id, decl, body, closure_sigs) {
|
||||
match self.merge_supplied_sig_with_expectation(
|
||||
expr_def_id,
|
||||
decl,
|
||||
closure_kind,
|
||||
closure_sigs,
|
||||
) {
|
||||
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
|
||||
Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, body),
|
||||
Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -480,7 +550,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
body: &hir::Body<'_>,
|
||||
expected_sig: ExpectedSig<'tcx>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
let expr_map_node = self.tcx.hir_node_by_def_id(expr_def_id);
|
||||
|
|
@ -511,25 +580,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let error_sig = self.error_sig_of_closure(decl, guar);
|
||||
|
||||
self.closure_sigs(expr_def_id, body, error_sig)
|
||||
self.closure_sigs(expr_def_id, error_sig)
|
||||
}
|
||||
|
||||
/// Enforce the user's types against the expectation. See
|
||||
/// `sig_of_closure_with_expectation` for details on the overall
|
||||
/// strategy.
|
||||
#[instrument(level = "debug", skip(self, expr_def_id, decl, body, expected_sigs))]
|
||||
#[instrument(level = "debug", skip(self, expr_def_id, decl, expected_sigs))]
|
||||
fn merge_supplied_sig_with_expectation(
|
||||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
body: &hir::Body<'_>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
mut expected_sigs: ClosureSignatures<'tcx>,
|
||||
) -> InferResult<'tcx, ClosureSignatures<'tcx>> {
|
||||
// Get the signature S that the user gave.
|
||||
//
|
||||
// (See comment on `sig_of_closure_with_expectation` for the
|
||||
// meaning of these letters.)
|
||||
let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
|
||||
let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind);
|
||||
|
||||
debug!(?supplied_sig);
|
||||
|
||||
|
|
@ -611,17 +680,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// types that the user gave into a signature.
|
||||
///
|
||||
/// Also, record this closure signature for later.
|
||||
#[instrument(skip(self, decl, body), level = "debug", ret)]
|
||||
#[instrument(skip(self, decl), level = "debug", ret)]
|
||||
fn supplied_sig_of_closure(
|
||||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
body: &hir::Body<'_>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
let astconv: &dyn AstConv<'_> = self;
|
||||
|
||||
trace!("decl = {:#?}", decl);
|
||||
debug!(?body.coroutine_kind);
|
||||
debug!(?closure_kind);
|
||||
|
||||
let hir_id = self.tcx.local_def_id_to_hir_id(expr_def_id);
|
||||
let bound_vars = self.tcx.late_bound_vars(hir_id);
|
||||
|
|
@ -630,36 +699,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a));
|
||||
let supplied_return = match decl.output {
|
||||
hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(output),
|
||||
hir::FnRetTy::DefaultReturn(_) => match body.coroutine_kind {
|
||||
hir::FnRetTy::DefaultReturn(_) => match closure_kind {
|
||||
// In the case of the async block that we create for a function body,
|
||||
// we expect the return type of the block to match that of the enclosing
|
||||
// function.
|
||||
Some(hir::CoroutineKind::Desugared(
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
debug!("closure is async fn body");
|
||||
let def_id = self.tcx.hir().body_owner_def_id(body.id());
|
||||
self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else(
|
||||
|| {
|
||||
// AFAIK, deducing the future output
|
||||
// always succeeds *except* in error cases
|
||||
// like #65159. I'd like to return Error
|
||||
// here, but I can't because I can't
|
||||
// easily (and locally) prove that we
|
||||
// *have* reported an
|
||||
// error. --nikomatsakis
|
||||
astconv.ty_infer(None, decl.output.span())
|
||||
},
|
||||
)
|
||||
self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| {
|
||||
// AFAIK, deducing the future output
|
||||
// always succeeds *except* in error cases
|
||||
// like #65159. I'd like to return Error
|
||||
// here, but I can't because I can't
|
||||
// easily (and locally) prove that we
|
||||
// *have* reported an
|
||||
// error. --nikomatsakis
|
||||
astconv.ty_infer(None, decl.output.span())
|
||||
})
|
||||
}
|
||||
// All `gen {}` and `async gen {}` must return unit.
|
||||
Some(
|
||||
hir::ClosureKind::Coroutine(
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
|
||||
) => self.tcx.types.unit,
|
||||
|
||||
_ => astconv.ty_infer(None, decl.output.span()),
|
||||
// For async blocks, we just fall back to `_` here.
|
||||
// For closures/coroutines, we know nothing about the return
|
||||
// type unless it was supplied.
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
_,
|
||||
))
|
||||
| hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_))
|
||||
| hir::ClosureKind::Closure => astconv.ty_infer(None, decl.output.span()),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -688,16 +762,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// Future<Output = T>`, so we do this by searching through the
|
||||
/// obligations to extract the `T`.
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
fn deduce_future_output_from_obligations(
|
||||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
body_def_id: LocalDefId,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
fn deduce_future_output_from_obligations(&self, body_def_id: LocalDefId) -> Option<Ty<'tcx>> {
|
||||
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
|
||||
span_bug!(self.tcx.def_span(expr_def_id), "async fn coroutine outside of a fn")
|
||||
span_bug!(self.tcx.def_span(body_def_id), "async fn coroutine outside of a fn")
|
||||
});
|
||||
|
||||
let closure_span = self.tcx.def_span(expr_def_id);
|
||||
let closure_span = self.tcx.def_span(body_def_id);
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty);
|
||||
|
||||
|
|
@ -842,12 +912,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn closure_sigs(
|
||||
&self,
|
||||
expr_def_id: LocalDefId,
|
||||
body: &hir::Body<'_>,
|
||||
bound_sig: ty::PolyFnSig<'tcx>,
|
||||
) -> ClosureSignatures<'tcx> {
|
||||
let liberated_sig =
|
||||
self.tcx().liberate_late_bound_regions(expr_def_id.to_def_id(), bound_sig);
|
||||
let liberated_sig = self.normalize(body.value.span, liberated_sig);
|
||||
let liberated_sig = self.normalize(self.tcx.def_span(expr_def_id), liberated_sig);
|
||||
ClosureSignatures { bound_sig, liberated_sig }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use crate::errors::{
|
|||
use crate::fatally_break_rust;
|
||||
use crate::method::SelfSource;
|
||||
use crate::type_error_struct;
|
||||
use crate::CoroutineTypes;
|
||||
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
use crate::{
|
||||
report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
|
||||
|
|
@ -187,8 +188,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected: Expectation<'tcx>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
) -> Ty<'tcx> {
|
||||
if self.tcx().sess.verbose() {
|
||||
// make this code only run with -Zverbose because it is probably slow
|
||||
if self.tcx().sess.verbose_internals() {
|
||||
// make this code only run with -Zverbose-internals because it is probably slow
|
||||
if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
|
||||
if !lint_str.contains('\n') {
|
||||
debug!("expr text: {lint_str}");
|
||||
|
|
@ -349,7 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ExprKind::Index(base, idx, brackets_span) => {
|
||||
self.check_expr_index(base, idx, expr, brackets_span)
|
||||
}
|
||||
ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
|
||||
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
|
||||
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
|
||||
}
|
||||
}
|
||||
|
|
@ -1131,8 +1132,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap();
|
||||
let lhs_ty = self.check_expr(lhs);
|
||||
let rhs_ty = self.check_expr(rhs);
|
||||
let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| {
|
||||
let lhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, lhs.peel_refs());
|
||||
let rhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rhs.peel_refs());
|
||||
self.can_coerce(rhs, lhs)
|
||||
};
|
||||
let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) {
|
||||
(Applicability::MachineApplicable, true)
|
||||
} else if refs_can_coerce(rhs_ty, lhs_ty) {
|
||||
// The lhs and rhs are likely missing some references in either side. Subsequent
|
||||
// suggestions will show up.
|
||||
(Applicability::MaybeIncorrect, true)
|
||||
} else if let ExprKind::Binary(
|
||||
Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
|
||||
_,
|
||||
|
|
@ -1142,7 +1152,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// if x == 1 && y == 2 { .. }
|
||||
// +
|
||||
let actual_lhs_ty = self.check_expr(rhs_expr);
|
||||
(Applicability::MaybeIncorrect, self.can_coerce(rhs_ty, actual_lhs_ty))
|
||||
(
|
||||
Applicability::MaybeIncorrect,
|
||||
self.can_coerce(rhs_ty, actual_lhs_ty)
|
||||
|| refs_can_coerce(rhs_ty, actual_lhs_ty),
|
||||
)
|
||||
} else if let ExprKind::Binary(
|
||||
Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
|
||||
lhs_expr,
|
||||
|
|
@ -1152,7 +1166,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// if x == 1 && y == 2 { .. }
|
||||
// +
|
||||
let actual_rhs_ty = self.check_expr(lhs_expr);
|
||||
(Applicability::MaybeIncorrect, self.can_coerce(actual_rhs_ty, lhs_ty))
|
||||
(
|
||||
Applicability::MaybeIncorrect,
|
||||
self.can_coerce(actual_rhs_ty, lhs_ty)
|
||||
|| refs_can_coerce(actual_rhs_ty, lhs_ty),
|
||||
)
|
||||
} else {
|
||||
(Applicability::MaybeIncorrect, false)
|
||||
};
|
||||
|
|
@ -3145,22 +3163,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
value: &'tcx hir::Expr<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
src: &'tcx hir::YieldSource,
|
||||
) -> Ty<'tcx> {
|
||||
match self.resume_yield_tys {
|
||||
Some((resume_ty, yield_ty)) => {
|
||||
match self.coroutine_types {
|
||||
Some(CoroutineTypes { resume_ty, yield_ty }) => {
|
||||
self.check_expr_coercible_to_type(value, yield_ty, None);
|
||||
|
||||
resume_ty
|
||||
}
|
||||
// Given that this `yield` expression was generated as a result of lowering a `.await`,
|
||||
// we know that the yield type must be `()`; however, the context won't contain this
|
||||
// information. Hence, we check the source of the yield expression here and check its
|
||||
// value's type against `()` (this check should always hold).
|
||||
None if src.is_await() => {
|
||||
self.check_expr_coercible_to_type(value, Ty::new_unit(self.tcx), None);
|
||||
Ty::new_unit(self.tcx)
|
||||
}
|
||||
_ => {
|
||||
self.dcx().emit_err(YieldExprOutsideOfCoroutine { span: expr.span });
|
||||
// Avoid expressions without types during writeback (#78653).
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue