1
Fork 0

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