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>),
/// A `yield`, with an optional value to be yielded.
Yield(Option<P<Expr>>),
Yield(YieldKind),
/// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever),
/// with an optional value to be returned.
@ -1903,6 +1903,44 @@ pub enum MatchKind {
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.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
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) => {
vis.visit_expr(expr);
}
ExprKind::Yield(expr) => {
visit_opt(expr, |expr| vis.visit_expr(expr));
ExprKind::Yield(kind) => {
let expr = kind.expr_mut();
if let Some(expr) = expr {
vis.visit_expr(expr);
}
}
ExprKind::Try(expr) => vis.visit_expr(expr),
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), _)
| Ret(Some(e))
| Unary(_, e)
| Yield(Some(e))
| Yeet(Some(e))
| Become(e) => {
expr = e;
}
Yield(kind) => match kind.expr() {
Some(e) => expr = e,
None => break None,
},
Closure(closure) => {
expr = &closure.body;
}
@ -217,7 +220,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
Break(_, None)
| Range(_, None, _)
| Ret(None)
| Yield(None)
| Array(_)
| Call(_, _)
| MethodCall(_)
@ -237,7 +239,9 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
| Yeet(None)
| UnsafeBinderCast(..)
| 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));
walk_list!(visitor, visit_ident, fields.iter());
}
ExprKind::Yield(optional_expression) => {
visit_opt!(visitor, visit_expr, optional_expression);
ExprKind::Yield(kind) => {
visit_opt!(visitor, visit_expr, kind.expr());
}
ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)),
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),

View File

@ -351,7 +351,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
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::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 {
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
PatKind::Wild => Ident::new(kw::Underscore, self.lower_span(param.pat.span)),
PatKind::Ident(_, ident, _) => {
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(
param.pat.span,
"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::{
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
FormatDebugHex, FormatSign, FormatTrait, token,
FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
};
use crate::pp::Breaks::Inconsistent;
@ -761,7 +761,7 @@ impl<'a> State<'a> {
self.print_expr(e, FixupContext::default());
self.pclose();
}
ast::ExprKind::Yield(e) => {
ast::ExprKind::Yield(YieldKind::Prefix(e)) => {
self.word("yield");
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) => {
self.print_expr_cond_paren(
e,

View File

@ -2514,12 +2514,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let ty::Tuple(params) = tupled_params.kind() else { return };
// Find the first argument with a matching type, get its name
let Some((_, this_name)) =
params.iter().zip(tcx.hir_body_param_names(closure.body)).find(|(param_ty, name)| {
let Some(this_name) = params.iter().zip(tcx.hir_body_param_names(closure.body)).find_map(
|(param_ty, name)| {
// FIXME: also support deref for stuff like `Rc` arguments
param_ty.peel_refs() == local_ty && name != &Ident::empty()
})
else {
if param_ty.peel_refs() == local_ty { name } else { None }
},
) else {
return;
};
@ -3787,7 +3787,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
method_args,
*fn_span,
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}`"));

View File

@ -1029,7 +1029,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
method_args,
*fn_span,
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 {

View File

@ -146,6 +146,7 @@ pub(crate) struct CoverageSpan {
#[derive(Clone, Debug, Default)]
pub(crate) struct Regions {
pub(crate) code_regions: Vec<CodeRegion>,
pub(crate) expansion_regions: Vec<ExpansionRegion>,
pub(crate) branch_regions: Vec<BranchRegion>,
pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>,
pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>,
@ -154,10 +155,16 @@ pub(crate) struct Regions {
impl Regions {
/// Returns true if none of this structure's tables contain any regions.
pub(crate) fn has_no_regions(&self) -> bool {
let Self { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
self;
let Self {
code_regions,
expansion_regions,
branch_regions,
mcdc_branch_regions,
mcdc_decision_regions,
} = self;
code_regions.is_empty()
&& expansion_regions.is_empty()
&& branch_regions.is_empty()
&& mcdc_branch_regions.is_empty()
&& mcdc_decision_regions.is_empty()
@ -172,6 +179,14 @@ pub(crate) struct CodeRegion {
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`.
#[derive(Clone, Debug)]
#[repr(C)]

View File

@ -63,8 +63,18 @@ pub(crate) fn write_function_mappings_to_buffer(
expressions: &[ffi::CounterExpression],
regions: &ffi::Regions,
) -> Vec<u8> {
let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
regions;
let ffi::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::LLVMRustCoverageWriteFunctionMappingsToBuffer(
virtual_file_mapping.as_ptr(),
@ -73,6 +83,8 @@ pub(crate) fn write_function_mappings_to_buffer(
expressions.len(),
code_regions.as_ptr(),
code_regions.len(),
expansion_regions.as_ptr(),
expansion_regions.len(),
branch_regions.as_ptr(),
branch_regions.len(),
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.
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 } =
&mut covfun.regions;
let make_cov_span =
|span: Span| spans::make_coverage_span(local_file_id, source_map, &source_file, span);
// In rare cases, _all_ of a function's spans are discarded, and coverage
// codegen needs to handle that gracefully to avoid #133606.
// It's hard for tests to trigger this organically, so instead we set
// `-Zcoverage-options=discard-all-spans-in-codegen` to force it to occur.
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
// form suitable for FFI.
@ -140,17 +150,8 @@ fn fill_region_tables<'tcx>(
ffi::Counter::from_term(term)
};
// Convert the `Span` into coordinates that we can pass to LLVM, or
// discard the span if conversion fails. In rare, cases _all_ of a
// 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;
}
let Some(coords) = make_coords(span) else { continue };
let cov_span = coords.make_coverage_span(local_file_id);
match *kind {
MappingKind::Code { bcb } => {

View File

@ -5,22 +5,40 @@ use tracing::debug;
use crate::coverageinfo::ffi;
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.
///
/// 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
/// 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
/// 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.
pub(crate) fn make_coverage_span(
file_id: LocalFileId,
source_map: &SourceMap,
file: &SourceFile,
span: Span,
) -> Option<ffi::CoverageSpan> {
pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option<Coords> {
let span = ensure_non_empty_span(source_map, span)?;
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);
end_line = source_map.doctest_offset_line(&file.name, end_line);
check_coverage_span(ffi::CoverageSpan {
file_id: file_id.as_u32(),
check_coords(Coords {
start_line: start_line as u32,
start_col: start_col 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,
/// discard regions that are improperly ordered, or might be interpreted in a
/// way that makes them improperly ordered.
fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option<ffi::CoverageSpan> {
let ffi::CoverageSpan { file_id: _, start_line, start_col, end_line, end_col } = cov_span;
fn check_coords(coords: Coords) -> Option<Coords> {
let Coords { start_line, start_col, end_line, end_col } = coords;
// Line/column coordinates are supposed to be 1-based. If we ever emit
// 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);
if all_nonzero && end_col_has_high_bit_unset && is_ordered {
Some(cov_span)
Some(coords)
} else {
debug!(
?cov_span,
?coords,
?all_nonzero,
?end_col_has_high_bit_unset,
?is_ordered,
"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.
debug_assert!(false, "Improper source region: {cov_span:?}");
debug_assert!(false, "Improper source region: {coords:?}");
None
}
}

View File

@ -2019,6 +2019,8 @@ unsafe extern "C" {
NumExpressions: size_t,
CodeRegions: *const crate::coverageinfo::ffi::CodeRegion,
NumCodeRegions: size_t,
ExpansionRegions: *const crate::coverageinfo::ffi::ExpansionRegion,
NumExpansionRegions: size_t,
BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
NumBranchRegions: size_t,
MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,

View File

@ -93,7 +93,7 @@ const_eval_expected_inbounds_pointer =
}
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_fn_ptr_call =
@ -381,7 +381,7 @@ const_eval_thread_local_access =
thread-local statics cannot be accessed at compile-time
const_eval_thread_local_static =
cannot access thread local static ({$did})
cannot access thread local static `{$did}`
const_eval_too_generic =
encountered overly generic constant
const_eval_too_many_caller_args =

View File

@ -898,6 +898,7 @@ impl ReportErrorExt for UnsupportedOpInfo {
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
}
}
fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
use UnsupportedOpInfo::*;
@ -917,9 +918,9 @@ impl ReportErrorExt for UnsupportedOpInfo {
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
diag.arg("ptr", ptr);
}
ThreadLocalStatic(did) | ExternStatic(did) => {
diag.arg("did", format!("{did:?}"));
}
ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| {
diag.arg("did", tcx.def_path_str(did));
}),
}
}
}

View File

@ -2949,7 +2949,7 @@ impl<'hir> TraitItem<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TraitFn<'hir> {
/// 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.
Provided(BodyId),
@ -3354,7 +3354,9 @@ pub struct BareFnTy<'hir> {
pub abi: ExternAbi,
pub generic_params: &'hir [GenericParam<'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)]
@ -4335,7 +4337,12 @@ impl ForeignItem<'_> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum ForeignItemKind<'hir> {
/// 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`).
Static(&'hir Ty<'hir>, Mutability, Safety),
/// 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) => {
try_visit!(visitor.visit_generics(generics));
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, _, _) => {
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)) => {
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)) => {
try_visit!(visitor.visit_fn(

View File

@ -1034,7 +1034,13 @@ fn report_trait_method_mismatch<'tcx>(
let span = tcx
.hir_body_param_names(body)
.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()
.unwrap_or(impl_err_span);

View File

@ -3,11 +3,10 @@
use rustc_data_structures::fx::FxIndexSet;
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_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::{DefId, LocalDefId};
@ -356,13 +355,20 @@ fn orphan_check<'tcx>(
})
}
OrphanCheckErr::NonLocalInputType(tys) => {
let generics = tcx.generics_of(impl_def_id);
let tys = tys
.into_iter()
.map(|(ty, is_target_ty)| {
(ty.fold_with(&mut TyVarReplacer { infcx: &infcx, generics }), is_target_ty)
})
.collect();
let tys = infcx.probe(|_| {
// Map the unconstrained args back to their params,
// ignoring any type unification errors.
for (arg, id_arg) in
std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id))
{
let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq(
DefineOpaqueTypes::No,
arg,
id_arg,
);
}
infcx.resolve_vars_if_possible(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)) => {
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
// ^^^^^^
let span = bare_fn_ty.param_names[index]
.span
.to(bare_fn_ty.decl.inputs[index].span)
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
let span = if let Some(ident) = bare_fn_ty.param_names[index] {
ident.span.to(bare_fn_ty.decl.inputs[index].span)
} else {
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;
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`.
// tidy-alphabetical-start
#![feature(let_chains)]
#![recursion_limit = "256"]
// tidy-alphabetical-end
@ -898,7 +899,7 @@ impl<'a> State<'a> {
ident: Ident,
m: &hir::FnSig<'_>,
generics: &hir::Generics<'_>,
arg_names: &[Ident],
arg_names: &[Option<Ident>],
body_id: Option<hir::BodyId>,
) {
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,
name: Option<Symbol>,
generics: &hir::Generics<'_>,
arg_names: &[Ident],
arg_names: &[Option<Ident>],
body_id: Option<hir::BodyId>,
) {
self.print_fn_header_info(header);
@ -2141,7 +2142,7 @@ impl<'a> State<'a> {
s.print_implicit_self(&decl.implicit_self);
} else {
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(":");
s.space();
@ -2451,7 +2452,7 @@ impl<'a> State<'a> {
decl: &hir::FnDecl<'_>,
name: Option<Symbol>,
generic_params: &[hir::GenericParam<'_>],
arg_names: &[Ident],
arg_names: &[Option<Ident>],
) {
self.ibox(INDENT_UNIT);
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 interior = self.next_ty_var(expr_span);
self.deferred_coroutine_interiors.borrow_mut().push((
expr_def_id,
body.id(),
interior,
));
self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior));
// Coroutines that come from coroutine closures have not yet determined
// 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());
debug!(?coroutines);
for &(expr_def_id, body_id, interior) in coroutines.iter() {
debug!(?expr_def_id);
let mut obligations = vec![];
for &(coroutine_def_id, interior) in coroutines.iter() {
debug!(?coroutine_def_id);
// Create the `CoroutineWitness` type that we will unify with `interior`.
let args = ty::GenericArgs::identity_for_item(
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.
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 {
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.
.eq(DefineOpaqueTypes::Yes, interior, witness)
.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
.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")]

View File

@ -1135,7 +1135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self.tcx.def_kind(fn_def_id).is_fn_like()
&& let self_implicit =
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)
&& 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)?;
debug_assert_eq!(params.len(), fn_inputs.len());
Some((
fn_inputs.zip(params.iter().map(|&param| FnParam::Name(param))).collect(),
fn_inputs.zip(params.iter().map(|&ident| FnParam::Name(ident))).collect(),
generics,
))
}
@ -2709,14 +2709,20 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> {
#[derive(Clone, Copy)]
enum FnParam<'hir> {
Param(&'hir hir::Param<'hir>),
Name(Ident),
Name(Option<Ident>),
}
impl FnParam<'_> {
fn span(&self) -> Span {
match self {
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)
}
FnParam::Name(ident)
if ident.name != kw::Empty && ident.name != kw::Underscore =>
if let Some(ident) = ident
&& ident.name != kw::Underscore =>
{
Some(ident.name)
}

View File

@ -3766,7 +3766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
let self_first_arg = match method {
hir::TraitFn::Required([ident, ..]) => {
ident.name == kw::SelfLower
matches!(ident, Some(Ident { name: kw::SelfLower, .. }))
}
hir::TraitFn::Provided(body_id) => {
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_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:
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 {
self.check_snake_case(cx, "trait method", &item.ident);
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;
};
// Must match the layout of
// `rustc_codegen_llvm::coverageinfo::ffi::ExpansionRegion`.
struct LLVMRustCoverageExpansionRegion {
LLVMRustCoverageSpan Span;
uint32_t ExpandedFileID;
};
// Must match the layout of
// `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`.
struct LLVMRustCoverageBranchRegion {
@ -151,6 +158,8 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
const unsigned *VirtualFileMappingIDs, size_t NumVirtualFileMappingIDs,
const LLVMRustCounterExpression *RustExpressions, size_t NumExpressions,
const LLVMRustCoverageCodeRegion *CodeRegions, size_t NumCodeRegions,
const LLVMRustCoverageExpansionRegion *ExpansionRegions,
size_t NumExpansionRegions,
const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions,
const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
size_t NumMCDCBranchRegions,
@ -179,6 +188,13 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
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:
for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) {
MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(

View File

@ -1318,7 +1318,7 @@ impl<'a> CrateMetadataRef<'a> {
.expect("argument names not encoded for a function")
.decode((self, sess))
.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> {

View File

@ -443,7 +443,7 @@ define_tables! {
rendered_const: Table<DefIndex, LazyValue<String>>,
rendered_precise_capturing_args: Table<DefIndex, LazyArray<PreciseCapturingArgKind<Symbol, Symbol>>>,
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_for_closure: 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 {
PatKind::Binding(_, _, ident, _) => ident,
PatKind::Wild => Ident::new(kw::Underscore, param.pat.span),
_ => Ident::empty(),
PatKind::Binding(_, _, ident, _) => Some(ident),
PatKind::Wild => Some(Ident::new(kw::Underscore, param.pat.span)),
_ => None,
})
}

View File

@ -1410,7 +1410,7 @@ rustc_queries! {
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) }
separate_provide_extern
}

View File

@ -4,7 +4,8 @@ use std::ops::ControlFlow;
use derive_where::derive_where;
use rustc_type_ir::inherent::*;
use rustc_type_ir::{
self as ty, InferCtxtLike, Interner, TypeVisitable, TypeVisitableExt, TypeVisitor,
self as ty, InferCtxtLike, Interner, TrivialTypeTraversalImpls, TypeVisitable,
TypeVisitableExt, TypeVisitor,
};
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)
}
TrivialTypeTraversalImpls! { IsFirstInputType, }
#[derive(Debug, Copy, Clone)]
pub enum IsFirstInputType {
No,

View File

@ -17,6 +17,7 @@ use rustc_ast::{
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
YieldKind,
};
use rustc_ast_pretty::pprust;
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);
}
// 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 mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);
@ -1884,7 +1894,7 @@ impl<'a> Parser<'a> {
/// Parse `"yield" expr?`.
fn parse_expr_yield(&mut self) -> PResult<'a, P<Expr>> {
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);
self.psess.gated_spans.gate(sym::yield_expr, span);
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
.get(&def_id)
.is_some_and(|sig| sig.has_self),
None => self
.r
.tcx
.fn_arg_names(def_id)
.first()
.is_some_and(|ident| ident.name == kw::SelfLower),
None => {
self.r.tcx.fn_arg_names(def_id).first().is_some_and(|&ident| {
matches!(ident, Some(Ident { name: kw::SelfLower, .. }))
})
}
};
if has_self {
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}`"));
#[allow(rustc::diagnostic_outside_of_impl)]
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()
}

View File

@ -1992,13 +1992,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.iter()
.enumerate()
.map(|(i, ident)| {
if ident.name.is_empty()
|| ident.name == kw::Underscore
|| ident.name == kw::SelfLower
if let Some(ident) = ident
&& !matches!(ident, Ident { name: kw::Underscore | kw::SelfLower, .. })
{
format!("arg{i}")
} else {
format!("{ident}")
} else {
format!("arg{i}")
}
})
.collect();

View File

@ -1,10 +1,11 @@
/// Used for types that are `Copy` and which **do not care arena
/// allocated data** (i.e., don't need to be folded).
#[macro_export]
macro_rules! TrivialTypeTraversalImpls {
($($ty:ty,)+) => {
$(
impl<I: $crate::Interner> $crate::fold::TypeFoldable<I> for $ty {
fn try_fold_with<F: $crate::fold::FallibleTypeFolder<I>>(
impl<I: $crate::Interner> $crate::TypeFoldable<I> for $ty {
fn try_fold_with<F: $crate::FallibleTypeFolder<I>>(
self,
_: &mut F,
) -> ::std::result::Result<Self, F::Error> {
@ -12,7 +13,7 @@ macro_rules! TrivialTypeTraversalImpls {
}
#[inline]
fn fold_with<F: $crate::fold::TypeFolder<I>>(
fn fold_with<F: $crate::TypeFolder<I>>(
self,
_: &mut F,
) -> 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]
fn visit_with<F: $crate::visit::TypeVisitor<I>>(
fn visit_with<F: $crate::TypeVisitor<I>>(
&self,
_: &mut F)
-> 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)
- [Cleanup Crew](./cleanup-crew.md)
- [Emscripten](./emscripten.md)
- [LLVM](./llvm.md)
- [LLVM Icebreakers](./llvm.md)
- [RISC-V](./risc-v.md)
- [WASI](./wasi.md)
- [WebAssembly](./wasm.md)
@ -83,7 +83,7 @@ group. For example:
@rustbot ping arm
@rustbot ping cleanup-crew
@rustbot ping emscripten
@rustbot ping llvm
@rustbot ping icebreakers-llvm
@rustbot ping risc-v
@rustbot ping wasi
@rustbot ping wasm

View File

@ -1,13 +1,16 @@
# LLVM Notification group
# LLVM Icebreakers Notification group
**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
The "LLVM 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:
*Note*: this notification group is *not* the same as the LLVM working group
(WG-llvm).
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,
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> {
Body(hir::BodyId),
Names(&'tcx [Ident]),
Names(&'tcx [Option<Ident>]),
}
fn clean_function<'tcx>(
@ -1117,13 +1117,15 @@ fn clean_function<'tcx>(
fn clean_args_from_types_and_names<'tcx>(
cx: &mut DocContext<'tcx>,
types: &[hir::Ty<'tcx>],
names: &[Ident],
names: &[Option<Ident>],
) -> Arguments {
fn nonempty_name(ident: &Ident) -> Option<Symbol> {
if ident.name == kw::Underscore || ident.name == kw::Empty {
None
} else {
fn nonempty_name(ident: &Option<Ident>) -> Option<Symbol> {
if let Some(ident) = ident
&& ident.name != kw::Underscore
{
Some(ident.name)
} else {
None
}
}
@ -1216,11 +1218,11 @@ fn clean_poly_fn_sig<'tcx>(
.iter()
.map(|t| Argument {
type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None),
name: names
.next()
.map(|i| i.name)
.filter(|i| !i.is_empty())
.unwrap_or(kw::Underscore),
name: if let Some(Some(ident)) = names.next() {
ident.name
} else {
kw::Underscore
},
is_const: false,
})
.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_lint::LateContext;
use rustc_span::Span;
use rustc_span::symbol::{Ident, Symbol, kw};
use rustc_span::symbol::{Ident, kw};
use super::RENAMED_FUNCTION_PARAMS;
@ -51,22 +51,33 @@ struct RenamedFnArgs(Vec<(Span, String)>);
impl RenamedFnArgs {
/// Comparing between an iterator of default names and one with current names,
/// 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
I: Iterator<Item = Ident>,
T: Iterator<Item = Ident>,
I1: Iterator<Item = Option<Ident>>,
I2: Iterator<Item = Option<Ident>>,
{
let mut renamed: Vec<(Span, String)> = vec![];
debug_assert!(default_names.size_hint() == current_names.size_hint());
while let (Some(def_name), Some(cur_name)) = (default_names.next(), current_names.next()) {
let current_name = cur_name.name;
let default_name = def_name.name;
if is_unused_or_empty_symbol(current_name) || is_unused_or_empty_symbol(default_name) {
continue;
}
if current_name != default_name {
renamed.push((cur_name.span, default_name.to_string()));
debug_assert!(default_idents.size_hint() == current_idents.size_hint());
while let (Some(default_ident), Some(current_ident)) =
(default_idents.next(), current_idents.next())
{
let has_name_to_check = |ident: Option<Ident>| {
if let Some(ident) = ident
&& ident.name != kw::Underscore
&& !ident.name.as_str().starts_with('_')
{
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.
fn trait_item_def_id_of_impl(items: &[ImplItemRef], target: OwnerId) -> Option<DefId> {
items.iter().find_map(|item| {

View File

@ -189,7 +189,7 @@ fn check_fn_inner<'tcx>(
cx: &LateContext<'tcx>,
sig: &'tcx FnSig<'_>,
body: Option<BodyId>,
trait_sig: Option<&[Ident]>,
trait_sig: Option<&[Option<Ident>]>,
generics: &'tcx Generics<'_>,
span: Span,
report_extra_lifetimes: bool,
@ -264,7 +264,7 @@ fn could_use_elision<'tcx>(
cx: &LateContext<'tcx>,
func: &'tcx FnDecl<'_>,
body: Option<BodyId>,
trait_sig: Option<&[Ident]>,
trait_sig: Option<&[Option<Ident>]>,
named_generics: &'tcx [GenericParam<'_>],
msrv: Msrv,
) -> Option<(Vec<LocalDefId>, Vec<Lifetime>)> {
@ -310,7 +310,7 @@ fn could_use_elision<'tcx>(
let body = cx.tcx.hir_body(body_id);
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;
}
@ -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
fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>, msrv: Msrv) -> bool {
if let Some(ident) = ident
fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Option<Ident>>, msrv: Msrv) -> bool {
if let Some(Some(ident)) = ident
&& ident.name == kw::SelfLower
&& !func.implicit_self.has_implicit_self()
&& 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),
(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),
(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()),
(Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()),
(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 {
use WherePredicateKind::*;
over(&l.attrs, &r.attrs, eq_attr)
over(&l.attrs, &r.attrs, eq_attr)
&& match (&l.kind, &r.kind) {
(BoundPredicate(l), BoundPredicate(r)) => {
over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {

View File

@ -192,6 +192,7 @@ enum ChainItemKind {
StructField(symbol::Ident),
TupleField(symbol::Ident, bool),
Await,
Yield,
Comment(String, CommentPosition),
}
@ -203,6 +204,7 @@ impl ChainItemKind {
| ChainItemKind::StructField(..)
| ChainItemKind::TupleField(..)
| ChainItemKind::Await
| ChainItemKind::Yield
| ChainItemKind::Comment(..) => false,
}
}
@ -257,6 +259,10 @@ impl ChainItemKind {
let span = mk_sp(nested.span.hi(), expr.span.hi());
(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 (
ChainItemKind::Parent {
@ -306,6 +312,7 @@ impl Rewrite for ChainItem {
rewrite_ident(context, ident)
),
ChainItemKind::Await => ".await".to_owned(),
ChainItemKind::Yield => ".yield".to_owned(),
ChainItemKind::Comment(ref comment, _) => {
rewrite_comment(comment, false, shape, context.config)?
}
@ -508,7 +515,8 @@ impl Chain {
}),
ast::ExprKind::Field(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),
is_method_call_receiver: false,
}),

View File

@ -221,7 +221,7 @@ pub(crate) fn format_expr(
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 {
rewrite_unary_prefix(context, "yield ", &**expr, shape)
} else {
@ -243,7 +243,8 @@ pub(crate) fn format_expr(
ast::ExprKind::Try(..)
| ast::ExprKind::Field(..)
| 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) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|_| {
wrap_str(

View File

@ -4,7 +4,7 @@ use rustc_ast::ast::{
self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility,
VisibilityKind,
};
use rustc_ast::ptr;
use rustc_ast::{YieldKind, ptr};
use rustc_ast_pretty::pprust;
use rustc_span::{BytePos, LocalExpnId, Span, Symbol, SyntaxContext, sym, symbol};
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::Unary(_, 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),
// This can only be a string 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::Use(..)
| ast::ExprKind::Type(..)
| ast::ExprKind::Yield(None)
| ast::ExprKind::Yield(..)
| 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
|
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
--> $DIR/extern-static.rs:16:14
|
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

View File

@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
--> $DIR/tls.rs:11:25
|
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
--> $DIR/tls.rs:20:26
|
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
|

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
|
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
--> $DIR/issue-28324.rs:5:25

View File

@ -1,4 +1,5 @@
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: 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
|
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
--> $DIR/issue-14227.rs:4:21

View File

@ -47,7 +47,6 @@ add_labels = ["S-waiting-on-review"]
[glacier]
[ping.icebreakers-llvm]
alias = ["llvm", "llvms"]
message = """\
Hey LLVM ICE-breakers! This bug has been identified as a good
"LLVM ICE-breaking candidate". In case it's useful, here are some