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:
bors 2025-03-20 22:35:15 +00:00
commit eda7820be5
62 changed files with 499 additions and 240 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

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

View 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() {}

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

@ -0,0 +1,2 @@
//@ check-fail
//@ compile-flags: /dev/null --print lints

View 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

View file

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

View file

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