Auto merge of #138747 - matthiaskrgr:rollup-68x44rw, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #138435 (Add support for postfix yield expressions) - #138685 (Use `Option<Ident>` for lowered param names.) - #138700 (Suggest `-Whelp` when pass `--print lints` to rustc) - #138727 (Do not rely on `type_var_origin` in `OrphanCheckErr::NonLocalInputType`) - #138729 (Clean up `FnCtxt::resolve_coroutine_interiors`) - #138731 (coverage: Add LLVM plumbing for expansion regions) - #138732 (Use `def_path_str` for def id arg in `UnsupportedOpInfo`) - #138735 (Remove `llvm` and `llvms` triagebot ping aliases for `icebreakers-llvm` ping group) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
eda7820be5
62 changed files with 499 additions and 240 deletions
|
@ -1657,7 +1657,7 @@ pub enum ExprKind {
|
||||||
Try(P<Expr>),
|
Try(P<Expr>),
|
||||||
|
|
||||||
/// A `yield`, with an optional value to be yielded.
|
/// A `yield`, with an optional value to be yielded.
|
||||||
Yield(Option<P<Expr>>),
|
Yield(YieldKind),
|
||||||
|
|
||||||
/// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever),
|
/// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever),
|
||||||
/// with an optional value to be returned.
|
/// with an optional value to be returned.
|
||||||
|
@ -1903,6 +1903,44 @@ pub enum MatchKind {
|
||||||
Postfix,
|
Postfix,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of yield expression
|
||||||
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
|
pub enum YieldKind {
|
||||||
|
/// yield expr { ... }
|
||||||
|
Prefix(Option<P<Expr>>),
|
||||||
|
/// expr.yield { ... }
|
||||||
|
Postfix(P<Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl YieldKind {
|
||||||
|
/// Returns the expression inside the yield expression, if any.
|
||||||
|
///
|
||||||
|
/// For postfix yields, this is guaranteed to be `Some`.
|
||||||
|
pub const fn expr(&self) -> Option<&P<Expr>> {
|
||||||
|
match self {
|
||||||
|
YieldKind::Prefix(expr) => expr.as_ref(),
|
||||||
|
YieldKind::Postfix(expr) => Some(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the expression being yielded, if any.
|
||||||
|
pub const fn expr_mut(&mut self) -> Option<&mut P<Expr>> {
|
||||||
|
match self {
|
||||||
|
YieldKind::Prefix(expr) => expr.as_mut(),
|
||||||
|
YieldKind::Postfix(expr) => Some(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if both yields are prefix or both are postfix.
|
||||||
|
pub const fn same_kind(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(YieldKind::Prefix(_), YieldKind::Prefix(_)) => true,
|
||||||
|
(YieldKind::Postfix(_), YieldKind::Postfix(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A literal in a meta item.
|
/// A literal in a meta item.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub struct MetaItemLit {
|
pub struct MetaItemLit {
|
||||||
|
|
|
@ -1813,8 +1813,11 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
||||||
ExprKind::Paren(expr) => {
|
ExprKind::Paren(expr) => {
|
||||||
vis.visit_expr(expr);
|
vis.visit_expr(expr);
|
||||||
}
|
}
|
||||||
ExprKind::Yield(expr) => {
|
ExprKind::Yield(kind) => {
|
||||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
let expr = kind.expr_mut();
|
||||||
|
if let Some(expr) = expr {
|
||||||
|
vis.visit_expr(expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Try(expr) => vis.visit_expr(expr),
|
ExprKind::Try(expr) => vis.visit_expr(expr),
|
||||||
ExprKind::TryBlock(body) => vis.visit_block(body),
|
ExprKind::TryBlock(body) => vis.visit_block(body),
|
||||||
|
|
|
@ -182,11 +182,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
||||||
| Range(_, Some(e), _)
|
| Range(_, Some(e), _)
|
||||||
| Ret(Some(e))
|
| Ret(Some(e))
|
||||||
| Unary(_, e)
|
| Unary(_, e)
|
||||||
| Yield(Some(e))
|
|
||||||
| Yeet(Some(e))
|
| Yeet(Some(e))
|
||||||
| Become(e) => {
|
| Become(e) => {
|
||||||
expr = e;
|
expr = e;
|
||||||
}
|
}
|
||||||
|
Yield(kind) => match kind.expr() {
|
||||||
|
Some(e) => expr = e,
|
||||||
|
None => break None,
|
||||||
|
},
|
||||||
Closure(closure) => {
|
Closure(closure) => {
|
||||||
expr = &closure.body;
|
expr = &closure.body;
|
||||||
}
|
}
|
||||||
|
@ -217,7 +220,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
||||||
Break(_, None)
|
Break(_, None)
|
||||||
| Range(_, None, _)
|
| Range(_, None, _)
|
||||||
| Ret(None)
|
| Ret(None)
|
||||||
| Yield(None)
|
|
||||||
| Array(_)
|
| Array(_)
|
||||||
| Call(_, _)
|
| Call(_, _)
|
||||||
| MethodCall(_)
|
| MethodCall(_)
|
||||||
|
@ -237,7 +239,9 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
||||||
| Yeet(None)
|
| Yeet(None)
|
||||||
| UnsafeBinderCast(..)
|
| UnsafeBinderCast(..)
|
||||||
| Err(_)
|
| Err(_)
|
||||||
| Dummy => break None,
|
| Dummy => {
|
||||||
|
break None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1269,8 +1269,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
||||||
try_visit!(visitor.visit_ty(container));
|
try_visit!(visitor.visit_ty(container));
|
||||||
walk_list!(visitor, visit_ident, fields.iter());
|
walk_list!(visitor, visit_ident, fields.iter());
|
||||||
}
|
}
|
||||||
ExprKind::Yield(optional_expression) => {
|
ExprKind::Yield(kind) => {
|
||||||
visit_opt!(visitor, visit_expr, optional_expression);
|
visit_opt!(visitor, visit_expr, kind.expr());
|
||||||
}
|
}
|
||||||
ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)),
|
ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)),
|
||||||
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
|
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
|
||||||
|
|
|
@ -351,7 +351,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
rest,
|
rest,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)),
|
||||||
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
|
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
|
||||||
|
|
||||||
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
|
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
|
||||||
|
|
|
@ -1513,16 +1513,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
|
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] {
|
||||||
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
|
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
|
||||||
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
|
PatKind::Ident(_, ident, _) => {
|
||||||
PatKind::Wild => Ident::new(kw::Underscore, self.lower_span(param.pat.span)),
|
if ident.name != kw::Empty {
|
||||||
|
Some(self.lower_ident(ident))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))),
|
||||||
_ => {
|
_ => {
|
||||||
self.dcx().span_delayed_bug(
|
self.dcx().span_delayed_bug(
|
||||||
param.pat.span,
|
param.pat.span,
|
||||||
"non-ident/wild param pat must trigger an error",
|
"non-ident/wild param pat must trigger an error",
|
||||||
);
|
);
|
||||||
Ident::new(kw::Empty, self.lower_span(param.pat.span))
|
None
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||||
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
|
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
|
||||||
use rustc_ast::{
|
use rustc_ast::{
|
||||||
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
|
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
|
||||||
FormatDebugHex, FormatSign, FormatTrait, token,
|
FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::pp::Breaks::Inconsistent;
|
use crate::pp::Breaks::Inconsistent;
|
||||||
|
@ -761,7 +761,7 @@ impl<'a> State<'a> {
|
||||||
self.print_expr(e, FixupContext::default());
|
self.print_expr(e, FixupContext::default());
|
||||||
self.pclose();
|
self.pclose();
|
||||||
}
|
}
|
||||||
ast::ExprKind::Yield(e) => {
|
ast::ExprKind::Yield(YieldKind::Prefix(e)) => {
|
||||||
self.word("yield");
|
self.word("yield");
|
||||||
|
|
||||||
if let Some(expr) = e {
|
if let Some(expr) = e {
|
||||||
|
@ -773,6 +773,14 @@ impl<'a> State<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::ExprKind::Yield(YieldKind::Postfix(e)) => {
|
||||||
|
self.print_expr_cond_paren(
|
||||||
|
e,
|
||||||
|
e.precedence() < ExprPrecedence::Unambiguous,
|
||||||
|
fixup.leftmost_subexpression_with_dot(),
|
||||||
|
);
|
||||||
|
self.word(".yield");
|
||||||
|
}
|
||||||
ast::ExprKind::Try(e) => {
|
ast::ExprKind::Try(e) => {
|
||||||
self.print_expr_cond_paren(
|
self.print_expr_cond_paren(
|
||||||
e,
|
e,
|
||||||
|
|
|
@ -2514,12 +2514,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let ty::Tuple(params) = tupled_params.kind() else { return };
|
let ty::Tuple(params) = tupled_params.kind() else { return };
|
||||||
|
|
||||||
// Find the first argument with a matching type, get its name
|
// Find the first argument with a matching type, get its name
|
||||||
let Some((_, this_name)) =
|
let Some(this_name) = params.iter().zip(tcx.hir_body_param_names(closure.body)).find_map(
|
||||||
params.iter().zip(tcx.hir_body_param_names(closure.body)).find(|(param_ty, name)| {
|
|(param_ty, name)| {
|
||||||
// FIXME: also support deref for stuff like `Rc` arguments
|
// FIXME: also support deref for stuff like `Rc` arguments
|
||||||
param_ty.peel_refs() == local_ty && name != &Ident::empty()
|
if param_ty.peel_refs() == local_ty { name } else { None }
|
||||||
})
|
},
|
||||||
else {
|
) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3787,7 +3787,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
method_args,
|
method_args,
|
||||||
*fn_span,
|
*fn_span,
|
||||||
call_source.from_hir_call(),
|
call_source.from_hir_call(),
|
||||||
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
|
self.infcx.tcx.fn_arg_names(method_did)[0],
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
|
err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
|
||||||
|
|
|
@ -1029,7 +1029,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
method_args,
|
method_args,
|
||||||
*fn_span,
|
*fn_span,
|
||||||
call_source.from_hir_call(),
|
call_source.from_hir_call(),
|
||||||
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
|
self.infcx.tcx.fn_arg_names(method_did)[0],
|
||||||
);
|
);
|
||||||
|
|
||||||
return FnSelfUse {
|
return FnSelfUse {
|
||||||
|
|
|
@ -146,6 +146,7 @@ pub(crate) struct CoverageSpan {
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub(crate) struct Regions {
|
pub(crate) struct Regions {
|
||||||
pub(crate) code_regions: Vec<CodeRegion>,
|
pub(crate) code_regions: Vec<CodeRegion>,
|
||||||
|
pub(crate) expansion_regions: Vec<ExpansionRegion>,
|
||||||
pub(crate) branch_regions: Vec<BranchRegion>,
|
pub(crate) branch_regions: Vec<BranchRegion>,
|
||||||
pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>,
|
pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>,
|
||||||
pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>,
|
pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>,
|
||||||
|
@ -154,10 +155,16 @@ pub(crate) struct Regions {
|
||||||
impl Regions {
|
impl Regions {
|
||||||
/// Returns true if none of this structure's tables contain any regions.
|
/// Returns true if none of this structure's tables contain any regions.
|
||||||
pub(crate) fn has_no_regions(&self) -> bool {
|
pub(crate) fn has_no_regions(&self) -> bool {
|
||||||
let Self { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
|
let Self {
|
||||||
self;
|
code_regions,
|
||||||
|
expansion_regions,
|
||||||
|
branch_regions,
|
||||||
|
mcdc_branch_regions,
|
||||||
|
mcdc_decision_regions,
|
||||||
|
} = self;
|
||||||
|
|
||||||
code_regions.is_empty()
|
code_regions.is_empty()
|
||||||
|
&& expansion_regions.is_empty()
|
||||||
&& branch_regions.is_empty()
|
&& branch_regions.is_empty()
|
||||||
&& mcdc_branch_regions.is_empty()
|
&& mcdc_branch_regions.is_empty()
|
||||||
&& mcdc_decision_regions.is_empty()
|
&& mcdc_decision_regions.is_empty()
|
||||||
|
@ -172,6 +179,14 @@ pub(crate) struct CodeRegion {
|
||||||
pub(crate) counter: Counter,
|
pub(crate) counter: Counter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Must match the layout of `LLVMRustCoverageExpansionRegion`.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct ExpansionRegion {
|
||||||
|
pub(crate) cov_span: CoverageSpan,
|
||||||
|
pub(crate) expanded_file_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
/// Must match the layout of `LLVMRustCoverageBranchRegion`.
|
/// Must match the layout of `LLVMRustCoverageBranchRegion`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
@ -63,8 +63,18 @@ pub(crate) fn write_function_mappings_to_buffer(
|
||||||
expressions: &[ffi::CounterExpression],
|
expressions: &[ffi::CounterExpression],
|
||||||
regions: &ffi::Regions,
|
regions: &ffi::Regions,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
|
let ffi::Regions {
|
||||||
regions;
|
code_regions,
|
||||||
|
expansion_regions,
|
||||||
|
branch_regions,
|
||||||
|
mcdc_branch_regions,
|
||||||
|
mcdc_decision_regions,
|
||||||
|
} = regions;
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// - All types are FFI-compatible and have matching representations in Rust/C++.
|
||||||
|
// - For pointer/length pairs, the pointer and length come from the same vector or slice.
|
||||||
|
// - C++ code does not retain any pointers after the call returns.
|
||||||
llvm::build_byte_buffer(|buffer| unsafe {
|
llvm::build_byte_buffer(|buffer| unsafe {
|
||||||
llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
||||||
virtual_file_mapping.as_ptr(),
|
virtual_file_mapping.as_ptr(),
|
||||||
|
@ -73,6 +83,8 @@ pub(crate) fn write_function_mappings_to_buffer(
|
||||||
expressions.len(),
|
expressions.len(),
|
||||||
code_regions.as_ptr(),
|
code_regions.as_ptr(),
|
||||||
code_regions.len(),
|
code_regions.len(),
|
||||||
|
expansion_regions.as_ptr(),
|
||||||
|
expansion_regions.len(),
|
||||||
branch_regions.as_ptr(),
|
branch_regions.as_ptr(),
|
||||||
branch_regions.len(),
|
branch_regions.len(),
|
||||||
mcdc_branch_regions.as_ptr(),
|
mcdc_branch_regions.as_ptr(),
|
||||||
|
|
|
@ -120,12 +120,22 @@ fn fill_region_tables<'tcx>(
|
||||||
// Associate that global file ID with a local file ID for this function.
|
// Associate that global file ID with a local file ID for this function.
|
||||||
let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id);
|
let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id);
|
||||||
|
|
||||||
let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
|
// In rare cases, _all_ of a function's spans are discarded, and coverage
|
||||||
&mut covfun.regions;
|
// codegen needs to handle that gracefully to avoid #133606.
|
||||||
|
// It's hard for tests to trigger this organically, so instead we set
|
||||||
let make_cov_span =
|
// `-Zcoverage-options=discard-all-spans-in-codegen` to force it to occur.
|
||||||
|span: Span| spans::make_coverage_span(local_file_id, source_map, &source_file, span);
|
|
||||||
let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen();
|
let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen();
|
||||||
|
let make_coords = |span: Span| {
|
||||||
|
if discard_all { None } else { spans::make_coords(source_map, &source_file, span) }
|
||||||
|
};
|
||||||
|
|
||||||
|
let ffi::Regions {
|
||||||
|
code_regions,
|
||||||
|
expansion_regions: _, // FIXME(Zalathar): Fill out support for expansion regions
|
||||||
|
branch_regions,
|
||||||
|
mcdc_branch_regions,
|
||||||
|
mcdc_decision_regions,
|
||||||
|
} = &mut covfun.regions;
|
||||||
|
|
||||||
// For each counter/region pair in this function+file, convert it to a
|
// For each counter/region pair in this function+file, convert it to a
|
||||||
// form suitable for FFI.
|
// form suitable for FFI.
|
||||||
|
@ -140,17 +150,8 @@ fn fill_region_tables<'tcx>(
|
||||||
ffi::Counter::from_term(term)
|
ffi::Counter::from_term(term)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert the `Span` into coordinates that we can pass to LLVM, or
|
let Some(coords) = make_coords(span) else { continue };
|
||||||
// discard the span if conversion fails. In rare, cases _all_ of a
|
let cov_span = coords.make_coverage_span(local_file_id);
|
||||||
// function's spans are discarded, and the rest of coverage codegen
|
|
||||||
// needs to handle that gracefully to avoid a repeat of #133606.
|
|
||||||
// We don't have a good test case for triggering that organically, so
|
|
||||||
// instead we set `-Zcoverage-options=discard-all-spans-in-codegen`
|
|
||||||
// to force it to occur.
|
|
||||||
let Some(cov_span) = make_cov_span(span) else { continue };
|
|
||||||
if discard_all {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
match *kind {
|
match *kind {
|
||||||
MappingKind::Code { bcb } => {
|
MappingKind::Code { bcb } => {
|
||||||
|
|
|
@ -5,22 +5,40 @@ use tracing::debug;
|
||||||
use crate::coverageinfo::ffi;
|
use crate::coverageinfo::ffi;
|
||||||
use crate::coverageinfo::mapgen::LocalFileId;
|
use crate::coverageinfo::mapgen::LocalFileId;
|
||||||
|
|
||||||
|
/// Line and byte-column coordinates of a source code span within some file.
|
||||||
|
/// The file itself must be tracked separately.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub(crate) struct Coords {
|
||||||
|
/// 1-based starting line of the source code span.
|
||||||
|
pub(crate) start_line: u32,
|
||||||
|
/// 1-based starting column (in bytes) of the source code span.
|
||||||
|
pub(crate) start_col: u32,
|
||||||
|
/// 1-based ending line of the source code span.
|
||||||
|
pub(crate) end_line: u32,
|
||||||
|
/// 1-based ending column (in bytes) of the source code span. High bit must be unset.
|
||||||
|
pub(crate) end_col: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Coords {
|
||||||
|
/// Attaches a local file ID to these coordinates to produce an `ffi::CoverageSpan`.
|
||||||
|
pub(crate) fn make_coverage_span(&self, local_file_id: LocalFileId) -> ffi::CoverageSpan {
|
||||||
|
let &Self { start_line, start_col, end_line, end_col } = self;
|
||||||
|
let file_id = local_file_id.as_u32();
|
||||||
|
ffi::CoverageSpan { file_id, start_line, start_col, end_line, end_col }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts the span into its start line and column, and end line and column.
|
/// Converts the span into its start line and column, and end line and column.
|
||||||
///
|
///
|
||||||
/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
|
/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
|
||||||
/// the compiler, these column numbers are denoted in **bytes**, because that's what
|
/// the compiler, these column numbers are denoted in **bytes**, because that's what
|
||||||
/// LLVM's `llvm-cov` tool expects to see in coverage maps.
|
/// LLVM's `llvm-cov` tool expects to see in coverage maps.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the conversion failed for some reason. This shouldn't happen,
|
/// Returns `None` if the conversion failed for some reason. This should be uncommon,
|
||||||
/// but it's hard to rule out entirely (especially in the presence of complex macros
|
/// but it's hard to rule out entirely (especially in the presence of complex macros
|
||||||
/// or other expansions), and if it does happen then skipping a span or function is
|
/// or other expansions), and if it does happen then skipping a span or function is
|
||||||
/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
|
/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
|
||||||
pub(crate) fn make_coverage_span(
|
pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option<Coords> {
|
||||||
file_id: LocalFileId,
|
|
||||||
source_map: &SourceMap,
|
|
||||||
file: &SourceFile,
|
|
||||||
span: Span,
|
|
||||||
) -> Option<ffi::CoverageSpan> {
|
|
||||||
let span = ensure_non_empty_span(source_map, span)?;
|
let span = ensure_non_empty_span(source_map, span)?;
|
||||||
|
|
||||||
let lo = span.lo();
|
let lo = span.lo();
|
||||||
|
@ -44,8 +62,7 @@ pub(crate) fn make_coverage_span(
|
||||||
start_line = source_map.doctest_offset_line(&file.name, start_line);
|
start_line = source_map.doctest_offset_line(&file.name, start_line);
|
||||||
end_line = source_map.doctest_offset_line(&file.name, end_line);
|
end_line = source_map.doctest_offset_line(&file.name, end_line);
|
||||||
|
|
||||||
check_coverage_span(ffi::CoverageSpan {
|
check_coords(Coords {
|
||||||
file_id: file_id.as_u32(),
|
|
||||||
start_line: start_line as u32,
|
start_line: start_line as u32,
|
||||||
start_col: start_col as u32,
|
start_col: start_col as u32,
|
||||||
end_line: end_line as u32,
|
end_line: end_line as u32,
|
||||||
|
@ -80,8 +97,8 @@ fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
|
||||||
/// it will immediately exit with a fatal error. To prevent that from happening,
|
/// it will immediately exit with a fatal error. To prevent that from happening,
|
||||||
/// discard regions that are improperly ordered, or might be interpreted in a
|
/// discard regions that are improperly ordered, or might be interpreted in a
|
||||||
/// way that makes them improperly ordered.
|
/// way that makes them improperly ordered.
|
||||||
fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option<ffi::CoverageSpan> {
|
fn check_coords(coords: Coords) -> Option<Coords> {
|
||||||
let ffi::CoverageSpan { file_id: _, start_line, start_col, end_line, end_col } = cov_span;
|
let Coords { start_line, start_col, end_line, end_col } = coords;
|
||||||
|
|
||||||
// Line/column coordinates are supposed to be 1-based. If we ever emit
|
// Line/column coordinates are supposed to be 1-based. If we ever emit
|
||||||
// coordinates of 0, `llvm-cov` might misinterpret them.
|
// coordinates of 0, `llvm-cov` might misinterpret them.
|
||||||
|
@ -94,17 +111,17 @@ fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option<ffi::CoverageSpan>
|
||||||
let is_ordered = (start_line, start_col) <= (end_line, end_col);
|
let is_ordered = (start_line, start_col) <= (end_line, end_col);
|
||||||
|
|
||||||
if all_nonzero && end_col_has_high_bit_unset && is_ordered {
|
if all_nonzero && end_col_has_high_bit_unset && is_ordered {
|
||||||
Some(cov_span)
|
Some(coords)
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!(
|
||||||
?cov_span,
|
?coords,
|
||||||
?all_nonzero,
|
?all_nonzero,
|
||||||
?end_col_has_high_bit_unset,
|
?end_col_has_high_bit_unset,
|
||||||
?is_ordered,
|
?is_ordered,
|
||||||
"Skipping source region that would be misinterpreted or rejected by LLVM"
|
"Skipping source region that would be misinterpreted or rejected by LLVM"
|
||||||
);
|
);
|
||||||
// If this happens in a debug build, ICE to make it easier to notice.
|
// If this happens in a debug build, ICE to make it easier to notice.
|
||||||
debug_assert!(false, "Improper source region: {cov_span:?}");
|
debug_assert!(false, "Improper source region: {coords:?}");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2019,6 +2019,8 @@ unsafe extern "C" {
|
||||||
NumExpressions: size_t,
|
NumExpressions: size_t,
|
||||||
CodeRegions: *const crate::coverageinfo::ffi::CodeRegion,
|
CodeRegions: *const crate::coverageinfo::ffi::CodeRegion,
|
||||||
NumCodeRegions: size_t,
|
NumCodeRegions: size_t,
|
||||||
|
ExpansionRegions: *const crate::coverageinfo::ffi::ExpansionRegion,
|
||||||
|
NumExpansionRegions: size_t,
|
||||||
BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
|
BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
|
||||||
NumBranchRegions: size_t,
|
NumBranchRegions: size_t,
|
||||||
MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,
|
MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,
|
||||||
|
|
|
@ -93,7 +93,7 @@ const_eval_expected_inbounds_pointer =
|
||||||
}
|
}
|
||||||
|
|
||||||
const_eval_extern_static =
|
const_eval_extern_static =
|
||||||
cannot access extern static ({$did})
|
cannot access extern static `{$did}`
|
||||||
const_eval_extern_type_field = `extern type` field does not have a known offset
|
const_eval_extern_type_field = `extern type` field does not have a known offset
|
||||||
|
|
||||||
const_eval_fn_ptr_call =
|
const_eval_fn_ptr_call =
|
||||||
|
@ -381,7 +381,7 @@ const_eval_thread_local_access =
|
||||||
thread-local statics cannot be accessed at compile-time
|
thread-local statics cannot be accessed at compile-time
|
||||||
|
|
||||||
const_eval_thread_local_static =
|
const_eval_thread_local_static =
|
||||||
cannot access thread local static ({$did})
|
cannot access thread local static `{$did}`
|
||||||
const_eval_too_generic =
|
const_eval_too_generic =
|
||||||
encountered overly generic constant
|
encountered overly generic constant
|
||||||
const_eval_too_many_caller_args =
|
const_eval_too_many_caller_args =
|
||||||
|
|
|
@ -898,6 +898,7 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
||||||
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
|
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||||
use UnsupportedOpInfo::*;
|
use UnsupportedOpInfo::*;
|
||||||
|
|
||||||
|
@ -917,9 +918,9 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
||||||
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
|
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
|
||||||
diag.arg("ptr", ptr);
|
diag.arg("ptr", ptr);
|
||||||
}
|
}
|
||||||
ThreadLocalStatic(did) | ExternStatic(did) => {
|
ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| {
|
||||||
diag.arg("did", format!("{did:?}"));
|
diag.arg("did", tcx.def_path_str(did));
|
||||||
}
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2949,7 +2949,7 @@ impl<'hir> TraitItem<'hir> {
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
pub enum TraitFn<'hir> {
|
pub enum TraitFn<'hir> {
|
||||||
/// No default body in the trait, just a signature.
|
/// No default body in the trait, just a signature.
|
||||||
Required(&'hir [Ident]),
|
Required(&'hir [Option<Ident>]),
|
||||||
|
|
||||||
/// Both signature and body are provided in the trait.
|
/// Both signature and body are provided in the trait.
|
||||||
Provided(BodyId),
|
Provided(BodyId),
|
||||||
|
@ -3354,7 +3354,9 @@ pub struct BareFnTy<'hir> {
|
||||||
pub abi: ExternAbi,
|
pub abi: ExternAbi,
|
||||||
pub generic_params: &'hir [GenericParam<'hir>],
|
pub generic_params: &'hir [GenericParam<'hir>],
|
||||||
pub decl: &'hir FnDecl<'hir>,
|
pub decl: &'hir FnDecl<'hir>,
|
||||||
pub param_names: &'hir [Ident],
|
// `Option` because bare fn parameter names are optional. We also end up
|
||||||
|
// with `None` in some error cases, e.g. invalid parameter patterns.
|
||||||
|
pub param_names: &'hir [Option<Ident>],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
|
@ -4335,7 +4337,12 @@ impl ForeignItem<'_> {
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
pub enum ForeignItemKind<'hir> {
|
pub enum ForeignItemKind<'hir> {
|
||||||
/// A foreign function.
|
/// A foreign function.
|
||||||
Fn(FnSig<'hir>, &'hir [Ident], &'hir Generics<'hir>),
|
///
|
||||||
|
/// All argument idents are actually always present (i.e. `Some`), but
|
||||||
|
/// `&[Option<Ident>]` is used because of code paths shared with `TraitFn`
|
||||||
|
/// and `BareFnTy`. The sharing is due to all of these cases not allowing
|
||||||
|
/// arbitrary patterns for parameters.
|
||||||
|
Fn(FnSig<'hir>, &'hir [Option<Ident>], &'hir Generics<'hir>),
|
||||||
/// A foreign static item (`static ext: u8`).
|
/// A foreign static item (`static ext: u8`).
|
||||||
Static(&'hir Ty<'hir>, Mutability, Safety),
|
Static(&'hir Ty<'hir>, Mutability, Safety),
|
||||||
/// A foreign type.
|
/// A foreign type.
|
||||||
|
|
|
@ -655,7 +655,9 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
|
||||||
ForeignItemKind::Fn(ref sig, param_names, ref generics) => {
|
ForeignItemKind::Fn(ref sig, param_names, ref generics) => {
|
||||||
try_visit!(visitor.visit_generics(generics));
|
try_visit!(visitor.visit_generics(generics));
|
||||||
try_visit!(visitor.visit_fn_decl(sig.decl));
|
try_visit!(visitor.visit_fn_decl(sig.decl));
|
||||||
walk_list!(visitor, visit_ident, param_names.iter().copied());
|
for ident in param_names.iter().copied() {
|
||||||
|
visit_opt!(visitor, visit_ident, ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ForeignItemKind::Static(ref typ, _, _) => {
|
ForeignItemKind::Static(ref typ, _, _) => {
|
||||||
try_visit!(visitor.visit_ty_unambig(typ));
|
try_visit!(visitor.visit_ty_unambig(typ));
|
||||||
|
@ -1169,7 +1171,9 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
|
||||||
}
|
}
|
||||||
TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
|
TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
|
||||||
try_visit!(visitor.visit_fn_decl(sig.decl));
|
try_visit!(visitor.visit_fn_decl(sig.decl));
|
||||||
walk_list!(visitor, visit_ident, param_names.iter().copied());
|
for ident in param_names.iter().copied() {
|
||||||
|
visit_opt!(visitor, visit_ident, ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
|
TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
|
||||||
try_visit!(visitor.visit_fn(
|
try_visit!(visitor.visit_fn(
|
||||||
|
|
|
@ -1034,7 +1034,13 @@ fn report_trait_method_mismatch<'tcx>(
|
||||||
let span = tcx
|
let span = tcx
|
||||||
.hir_body_param_names(body)
|
.hir_body_param_names(body)
|
||||||
.zip(sig.decl.inputs.iter())
|
.zip(sig.decl.inputs.iter())
|
||||||
.map(|(param, ty)| param.span.to(ty.span))
|
.map(|(param_name, ty)| {
|
||||||
|
if let Some(param_name) = param_name {
|
||||||
|
param_name.span.to(ty.span)
|
||||||
|
} else {
|
||||||
|
ty.span
|
||||||
|
}
|
||||||
|
})
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or(impl_err_span);
|
.unwrap_or(impl_err_span);
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,10 @@
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
|
use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
|
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
|
||||||
TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
|
|
||||||
};
|
};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_span::def_id::{DefId, LocalDefId};
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
|
@ -356,13 +355,20 @@ fn orphan_check<'tcx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
OrphanCheckErr::NonLocalInputType(tys) => {
|
OrphanCheckErr::NonLocalInputType(tys) => {
|
||||||
let generics = tcx.generics_of(impl_def_id);
|
let tys = infcx.probe(|_| {
|
||||||
let tys = tys
|
// Map the unconstrained args back to their params,
|
||||||
.into_iter()
|
// ignoring any type unification errors.
|
||||||
.map(|(ty, is_target_ty)| {
|
for (arg, id_arg) in
|
||||||
(ty.fold_with(&mut TyVarReplacer { infcx: &infcx, generics }), is_target_ty)
|
std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id))
|
||||||
})
|
{
|
||||||
.collect();
|
let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq(
|
||||||
|
DefineOpaqueTypes::No,
|
||||||
|
arg,
|
||||||
|
id_arg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
infcx.resolve_vars_if_possible(tys)
|
||||||
|
});
|
||||||
OrphanCheckErr::NonLocalInputType(tys)
|
OrphanCheckErr::NonLocalInputType(tys)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -536,40 +542,3 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TyVarReplacer<'cx, 'tcx> {
|
|
||||||
infcx: &'cx InferCtxt<'tcx>,
|
|
||||||
generics: &'tcx ty::Generics,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> {
|
|
||||||
fn cx(&self) -> TyCtxt<'tcx> {
|
|
||||||
self.infcx.tcx
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
|
|
||||||
return ty;
|
|
||||||
}
|
|
||||||
let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
|
|
||||||
return ty.super_fold_with(self);
|
|
||||||
};
|
|
||||||
let origin = self.infcx.type_var_origin(vid);
|
|
||||||
if let Some(def_id) = origin.param_def_id {
|
|
||||||
// The generics of an `impl` don't have a parent, we can index directly.
|
|
||||||
let index = self.generics.param_def_id_to_index[&def_id];
|
|
||||||
let name = self.generics.own_params[index as usize].name;
|
|
||||||
|
|
||||||
Ty::new_param(self.infcx.tcx, index, name)
|
|
||||||
} else {
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
|
||||||
if !ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
|
|
||||||
return ct;
|
|
||||||
}
|
|
||||||
ct.super_fold_with(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,10 +49,12 @@ pub(crate) fn validate_cmse_abi<'tcx>(
|
||||||
Ok(Err(index)) => {
|
Ok(Err(index)) => {
|
||||||
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
|
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
|
||||||
// ^^^^^^
|
// ^^^^^^
|
||||||
let span = bare_fn_ty.param_names[index]
|
let span = if let Some(ident) = bare_fn_ty.param_names[index] {
|
||||||
.span
|
ident.span.to(bare_fn_ty.decl.inputs[index].span)
|
||||||
.to(bare_fn_ty.decl.inputs[index].span)
|
} else {
|
||||||
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
|
bare_fn_ty.decl.inputs[index].span
|
||||||
|
}
|
||||||
|
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
|
||||||
let plural = bare_fn_ty.param_names.len() - index != 1;
|
let plural = bare_fn_ty.param_names.len() - index != 1;
|
||||||
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi });
|
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi });
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
//! the definitions in this file have equivalents in `rustc_ast_pretty`.
|
//! the definitions in this file have equivalents in `rustc_ast_pretty`.
|
||||||
|
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
|
#![feature(let_chains)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
|
@ -898,7 +899,7 @@ impl<'a> State<'a> {
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
m: &hir::FnSig<'_>,
|
m: &hir::FnSig<'_>,
|
||||||
generics: &hir::Generics<'_>,
|
generics: &hir::Generics<'_>,
|
||||||
arg_names: &[Ident],
|
arg_names: &[Option<Ident>],
|
||||||
body_id: Option<hir::BodyId>,
|
body_id: Option<hir::BodyId>,
|
||||||
) {
|
) {
|
||||||
self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id);
|
self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id);
|
||||||
|
@ -2121,7 +2122,7 @@ impl<'a> State<'a> {
|
||||||
header: hir::FnHeader,
|
header: hir::FnHeader,
|
||||||
name: Option<Symbol>,
|
name: Option<Symbol>,
|
||||||
generics: &hir::Generics<'_>,
|
generics: &hir::Generics<'_>,
|
||||||
arg_names: &[Ident],
|
arg_names: &[Option<Ident>],
|
||||||
body_id: Option<hir::BodyId>,
|
body_id: Option<hir::BodyId>,
|
||||||
) {
|
) {
|
||||||
self.print_fn_header_info(header);
|
self.print_fn_header_info(header);
|
||||||
|
@ -2141,7 +2142,7 @@ impl<'a> State<'a> {
|
||||||
s.print_implicit_self(&decl.implicit_self);
|
s.print_implicit_self(&decl.implicit_self);
|
||||||
} else {
|
} else {
|
||||||
if let Some(arg_name) = arg_names.get(i) {
|
if let Some(arg_name) = arg_names.get(i) {
|
||||||
if arg_name.name != kw::Empty {
|
if let Some(arg_name) = arg_name {
|
||||||
s.word(arg_name.to_string());
|
s.word(arg_name.to_string());
|
||||||
s.word(":");
|
s.word(":");
|
||||||
s.space();
|
s.space();
|
||||||
|
@ -2451,7 +2452,7 @@ impl<'a> State<'a> {
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
name: Option<Symbol>,
|
name: Option<Symbol>,
|
||||||
generic_params: &[hir::GenericParam<'_>],
|
generic_params: &[hir::GenericParam<'_>],
|
||||||
arg_names: &[Ident],
|
arg_names: &[Option<Ident>],
|
||||||
) {
|
) {
|
||||||
self.ibox(INDENT_UNIT);
|
self.ibox(INDENT_UNIT);
|
||||||
self.print_formal_generic_params(generic_params);
|
self.print_formal_generic_params(generic_params);
|
||||||
|
|
|
@ -164,11 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
|
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
|
||||||
|
|
||||||
let interior = self.next_ty_var(expr_span);
|
let interior = self.next_ty_var(expr_span);
|
||||||
self.deferred_coroutine_interiors.borrow_mut().push((
|
self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior));
|
||||||
expr_def_id,
|
|
||||||
body.id(),
|
|
||||||
interior,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Coroutines that come from coroutine closures have not yet determined
|
// Coroutines that come from coroutine closures have not yet determined
|
||||||
// their kind ty, so make a fresh infer var which will be constrained
|
// their kind ty, so make a fresh infer var which will be constrained
|
||||||
|
|
|
@ -633,18 +633,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let coroutines = std::mem::take(&mut *self.deferred_coroutine_interiors.borrow_mut());
|
let coroutines = std::mem::take(&mut *self.deferred_coroutine_interiors.borrow_mut());
|
||||||
debug!(?coroutines);
|
debug!(?coroutines);
|
||||||
|
|
||||||
for &(expr_def_id, body_id, interior) in coroutines.iter() {
|
let mut obligations = vec![];
|
||||||
debug!(?expr_def_id);
|
|
||||||
|
for &(coroutine_def_id, interior) in coroutines.iter() {
|
||||||
|
debug!(?coroutine_def_id);
|
||||||
|
|
||||||
// Create the `CoroutineWitness` type that we will unify with `interior`.
|
// Create the `CoroutineWitness` type that we will unify with `interior`.
|
||||||
let args = ty::GenericArgs::identity_for_item(
|
let args = ty::GenericArgs::identity_for_item(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
|
self.tcx.typeck_root_def_id(coroutine_def_id.to_def_id()),
|
||||||
);
|
);
|
||||||
let witness = Ty::new_coroutine_witness(self.tcx, expr_def_id.to_def_id(), args);
|
let witness = Ty::new_coroutine_witness(self.tcx, coroutine_def_id.to_def_id(), args);
|
||||||
|
|
||||||
// Unify `interior` with `witness` and collect all the resulting obligations.
|
// Unify `interior` with `witness` and collect all the resulting obligations.
|
||||||
let span = self.tcx.hir_body(body_id).value.span;
|
let span = self.tcx.hir_body_owned_by(coroutine_def_id).value.span;
|
||||||
let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else {
|
let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else {
|
||||||
span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind())
|
span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind())
|
||||||
};
|
};
|
||||||
|
@ -653,15 +655,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// Will never define opaque types, as all we do is instantiate a type variable.
|
// Will never define opaque types, as all we do is instantiate a type variable.
|
||||||
.eq(DefineOpaqueTypes::Yes, interior, witness)
|
.eq(DefineOpaqueTypes::Yes, interior, witness)
|
||||||
.expect("Failed to unify coroutine interior type");
|
.expect("Failed to unify coroutine interior type");
|
||||||
let mut obligations = ok.obligations;
|
|
||||||
|
|
||||||
// Also collect the obligations that were unstalled by this unification.
|
obligations.extend(ok.obligations);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Use a real visitor for unstalled obligations in the new solver.
|
||||||
|
if !coroutines.is_empty() {
|
||||||
obligations
|
obligations
|
||||||
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
|
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
|
||||||
|
|
||||||
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause));
|
|
||||||
self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend(obligations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.typeck_results
|
||||||
|
.borrow_mut()
|
||||||
|
.coroutine_stalled_predicates
|
||||||
|
.extend(obligations.into_iter().map(|o| (o.predicate, o.cause)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
|
|
@ -1135,7 +1135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&& self.tcx.def_kind(fn_def_id).is_fn_like()
|
&& self.tcx.def_kind(fn_def_id).is_fn_like()
|
||||||
&& let self_implicit =
|
&& let self_implicit =
|
||||||
matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
|
matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
|
||||||
&& let Some(arg) =
|
&& let Some(Some(arg)) =
|
||||||
self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit)
|
self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit)
|
||||||
&& arg.name != kw::SelfLower
|
&& arg.name != kw::SelfLower
|
||||||
{
|
{
|
||||||
|
@ -2678,7 +2678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?;
|
params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?;
|
||||||
debug_assert_eq!(params.len(), fn_inputs.len());
|
debug_assert_eq!(params.len(), fn_inputs.len());
|
||||||
Some((
|
Some((
|
||||||
fn_inputs.zip(params.iter().map(|¶m| FnParam::Name(param))).collect(),
|
fn_inputs.zip(params.iter().map(|&ident| FnParam::Name(ident))).collect(),
|
||||||
generics,
|
generics,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -2709,14 +2709,20 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum FnParam<'hir> {
|
enum FnParam<'hir> {
|
||||||
Param(&'hir hir::Param<'hir>),
|
Param(&'hir hir::Param<'hir>),
|
||||||
Name(Ident),
|
Name(Option<Ident>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnParam<'_> {
|
impl FnParam<'_> {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Self::Param(param) => param.span,
|
Self::Param(param) => param.span,
|
||||||
Self::Name(ident) => ident.span,
|
Self::Name(ident) => {
|
||||||
|
if let Some(ident) = ident {
|
||||||
|
ident.span
|
||||||
|
} else {
|
||||||
|
DUMMY_SP
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2733,7 +2739,8 @@ impl FnParam<'_> {
|
||||||
Some(ident.name)
|
Some(ident.name)
|
||||||
}
|
}
|
||||||
FnParam::Name(ident)
|
FnParam::Name(ident)
|
||||||
if ident.name != kw::Empty && ident.name != kw::Underscore =>
|
if let Some(ident) = ident
|
||||||
|
&& ident.name != kw::Underscore =>
|
||||||
{
|
{
|
||||||
Some(ident.name)
|
Some(ident.name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3766,7 +3766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
let self_first_arg = match method {
|
let self_first_arg = match method {
|
||||||
hir::TraitFn::Required([ident, ..]) => {
|
hir::TraitFn::Required([ident, ..]) => {
|
||||||
ident.name == kw::SelfLower
|
matches!(ident, Some(Ident { name: kw::SelfLower, .. }))
|
||||||
}
|
}
|
||||||
hir::TraitFn::Provided(body_id) => {
|
hir::TraitFn::Provided(body_id) => {
|
||||||
self.tcx.hir_body(*body_id).params.first().is_some_and(
|
self.tcx.hir_body(*body_id).params.first().is_some_and(
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub(crate) struct TypeckRootCtxt<'tcx> {
|
||||||
|
|
||||||
pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, HirId)>>,
|
pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, HirId)>>,
|
||||||
|
|
||||||
pub(super) deferred_coroutine_interiors: RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>)>>,
|
pub(super) deferred_coroutine_interiors: RefCell<Vec<(LocalDefId, Ty<'tcx>)>>,
|
||||||
|
|
||||||
pub(super) deferred_repeat_expr_checks:
|
pub(super) deferred_repeat_expr_checks:
|
||||||
RefCell<Vec<(&'tcx hir::Expr<'tcx>, Ty<'tcx>, ty::Const<'tcx>)>>,
|
RefCell<Vec<(&'tcx hir::Expr<'tcx>, Ty<'tcx>, ty::Const<'tcx>)>>,
|
||||||
|
|
|
@ -424,7 +424,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
||||||
if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(pnames)) = item.kind {
|
if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(pnames)) = item.kind {
|
||||||
self.check_snake_case(cx, "trait method", &item.ident);
|
self.check_snake_case(cx, "trait method", &item.ident);
|
||||||
for param_name in pnames {
|
for param_name in pnames {
|
||||||
self.check_snake_case(cx, "variable", param_name);
|
if let Some(param_name) = param_name {
|
||||||
|
self.check_snake_case(cx, "variable", param_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,13 @@ struct LLVMRustCoverageCodeRegion {
|
||||||
LLVMRustCounter Count;
|
LLVMRustCounter Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Must match the layout of
|
||||||
|
// `rustc_codegen_llvm::coverageinfo::ffi::ExpansionRegion`.
|
||||||
|
struct LLVMRustCoverageExpansionRegion {
|
||||||
|
LLVMRustCoverageSpan Span;
|
||||||
|
uint32_t ExpandedFileID;
|
||||||
|
};
|
||||||
|
|
||||||
// Must match the layout of
|
// Must match the layout of
|
||||||
// `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`.
|
// `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`.
|
||||||
struct LLVMRustCoverageBranchRegion {
|
struct LLVMRustCoverageBranchRegion {
|
||||||
|
@ -151,6 +158,8 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
||||||
const unsigned *VirtualFileMappingIDs, size_t NumVirtualFileMappingIDs,
|
const unsigned *VirtualFileMappingIDs, size_t NumVirtualFileMappingIDs,
|
||||||
const LLVMRustCounterExpression *RustExpressions, size_t NumExpressions,
|
const LLVMRustCounterExpression *RustExpressions, size_t NumExpressions,
|
||||||
const LLVMRustCoverageCodeRegion *CodeRegions, size_t NumCodeRegions,
|
const LLVMRustCoverageCodeRegion *CodeRegions, size_t NumCodeRegions,
|
||||||
|
const LLVMRustCoverageExpansionRegion *ExpansionRegions,
|
||||||
|
size_t NumExpansionRegions,
|
||||||
const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions,
|
const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions,
|
||||||
const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
|
const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
|
||||||
size_t NumMCDCBranchRegions,
|
size_t NumMCDCBranchRegions,
|
||||||
|
@ -179,6 +188,13 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
||||||
Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd));
|
Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expansion regions:
|
||||||
|
for (const auto &Region : ArrayRef(ExpansionRegions, NumExpansionRegions)) {
|
||||||
|
MappingRegions.push_back(coverage::CounterMappingRegion::makeExpansion(
|
||||||
|
Region.Span.FileID, Region.ExpandedFileID, Region.Span.LineStart,
|
||||||
|
Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd));
|
||||||
|
}
|
||||||
|
|
||||||
// Branch regions:
|
// Branch regions:
|
||||||
for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) {
|
for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) {
|
||||||
MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
|
MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
|
||||||
|
|
|
@ -1318,7 +1318,7 @@ impl<'a> CrateMetadataRef<'a> {
|
||||||
.expect("argument names not encoded for a function")
|
.expect("argument names not encoded for a function")
|
||||||
.decode((self, sess))
|
.decode((self, sess))
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.is_some_and(|ident| ident.name == kw::SelfLower)
|
.is_some_and(|ident| matches!(ident, Some(Ident { name: kw::SelfLower, .. })))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_associated_item_or_field_def_ids(self, id: DefIndex) -> impl Iterator<Item = DefId> {
|
fn get_associated_item_or_field_def_ids(self, id: DefIndex) -> impl Iterator<Item = DefId> {
|
||||||
|
|
|
@ -443,7 +443,7 @@ define_tables! {
|
||||||
rendered_const: Table<DefIndex, LazyValue<String>>,
|
rendered_const: Table<DefIndex, LazyValue<String>>,
|
||||||
rendered_precise_capturing_args: Table<DefIndex, LazyArray<PreciseCapturingArgKind<Symbol, Symbol>>>,
|
rendered_precise_capturing_args: Table<DefIndex, LazyArray<PreciseCapturingArgKind<Symbol, Symbol>>>,
|
||||||
asyncness: Table<DefIndex, ty::Asyncness>,
|
asyncness: Table<DefIndex, ty::Asyncness>,
|
||||||
fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
|
fn_arg_names: Table<DefIndex, LazyArray<Option<Ident>>>,
|
||||||
coroutine_kind: Table<DefIndex, hir::CoroutineKind>,
|
coroutine_kind: Table<DefIndex, hir::CoroutineKind>,
|
||||||
coroutine_for_closure: Table<DefIndex, RawDefId>,
|
coroutine_for_closure: Table<DefIndex, RawDefId>,
|
||||||
coroutine_by_move_body_def_id: Table<DefIndex, RawDefId>,
|
coroutine_by_move_body_def_id: Table<DefIndex, RawDefId>,
|
||||||
|
|
|
@ -280,11 +280,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> {
|
pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator<Item = Option<Ident>> {
|
||||||
self.hir_body(id).params.iter().map(|param| match param.pat.kind {
|
self.hir_body(id).params.iter().map(|param| match param.pat.kind {
|
||||||
PatKind::Binding(_, _, ident, _) => ident,
|
PatKind::Binding(_, _, ident, _) => Some(ident),
|
||||||
PatKind::Wild => Ident::new(kw::Underscore, param.pat.span),
|
PatKind::Wild => Some(Ident::new(kw::Underscore, param.pat.span)),
|
||||||
_ => Ident::empty(),
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1410,7 +1410,7 @@ rustc_queries! {
|
||||||
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::Ident] {
|
query fn_arg_names(def_id: DefId) -> &'tcx [Option<rustc_span::Ident>] {
|
||||||
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ use std::ops::ControlFlow;
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
use rustc_type_ir::inherent::*;
|
use rustc_type_ir::inherent::*;
|
||||||
use rustc_type_ir::{
|
use rustc_type_ir::{
|
||||||
self as ty, InferCtxtLike, Interner, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
self as ty, InferCtxtLike, Interner, TrivialTypeTraversalImpls, TypeVisitable,
|
||||||
|
TypeVisitableExt, TypeVisitor,
|
||||||
};
|
};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
|
@ -95,6 +96,8 @@ pub fn trait_ref_is_local_or_fundamental<I: Interner>(tcx: I, trait_ref: ty::Tra
|
||||||
trait_ref.def_id.is_local() || tcx.trait_is_fundamental(trait_ref.def_id)
|
trait_ref.def_id.is_local() || tcx.trait_is_fundamental(trait_ref.def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TrivialTypeTraversalImpls! { IsFirstInputType, }
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum IsFirstInputType {
|
pub enum IsFirstInputType {
|
||||||
No,
|
No,
|
||||||
|
|
|
@ -17,6 +17,7 @@ use rustc_ast::{
|
||||||
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
|
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
|
||||||
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
|
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
|
||||||
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
|
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
|
||||||
|
YieldKind,
|
||||||
};
|
};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
|
@ -1310,6 +1311,15 @@ impl<'a> Parser<'a> {
|
||||||
return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
|
return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse a postfix `yield`.
|
||||||
|
if self.eat_keyword(exp!(Yield)) {
|
||||||
|
let yield_span = self.prev_token.span;
|
||||||
|
self.psess.gated_spans.gate(sym::yield_expr, yield_span);
|
||||||
|
return Ok(
|
||||||
|
self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let fn_span_lo = self.token.span;
|
let fn_span_lo = self.token.span;
|
||||||
let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
|
let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
|
||||||
self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);
|
self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);
|
||||||
|
@ -1884,7 +1894,7 @@ impl<'a> Parser<'a> {
|
||||||
/// Parse `"yield" expr?`.
|
/// Parse `"yield" expr?`.
|
||||||
fn parse_expr_yield(&mut self) -> PResult<'a, P<Expr>> {
|
fn parse_expr_yield(&mut self) -> PResult<'a, P<Expr>> {
|
||||||
let lo = self.prev_token.span;
|
let lo = self.prev_token.span;
|
||||||
let kind = ExprKind::Yield(self.parse_expr_opt()?);
|
let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));
|
||||||
let span = lo.to(self.prev_token.span);
|
let span = lo.to(self.prev_token.span);
|
||||||
self.psess.gated_spans.gate(sym::yield_expr, span);
|
self.psess.gated_spans.gate(sym::yield_expr, span);
|
||||||
let expr = self.mk_expr(span, kind);
|
let expr = self.mk_expr(span, kind);
|
||||||
|
|
|
@ -2217,12 +2217,11 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
.delegation_fn_sigs
|
.delegation_fn_sigs
|
||||||
.get(&def_id)
|
.get(&def_id)
|
||||||
.is_some_and(|sig| sig.has_self),
|
.is_some_and(|sig| sig.has_self),
|
||||||
None => self
|
None => {
|
||||||
.r
|
self.r.tcx.fn_arg_names(def_id).first().is_some_and(|&ident| {
|
||||||
.tcx
|
matches!(ident, Some(Ident { name: kw::SelfLower, .. }))
|
||||||
.fn_arg_names(def_id)
|
})
|
||||||
.first()
|
}
|
||||||
.is_some_and(|ident| ident.name == kw::SelfLower),
|
|
||||||
};
|
};
|
||||||
if has_self {
|
if has_self {
|
||||||
return Some(AssocSuggestion::MethodWithSelf { called });
|
return Some(AssocSuggestion::MethodWithSelf { called });
|
||||||
|
|
|
@ -2082,6 +2082,12 @@ fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str) -> ! {
|
||||||
let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`"));
|
let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`"));
|
||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
diag.help(format!("valid print requests are: {prints}"));
|
diag.help(format!("valid print requests are: {prints}"));
|
||||||
|
|
||||||
|
if req == "lints" {
|
||||||
|
diag.help(format!("use `-Whelp` to print a list of lints"));
|
||||||
|
}
|
||||||
|
|
||||||
|
diag.help(format!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information"));
|
||||||
diag.emit()
|
diag.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1992,13 +1992,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, ident)| {
|
.map(|(i, ident)| {
|
||||||
if ident.name.is_empty()
|
if let Some(ident) = ident
|
||||||
|| ident.name == kw::Underscore
|
&& !matches!(ident, Ident { name: kw::Underscore | kw::SelfLower, .. })
|
||||||
|| ident.name == kw::SelfLower
|
|
||||||
{
|
{
|
||||||
format!("arg{i}")
|
|
||||||
} else {
|
|
||||||
format!("{ident}")
|
format!("{ident}")
|
||||||
|
} else {
|
||||||
|
format!("arg{i}")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
/// Used for types that are `Copy` and which **do not care arena
|
/// Used for types that are `Copy` and which **do not care arena
|
||||||
/// allocated data** (i.e., don't need to be folded).
|
/// allocated data** (i.e., don't need to be folded).
|
||||||
|
#[macro_export]
|
||||||
macro_rules! TrivialTypeTraversalImpls {
|
macro_rules! TrivialTypeTraversalImpls {
|
||||||
($($ty:ty,)+) => {
|
($($ty:ty,)+) => {
|
||||||
$(
|
$(
|
||||||
impl<I: $crate::Interner> $crate::fold::TypeFoldable<I> for $ty {
|
impl<I: $crate::Interner> $crate::TypeFoldable<I> for $ty {
|
||||||
fn try_fold_with<F: $crate::fold::FallibleTypeFolder<I>>(
|
fn try_fold_with<F: $crate::FallibleTypeFolder<I>>(
|
||||||
self,
|
self,
|
||||||
_: &mut F,
|
_: &mut F,
|
||||||
) -> ::std::result::Result<Self, F::Error> {
|
) -> ::std::result::Result<Self, F::Error> {
|
||||||
|
@ -12,7 +13,7 @@ macro_rules! TrivialTypeTraversalImpls {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fold_with<F: $crate::fold::TypeFolder<I>>(
|
fn fold_with<F: $crate::TypeFolder<I>>(
|
||||||
self,
|
self,
|
||||||
_: &mut F,
|
_: &mut F,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -20,14 +21,14 @@ macro_rules! TrivialTypeTraversalImpls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: $crate::Interner> $crate::visit::TypeVisitable<I> for $ty {
|
impl<I: $crate::Interner> $crate::TypeVisitable<I> for $ty {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_with<F: $crate::visit::TypeVisitor<I>>(
|
fn visit_with<F: $crate::TypeVisitor<I>>(
|
||||||
&self,
|
&self,
|
||||||
_: &mut F)
|
_: &mut F)
|
||||||
-> F::Result
|
-> F::Result
|
||||||
{
|
{
|
||||||
<F::Result as rustc_ast_ir::visit::VisitorResult>::output()
|
<F::Result as $crate::VisitorResult>::output()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
|
|
|
@ -23,7 +23,7 @@ Here's the list of the notification groups:
|
||||||
- [ARM](./arm.md)
|
- [ARM](./arm.md)
|
||||||
- [Cleanup Crew](./cleanup-crew.md)
|
- [Cleanup Crew](./cleanup-crew.md)
|
||||||
- [Emscripten](./emscripten.md)
|
- [Emscripten](./emscripten.md)
|
||||||
- [LLVM](./llvm.md)
|
- [LLVM Icebreakers](./llvm.md)
|
||||||
- [RISC-V](./risc-v.md)
|
- [RISC-V](./risc-v.md)
|
||||||
- [WASI](./wasi.md)
|
- [WASI](./wasi.md)
|
||||||
- [WebAssembly](./wasm.md)
|
- [WebAssembly](./wasm.md)
|
||||||
|
@ -83,7 +83,7 @@ group. For example:
|
||||||
@rustbot ping arm
|
@rustbot ping arm
|
||||||
@rustbot ping cleanup-crew
|
@rustbot ping cleanup-crew
|
||||||
@rustbot ping emscripten
|
@rustbot ping emscripten
|
||||||
@rustbot ping llvm
|
@rustbot ping icebreakers-llvm
|
||||||
@rustbot ping risc-v
|
@rustbot ping risc-v
|
||||||
@rustbot ping wasi
|
@rustbot ping wasi
|
||||||
@rustbot ping wasm
|
@rustbot ping wasm
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
# LLVM Notification group
|
# LLVM Icebreakers Notification group
|
||||||
|
|
||||||
**Github Label:** [A-LLVM] <br>
|
**Github Label:** [A-LLVM] <br>
|
||||||
**Ping command:** `@rustbot ping llvm`
|
**Ping command:** `@rustbot ping icebreakers-llvm`
|
||||||
|
|
||||||
[A-LLVM]: https://github.com/rust-lang/rust/labels/A-LLVM
|
[A-LLVM]: https://github.com/rust-lang/rust/labels/A-LLVM
|
||||||
|
|
||||||
The "LLVM Notification Group" are focused on bugs that center around LLVM.
|
*Note*: this notification group is *not* the same as the LLVM working group
|
||||||
These bugs often arise because of LLVM optimizations gone awry, or as
|
(WG-llvm).
|
||||||
the result of an LLVM upgrade. The goal here is:
|
|
||||||
|
The "LLVM Icebreakers Notification Group" are focused on bugs that center around
|
||||||
|
LLVM. These bugs often arise because of LLVM optimizations gone awry, or as the
|
||||||
|
result of an LLVM upgrade. The goal here is:
|
||||||
|
|
||||||
- to determine whether the bug is a result of us generating invalid LLVM IR,
|
- to determine whether the bug is a result of us generating invalid LLVM IR,
|
||||||
or LLVM misoptimizing;
|
or LLVM misoptimizing;
|
||||||
|
|
|
@ -1088,7 +1088,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib
|
||||||
|
|
||||||
enum FunctionArgs<'tcx> {
|
enum FunctionArgs<'tcx> {
|
||||||
Body(hir::BodyId),
|
Body(hir::BodyId),
|
||||||
Names(&'tcx [Ident]),
|
Names(&'tcx [Option<Ident>]),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_function<'tcx>(
|
fn clean_function<'tcx>(
|
||||||
|
@ -1117,13 +1117,15 @@ fn clean_function<'tcx>(
|
||||||
fn clean_args_from_types_and_names<'tcx>(
|
fn clean_args_from_types_and_names<'tcx>(
|
||||||
cx: &mut DocContext<'tcx>,
|
cx: &mut DocContext<'tcx>,
|
||||||
types: &[hir::Ty<'tcx>],
|
types: &[hir::Ty<'tcx>],
|
||||||
names: &[Ident],
|
names: &[Option<Ident>],
|
||||||
) -> Arguments {
|
) -> Arguments {
|
||||||
fn nonempty_name(ident: &Ident) -> Option<Symbol> {
|
fn nonempty_name(ident: &Option<Ident>) -> Option<Symbol> {
|
||||||
if ident.name == kw::Underscore || ident.name == kw::Empty {
|
if let Some(ident) = ident
|
||||||
None
|
&& ident.name != kw::Underscore
|
||||||
} else {
|
{
|
||||||
Some(ident.name)
|
Some(ident.name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1216,11 +1218,11 @@ fn clean_poly_fn_sig<'tcx>(
|
||||||
.iter()
|
.iter()
|
||||||
.map(|t| Argument {
|
.map(|t| Argument {
|
||||||
type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None),
|
type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None),
|
||||||
name: names
|
name: if let Some(Some(ident)) = names.next() {
|
||||||
.next()
|
ident.name
|
||||||
.map(|i| i.name)
|
} else {
|
||||||
.filter(|i| !i.is_empty())
|
kw::Underscore
|
||||||
.unwrap_or(kw::Underscore),
|
},
|
||||||
is_const: false,
|
is_const: false,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc_hir::hir_id::OwnerId;
|
||||||
use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef};
|
use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_span::symbol::{Ident, Symbol, kw};
|
use rustc_span::symbol::{Ident, kw};
|
||||||
|
|
||||||
use super::RENAMED_FUNCTION_PARAMS;
|
use super::RENAMED_FUNCTION_PARAMS;
|
||||||
|
|
||||||
|
@ -51,22 +51,33 @@ struct RenamedFnArgs(Vec<(Span, String)>);
|
||||||
impl RenamedFnArgs {
|
impl RenamedFnArgs {
|
||||||
/// Comparing between an iterator of default names and one with current names,
|
/// Comparing between an iterator of default names and one with current names,
|
||||||
/// then collect the ones that got renamed.
|
/// then collect the ones that got renamed.
|
||||||
fn new<I, T>(default_names: &mut I, current_names: &mut T) -> Self
|
fn new<I1, I2>(default_idents: &mut I1, current_idents: &mut I2) -> Self
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Ident>,
|
I1: Iterator<Item = Option<Ident>>,
|
||||||
T: Iterator<Item = Ident>,
|
I2: Iterator<Item = Option<Ident>>,
|
||||||
{
|
{
|
||||||
let mut renamed: Vec<(Span, String)> = vec![];
|
let mut renamed: Vec<(Span, String)> = vec![];
|
||||||
|
|
||||||
debug_assert!(default_names.size_hint() == current_names.size_hint());
|
debug_assert!(default_idents.size_hint() == current_idents.size_hint());
|
||||||
while let (Some(def_name), Some(cur_name)) = (default_names.next(), current_names.next()) {
|
while let (Some(default_ident), Some(current_ident)) =
|
||||||
let current_name = cur_name.name;
|
(default_idents.next(), current_idents.next())
|
||||||
let default_name = def_name.name;
|
{
|
||||||
if is_unused_or_empty_symbol(current_name) || is_unused_or_empty_symbol(default_name) {
|
let has_name_to_check = |ident: Option<Ident>| {
|
||||||
continue;
|
if let Some(ident) = ident
|
||||||
}
|
&& ident.name != kw::Underscore
|
||||||
if current_name != default_name {
|
&& !ident.name.as_str().starts_with('_')
|
||||||
renamed.push((cur_name.span, default_name.to_string()));
|
{
|
||||||
|
Some(ident)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(default_ident) = has_name_to_check(default_ident)
|
||||||
|
&& let Some(current_ident) = has_name_to_check(current_ident)
|
||||||
|
&& default_ident.name != current_ident.name
|
||||||
|
{
|
||||||
|
renamed.push((current_ident.span, default_ident.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,14 +94,6 @@ impl RenamedFnArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_unused_or_empty_symbol(symbol: Symbol) -> bool {
|
|
||||||
// FIXME: `body_param_names` currently returning empty symbols for `wild` as well,
|
|
||||||
// so we need to check if the symbol is empty first.
|
|
||||||
// Therefore the check of whether it's equal to [`kw::Underscore`] has no use for now,
|
|
||||||
// but it would be nice to keep it here just to be future-proof.
|
|
||||||
symbol.is_empty() || symbol == kw::Underscore || symbol.as_str().starts_with('_')
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item.
|
/// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item.
|
||||||
fn trait_item_def_id_of_impl(items: &[ImplItemRef], target: OwnerId) -> Option<DefId> {
|
fn trait_item_def_id_of_impl(items: &[ImplItemRef], target: OwnerId) -> Option<DefId> {
|
||||||
items.iter().find_map(|item| {
|
items.iter().find_map(|item| {
|
||||||
|
|
|
@ -189,7 +189,7 @@ fn check_fn_inner<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
sig: &'tcx FnSig<'_>,
|
sig: &'tcx FnSig<'_>,
|
||||||
body: Option<BodyId>,
|
body: Option<BodyId>,
|
||||||
trait_sig: Option<&[Ident]>,
|
trait_sig: Option<&[Option<Ident>]>,
|
||||||
generics: &'tcx Generics<'_>,
|
generics: &'tcx Generics<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
report_extra_lifetimes: bool,
|
report_extra_lifetimes: bool,
|
||||||
|
@ -264,7 +264,7 @@ fn could_use_elision<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
func: &'tcx FnDecl<'_>,
|
func: &'tcx FnDecl<'_>,
|
||||||
body: Option<BodyId>,
|
body: Option<BodyId>,
|
||||||
trait_sig: Option<&[Ident]>,
|
trait_sig: Option<&[Option<Ident>]>,
|
||||||
named_generics: &'tcx [GenericParam<'_>],
|
named_generics: &'tcx [GenericParam<'_>],
|
||||||
msrv: Msrv,
|
msrv: Msrv,
|
||||||
) -> Option<(Vec<LocalDefId>, Vec<Lifetime>)> {
|
) -> Option<(Vec<LocalDefId>, Vec<Lifetime>)> {
|
||||||
|
@ -310,7 +310,7 @@ fn could_use_elision<'tcx>(
|
||||||
let body = cx.tcx.hir_body(body_id);
|
let body = cx.tcx.hir_body(body_id);
|
||||||
|
|
||||||
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
|
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
|
||||||
if non_elidable_self_type(cx, func, first_ident, msrv) {
|
if non_elidable_self_type(cx, func, Some(first_ident), msrv) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,8 +384,8 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet<LocalDefI
|
||||||
}
|
}
|
||||||
|
|
||||||
// elision doesn't work for explicit self types before Rust 1.81, see rust-lang/rust#69064
|
// elision doesn't work for explicit self types before Rust 1.81, see rust-lang/rust#69064
|
||||||
fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>, msrv: Msrv) -> bool {
|
fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Option<Ident>>, msrv: Msrv) -> bool {
|
||||||
if let Some(ident) = ident
|
if let Some(Some(ident)) = ident
|
||||||
&& ident.name == kw::SelfLower
|
&& ident.name == kw::SelfLower
|
||||||
&& !func.implicit_self.has_implicit_self()
|
&& !func.implicit_self.has_implicit_self()
|
||||||
&& let Some(self_ty) = func.inputs.first()
|
&& let Some(self_ty) = func.inputs.first()
|
||||||
|
|
|
@ -201,7 +201,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||||
(Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt),
|
(Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt),
|
||||||
(Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb),
|
(Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb),
|
||||||
(TryBlock(l), TryBlock(r)) => eq_block(l, r),
|
(TryBlock(l), TryBlock(r)) => eq_block(l, r),
|
||||||
(Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()),
|
(Yield(l), Yield(r)) => eq_expr_opt(l.expr(), r.expr()) && l.same_kind(r),
|
||||||
|
(Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()),
|
||||||
(Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()),
|
(Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()),
|
||||||
(Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()),
|
(Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()),
|
||||||
(Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
|
(Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
|
||||||
|
@ -688,7 +689,7 @@ pub fn eq_generics(l: &Generics, r: &Generics) -> bool {
|
||||||
|
|
||||||
pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
|
pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
|
||||||
use WherePredicateKind::*;
|
use WherePredicateKind::*;
|
||||||
over(&l.attrs, &r.attrs, eq_attr)
|
over(&l.attrs, &r.attrs, eq_attr)
|
||||||
&& match (&l.kind, &r.kind) {
|
&& match (&l.kind, &r.kind) {
|
||||||
(BoundPredicate(l), BoundPredicate(r)) => {
|
(BoundPredicate(l), BoundPredicate(r)) => {
|
||||||
over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
|
over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
|
||||||
|
|
|
@ -192,6 +192,7 @@ enum ChainItemKind {
|
||||||
StructField(symbol::Ident),
|
StructField(symbol::Ident),
|
||||||
TupleField(symbol::Ident, bool),
|
TupleField(symbol::Ident, bool),
|
||||||
Await,
|
Await,
|
||||||
|
Yield,
|
||||||
Comment(String, CommentPosition),
|
Comment(String, CommentPosition),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +204,7 @@ impl ChainItemKind {
|
||||||
| ChainItemKind::StructField(..)
|
| ChainItemKind::StructField(..)
|
||||||
| ChainItemKind::TupleField(..)
|
| ChainItemKind::TupleField(..)
|
||||||
| ChainItemKind::Await
|
| ChainItemKind::Await
|
||||||
|
| ChainItemKind::Yield
|
||||||
| ChainItemKind::Comment(..) => false,
|
| ChainItemKind::Comment(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,6 +259,10 @@ impl ChainItemKind {
|
||||||
let span = mk_sp(nested.span.hi(), expr.span.hi());
|
let span = mk_sp(nested.span.hi(), expr.span.hi());
|
||||||
(ChainItemKind::Await, span)
|
(ChainItemKind::Await, span)
|
||||||
}
|
}
|
||||||
|
ast::ExprKind::Yield(ast::YieldKind::Postfix(ref nested)) => {
|
||||||
|
let span = mk_sp(nested.span.hi(), expr.span.hi());
|
||||||
|
(ChainItemKind::Yield, span)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return (
|
return (
|
||||||
ChainItemKind::Parent {
|
ChainItemKind::Parent {
|
||||||
|
@ -306,6 +312,7 @@ impl Rewrite for ChainItem {
|
||||||
rewrite_ident(context, ident)
|
rewrite_ident(context, ident)
|
||||||
),
|
),
|
||||||
ChainItemKind::Await => ".await".to_owned(),
|
ChainItemKind::Await => ".await".to_owned(),
|
||||||
|
ChainItemKind::Yield => ".yield".to_owned(),
|
||||||
ChainItemKind::Comment(ref comment, _) => {
|
ChainItemKind::Comment(ref comment, _) => {
|
||||||
rewrite_comment(comment, false, shape, context.config)?
|
rewrite_comment(comment, false, shape, context.config)?
|
||||||
}
|
}
|
||||||
|
@ -508,7 +515,8 @@ impl Chain {
|
||||||
}),
|
}),
|
||||||
ast::ExprKind::Field(ref subexpr, _)
|
ast::ExprKind::Field(ref subexpr, _)
|
||||||
| ast::ExprKind::Try(ref subexpr)
|
| ast::ExprKind::Try(ref subexpr)
|
||||||
| ast::ExprKind::Await(ref subexpr, _) => Some(SubExpr {
|
| ast::ExprKind::Await(ref subexpr, _)
|
||||||
|
| ast::ExprKind::Yield(ast::YieldKind::Postfix(ref subexpr)) => Some(SubExpr {
|
||||||
expr: Self::convert_try(subexpr, context),
|
expr: Self::convert_try(subexpr, context),
|
||||||
is_method_call_receiver: false,
|
is_method_call_receiver: false,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -221,7 +221,7 @@ pub(crate) fn format_expr(
|
||||||
Ok(format!("break{id_str}"))
|
Ok(format!("break{id_str}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprKind::Yield(ref opt_expr) => {
|
ast::ExprKind::Yield(ast::YieldKind::Prefix(ref opt_expr)) => {
|
||||||
if let Some(ref expr) = *opt_expr {
|
if let Some(ref expr) = *opt_expr {
|
||||||
rewrite_unary_prefix(context, "yield ", &**expr, shape)
|
rewrite_unary_prefix(context, "yield ", &**expr, shape)
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,7 +243,8 @@ pub(crate) fn format_expr(
|
||||||
ast::ExprKind::Try(..)
|
ast::ExprKind::Try(..)
|
||||||
| ast::ExprKind::Field(..)
|
| ast::ExprKind::Field(..)
|
||||||
| ast::ExprKind::MethodCall(..)
|
| ast::ExprKind::MethodCall(..)
|
||||||
| ast::ExprKind::Await(_, _) => rewrite_chain(expr, context, shape),
|
| ast::ExprKind::Await(_, _)
|
||||||
|
| ast::ExprKind::Yield(ast::YieldKind::Postfix(_)) => rewrite_chain(expr, context, shape),
|
||||||
ast::ExprKind::MacCall(ref mac) => {
|
ast::ExprKind::MacCall(ref mac) => {
|
||||||
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|_| {
|
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|_| {
|
||||||
wrap_str(
|
wrap_str(
|
||||||
|
|
|
@ -4,7 +4,7 @@ use rustc_ast::ast::{
|
||||||
self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility,
|
self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility,
|
||||||
VisibilityKind,
|
VisibilityKind,
|
||||||
};
|
};
|
||||||
use rustc_ast::ptr;
|
use rustc_ast::{YieldKind, ptr};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_span::{BytePos, LocalExpnId, Span, Symbol, SyntaxContext, sym, symbol};
|
use rustc_span::{BytePos, LocalExpnId, Span, Symbol, SyntaxContext, sym, symbol};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
@ -485,7 +485,9 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
|
||||||
| ast::ExprKind::Index(_, ref expr, _)
|
| ast::ExprKind::Index(_, ref expr, _)
|
||||||
| ast::ExprKind::Unary(_, ref expr)
|
| ast::ExprKind::Unary(_, ref expr)
|
||||||
| ast::ExprKind::Try(ref expr)
|
| ast::ExprKind::Try(ref expr)
|
||||||
| ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr),
|
| ast::ExprKind::Yield(YieldKind::Prefix(Some(ref expr))) => {
|
||||||
|
is_block_expr(context, expr, repr)
|
||||||
|
}
|
||||||
ast::ExprKind::Closure(ref closure) => is_block_expr(context, &closure.body, repr),
|
ast::ExprKind::Closure(ref closure) => is_block_expr(context, &closure.body, repr),
|
||||||
// This can only be a string lit
|
// This can only be a string lit
|
||||||
ast::ExprKind::Lit(_) => {
|
ast::ExprKind::Lit(_) => {
|
||||||
|
@ -515,7 +517,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
|
||||||
| ast::ExprKind::Tup(..)
|
| ast::ExprKind::Tup(..)
|
||||||
| ast::ExprKind::Use(..)
|
| ast::ExprKind::Use(..)
|
||||||
| ast::ExprKind::Type(..)
|
| ast::ExprKind::Type(..)
|
||||||
| ast::ExprKind::Yield(None)
|
| ast::ExprKind::Yield(..)
|
||||||
| ast::ExprKind::Underscore => false,
|
| ast::ExprKind::Underscore => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/tools/rustfmt/tests/target/postfix-yield.rs
Normal file
17
src/tools/rustfmt/tests/target/postfix-yield.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// This demonstrates a proposed alternate or additional option of having yield in postfix position.
|
||||||
|
//@ edition: 2024
|
||||||
|
|
||||||
|
#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)]
|
||||||
|
|
||||||
|
use std::ops::{Coroutine, CoroutineState};
|
||||||
|
use std::pin::pin;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut coro = pin!(
|
||||||
|
#[coroutine]
|
||||||
|
|_: i32| {
|
||||||
|
let x = 1.yield;
|
||||||
|
(x + 2).await;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
//@ known-bug: #132826
|
|
||||||
pub trait MyTrait {
|
|
||||||
type Item;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> MyTrait for Vec<K> {
|
|
||||||
type Item = Vec<K>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> From<Vec<K>> for <Vec<K> as MyTrait>::Item {}
|
|
15
tests/pretty/postfix-yield.rs
Normal file
15
tests/pretty/postfix-yield.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// This demonstrates a proposed alternate or additional option of having yield in postfix position.
|
||||||
|
//@ edition: 2024
|
||||||
|
//@ pp-exact
|
||||||
|
|
||||||
|
#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)]
|
||||||
|
|
||||||
|
use std::ops::{Coroutine, CoroutineState};
|
||||||
|
use std::pin::pin;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut gn = gen { yield 1; 2.yield; (1 + 2).yield; };
|
||||||
|
|
||||||
|
let mut coro =
|
||||||
|
pin!(#[coroutine] |_: i32| { let x = 1.yield; (x + 2).yield; });
|
||||||
|
}
|
17
tests/ui/coherence/orphan-check-error-reporting-ty-var.rs
Normal file
17
tests/ui/coherence/orphan-check-error-reporting-ty-var.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Regression test for #132826.
|
||||||
|
|
||||||
|
// Make sure we don't try to resolve the variable `K1` in the generics of the impl
|
||||||
|
// (which only has `K2`).
|
||||||
|
|
||||||
|
pub trait MyTrait {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K1> MyTrait for Vec<K1> {
|
||||||
|
type Item = Vec<K1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K2> From<Vec<K2>> for <Vec<K2> as MyTrait>::Item {}
|
||||||
|
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,16 @@
|
||||||
|
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
||||||
|
--> $DIR/orphan-check-error-reporting-ty-var.rs:14:1
|
||||||
|
|
|
||||||
|
LL | impl<K2> From<Vec<K2>> for <Vec<K2> as MyTrait>::Item {}
|
||||||
|
| ^^^^^^^^^-------------^^^^^--------------------------
|
||||||
|
| | |
|
||||||
|
| | `Vec` is not defined in the current crate
|
||||||
|
| `Vec` is not defined in the current crate
|
||||||
|
|
|
||||||
|
= note: impl doesn't have any local type before any uncovered type parameters
|
||||||
|
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||||
|
= note: define and implement a trait or new type instead
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0117`.
|
|
@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/extern-static.rs:11:25
|
--> $DIR/extern-static.rs:11:25
|
||||||
|
|
|
|
||||||
LL | unsafe { let _val = DATA; }
|
LL | unsafe { let _val = DATA; }
|
||||||
| ^^^^ cannot access extern static (DefId(0:4 ~ extern_static[c41e]::{extern#0}::DATA))
|
| ^^^^ cannot access extern static `DATA`
|
||||||
|
|
||||||
error[E0080]: could not evaluate static initializer
|
error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/extern-static.rs:16:14
|
--> $DIR/extern-static.rs:16:14
|
||||||
|
|
|
|
||||||
LL | unsafe { DATA = 0; }
|
LL | unsafe { DATA = 0; }
|
||||||
| ^^^^^^^^ cannot access extern static (DefId(0:4 ~ extern_static[c41e]::{extern#0}::DATA))
|
| ^^^^^^^^ cannot access extern static `DATA`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/tls.rs:11:25
|
--> $DIR/tls.rs:11:25
|
||||||
|
|
|
|
||||||
LL | unsafe { let _val = A; }
|
LL | unsafe { let _val = A; }
|
||||||
| ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A))
|
| ^ cannot access thread local static `A`
|
||||||
|
|
||||||
error[E0080]: could not evaluate static initializer
|
error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/tls.rs:20:26
|
--> $DIR/tls.rs:20:26
|
||||||
|
|
|
|
||||||
LL | unsafe { let _val = &A; }
|
LL | unsafe { let _val = &A; }
|
||||||
| ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A))
|
| ^ cannot access thread local static `A`
|
||||||
|
|
||||||
warning: skipping const checks
|
warning: skipping const checks
|
||||||
|
|
|
|
||||||
|
|
34
tests/ui/coroutine/postfix-yield.rs
Normal file
34
tests/ui/coroutine/postfix-yield.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// This demonstrates a proposed alternate or additional option of having yield in postfix position.
|
||||||
|
|
||||||
|
//@ run-pass
|
||||||
|
//@ edition: 2024
|
||||||
|
|
||||||
|
#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)]
|
||||||
|
|
||||||
|
use std::ops::{Coroutine, CoroutineState};
|
||||||
|
use std::pin::pin;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// generators (i.e. yield doesn't return anything useful)
|
||||||
|
let mut gn = gen {
|
||||||
|
yield 1;
|
||||||
|
2.yield;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(gn.next(), Some(1));
|
||||||
|
assert_eq!(gn.next(), Some(2));
|
||||||
|
assert_eq!(gn.next(), None);
|
||||||
|
|
||||||
|
//coroutines (i.e. yield returns something useful)
|
||||||
|
let mut coro = pin!(
|
||||||
|
#[coroutine]
|
||||||
|
|_: i32| {
|
||||||
|
let x = 1.yield;
|
||||||
|
(x + 2).yield;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(coro.as_mut().resume(0), CoroutineState::Yielded(1));
|
||||||
|
assert_eq!(coro.as_mut().resume(2), CoroutineState::Yielded(4));
|
||||||
|
assert_eq!(coro.as_mut().resume(3), CoroutineState::Complete(()));
|
||||||
|
}
|
2
tests/ui/extern/issue-28324.stderr
vendored
2
tests/ui/extern/issue-28324.stderr
vendored
|
@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/issue-28324.rs:5:23
|
--> $DIR/issue-28324.rs:5:23
|
||||||
|
|
|
|
||||||
LL | pub static BAZ: u32 = *&error_message_count;
|
LL | pub static BAZ: u32 = *&error_message_count;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ cannot access extern static (DefId(0:4 ~ issue_28324[8ec4]::{extern#0}::error_message_count))
|
| ^^^^^^^^^^^^^^^^^^^^^ cannot access extern static `error_message_count`
|
||||||
|
|
||||||
error[E0133]: use of extern static is unsafe and requires unsafe function or block
|
error[E0133]: use of extern static is unsafe and requires unsafe function or block
|
||||||
--> $DIR/issue-28324.rs:5:25
|
--> $DIR/issue-28324.rs:5:25
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
error: unknown print request: `yyyy`
|
error: unknown print request: `yyyy`
|
||||||
|
|
|
|
||||||
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
|
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
|
||||||
|
= help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information
|
||||||
|
|
||||||
|
|
2
tests/ui/rustc-print-info-issue-138612.rs
Normal file
2
tests/ui/rustc-print-info-issue-138612.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
//@ check-fail
|
||||||
|
//@ compile-flags: /dev/null --print lints
|
6
tests/ui/rustc-print-info-issue-138612.stderr
Normal file
6
tests/ui/rustc-print-info-issue-138612.stderr
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
error: unknown print request: `lints`
|
||||||
|
|
|
||||||
|
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
|
||||||
|
= help: use `-Whelp` to print a list of lints
|
||||||
|
= help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information
|
||||||
|
|
|
@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/issue-14227.rs:4:21
|
--> $DIR/issue-14227.rs:4:21
|
||||||
|
|
|
|
||||||
LL | static CRASH: u32 = symbol;
|
LL | static CRASH: u32 = symbol;
|
||||||
| ^^^^^^ cannot access extern static (DefId(0:4 ~ issue_14227[1133]::{extern#0}::symbol))
|
| ^^^^^^ cannot access extern static `symbol`
|
||||||
|
|
||||||
error[E0133]: use of extern static is unsafe and requires unsafe function or block
|
error[E0133]: use of extern static is unsafe and requires unsafe function or block
|
||||||
--> $DIR/issue-14227.rs:4:21
|
--> $DIR/issue-14227.rs:4:21
|
||||||
|
|
|
@ -47,7 +47,6 @@ add_labels = ["S-waiting-on-review"]
|
||||||
[glacier]
|
[glacier]
|
||||||
|
|
||||||
[ping.icebreakers-llvm]
|
[ping.icebreakers-llvm]
|
||||||
alias = ["llvm", "llvms"]
|
|
||||||
message = """\
|
message = """\
|
||||||
Hey LLVM ICE-breakers! This bug has been identified as a good
|
Hey LLVM ICE-breakers! This bug has been identified as a good
|
||||||
"LLVM ICE-breaking candidate". In case it's useful, here are some
|
"LLVM ICE-breaking candidate". In case it's useful, here are some
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue