Merge from rustc

This commit is contained in:
The Miri Conjob Bot 2024-01-05 05:12:56 +00:00
commit d11a2bdc1d
1255 changed files with 19259 additions and 11266 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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, &param.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 &param.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,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-12-24"
channel = "nightly-2023-12-31"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -408,6 +408,7 @@ pub struct ConstImplForNonConstTrait {
pub struct ConstBoundForNonConstTrait {
#[primary_span]
pub span: Span,
pub modifier: &'static str,
}
#[derive(Diagnostic)]

View file

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

View file

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

View file

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

View file

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

View file

@ -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<'_>) {

View file

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

View file

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