Skip to content

Commit ab94f98

Browse files
committed
Auto merge of #119737 - matthiaskrgr:rollup-xre9fp9, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #118903 (Improved support of collapse_debuginfo attribute for macros.) - #119033 (coverage: `llvm-cov` expects column numbers to be bytes, not code points) - #119654 (bump bootstrap dependencies) - #119660 (remove an unnecessary stderr-per-bitwidth) - #119663 (tests: Normalize `\r\n` to `\n` in some run-make tests) - #119681 (coverage: Anonymize line numbers in branch views) - #119704 (Fix two variable binding issues in lint let_underscore) - #119725 (Add helper for when we want to know if an item has a host param) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 0ee9cfd + 5be59ec commit ab94f98

File tree

37 files changed

+1081
-395
lines changed

37 files changed

+1081
-395
lines changed

compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,7 @@ impl DebugContext {
6868
// In order to have a good line stepping behavior in debugger, we overwrite debug
6969
// locations of macro expansions with that of the outermost expansion site (when the macro is
7070
// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
71-
let span = if tcx.should_collapse_debuginfo(span) {
72-
span
73-
} else {
74-
// Walk up the macro expansion chain until we reach a non-expanded span.
75-
// We also stop at the function body level because no line stepping can occur
76-
// at the level above that.
77-
rustc_span::hygiene::walk_chain(span, function_span.ctxt())
78-
};
79-
71+
let span = tcx.collapsed_debuginfo(span, function_span);
8072
match tcx.sess.source_map().lookup_line(span.lo()) {
8173
Ok(SourceFileAndLine { sf: file, line }) => {
8274
let line_pos = file.lines()[line];

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -228,21 +228,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
228228
/// In order to have a good line stepping behavior in debugger, we overwrite debug
229229
/// locations of macro expansions with that of the outermost expansion site (when the macro is
230230
/// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
231-
fn adjust_span_for_debugging(&self, mut span: Span) -> Span {
231+
fn adjust_span_for_debugging(&self, span: Span) -> Span {
232232
// Bail out if debug info emission is not enabled.
233233
if self.debug_context.is_none() {
234234
return span;
235235
}
236-
237-
if self.cx.tcx().should_collapse_debuginfo(span) {
238-
// Walk up the macro expansion chain until we reach a non-expanded span.
239-
// We also stop at the function body level because no line stepping can occur
240-
// at the level above that.
241-
// Use span of the outermost expansion site, while keeping the original lexical scope.
242-
span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt());
243-
}
244-
245-
span
236+
// Walk up the macro expansion chain until we reach a non-expanded span.
237+
// We also stop at the function body level because no line stepping can occur
238+
// at the level above that.
239+
// Use span of the outermost expansion site, while keeping the original lexical scope.
240+
self.cx.tcx().collapsed_debuginfo(span, self.mir.span)
246241
}
247242

248243
fn spill_operand_to_stack(

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,7 @@ impl Qualif for NeedsNonConstDrop {
157157
// FIXME(effects): If `destruct` is not a `const_trait`,
158158
// or effects are disabled in this crate, then give up.
159159
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
160-
if cx.tcx.generics_of(destruct_def_id).host_effect_index.is_none()
161-
|| !cx.tcx.features().effects
162-
{
160+
if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects {
163161
return NeedsDrop::in_any_value_of_ty(cx, ty);
164162
}
165163

compiler/rustc_hir/src/hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1997,7 +1997,7 @@ pub enum LocalSource {
19971997
AsyncFn,
19981998
/// A desugared `<expr>.await`.
19991999
AwaitDesugar,
2000-
/// A desugared `expr = expr`, where the LHS is a tuple, struct or array.
2000+
/// A desugared `expr = expr`, where the LHS is a tuple, struct, array or underscore expression.
20012001
/// The span is that of the `=` sign.
20022002
AssignDesugar(Span),
20032003
}

compiler/rustc_hir_typeck/src/callee.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -490,11 +490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
490490
self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span));
491491
let fn_once_output_def_id =
492492
self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
493-
if self.tcx.generics_of(fn_once_def_id).host_effect_index.is_none() {
494-
if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
495-
self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
496-
}
497-
} else {
493+
if self.tcx.has_host_param(fn_once_def_id) {
498494
let const_param: ty::GenericArg<'tcx> =
499495
([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into();
500496
self.register_predicate(traits::Obligation::new(
@@ -523,6 +519,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
523519
));
524520

525521
self.select_obligations_where_possible(|_| {});
522+
} else if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
523+
self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
526524
}
527525
} else {
528526
self.dcx().emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty });

compiler/rustc_lint/src/let_underscore.rs

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
108108
if !matches!(local.pat.kind, hir::PatKind::Wild) {
109109
return;
110110
}
111+
112+
if matches!(local.source, rustc_hir::LocalSource::AsyncFn) {
113+
return;
114+
}
111115
if let Some(init) = local.init {
112116
let init_ty = cx.typeck_results().expr_ty(init);
113117
// If the type has a trivial Drop implementation, then it doesn't
@@ -126,6 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
126130
suggestion: local.pat.span,
127131
multi_suggestion_start: local.span.until(init.span),
128132
multi_suggestion_end: init.span.shrink_to_hi(),
133+
is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar(_)),
129134
};
130135
if is_sync_lock {
131136
let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]);

compiler/rustc_lint/src/lints.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -932,17 +932,19 @@ pub struct NonBindingLetSub {
932932
pub suggestion: Span,
933933
pub multi_suggestion_start: Span,
934934
pub multi_suggestion_end: Span,
935+
pub is_assign_desugar: bool,
935936
}
936937

937938
impl AddToDiagnostic for NonBindingLetSub {
938939
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
939940
where
940941
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
941942
{
943+
let prefix = if self.is_assign_desugar { "let " } else { "" };
942944
diag.span_suggestion_verbose(
943945
self.suggestion,
944946
fluent::lint_non_binding_let_suggestion,
945-
"_unused",
947+
format!("{prefix}_unused"),
946948
Applicability::MachineApplicable,
947949
);
948950
diag.multipart_suggestion(

compiler/rustc_middle/src/ty/mod.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use rustc_session::lint::LintBuffer;
5151
pub use rustc_session::lint::RegisteredTools;
5252
use rustc_span::hygiene::MacroKind;
5353
use rustc_span::symbol::{kw, sym, Ident, Symbol};
54-
use rustc_span::{ExpnId, ExpnKind, Span};
54+
use rustc_span::{hygiene, ExpnId, ExpnKind, Span};
5555
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
5656
pub use rustc_target::abi::{ReprFlags, ReprOptions};
5757
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
@@ -2518,21 +2518,21 @@ impl<'tcx> TyCtxt<'tcx> {
25182518
(ident, scope)
25192519
}
25202520

2521-
/// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion
2522-
/// site. Only applies when `Span` is the result of macro expansion.
2521+
/// Returns corrected span if the debuginfo for `span` should be collapsed to the outermost
2522+
/// expansion site (with collapse_debuginfo attribute if the corresponding feature enabled).
2523+
/// Only applies when `Span` is the result of macro expansion.
25232524
///
25242525
/// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default
2525-
/// and only when a macro definition is annotated with `#[collapse_debuginfo]`.
2526+
/// and only when a (some enclosing) macro definition is annotated with `#[collapse_debuginfo]`.
25262527
/// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default.
25272528
///
25282529
/// When `-Zdebug-macros` is provided then debuginfo will never be collapsed.
2529-
pub fn should_collapse_debuginfo(self, span: Span) -> bool {
2530-
!self.sess.opts.unstable_opts.debug_macros
2531-
&& if self.features().collapse_debuginfo {
2532-
span.in_macro_expansion_with_collapse_debuginfo()
2533-
} else {
2534-
span.from_expansion()
2535-
}
2530+
pub fn collapsed_debuginfo(self, span: Span, upto: Span) -> Span {
2531+
if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() {
2532+
return span;
2533+
}
2534+
let collapse_debuginfo_enabled = self.features().collapse_debuginfo;
2535+
hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled)
25362536
}
25372537

25382538
#[inline]

compiler/rustc_middle/src/ty/util.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
22
33
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
4-
use crate::query::Providers;
4+
use crate::query::{IntoQueryParam, Providers};
55
use crate::ty::layout::IntegerExt;
66
use crate::ty::{
77
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -786,6 +786,13 @@ impl<'tcx> TyCtxt<'tcx> {
786786
|| self.extern_crate(key.as_def_id()).is_some_and(|e| e.is_direct())
787787
}
788788

789+
/// Whether the item has a host effect param. This is different from `TyCtxt::is_const`,
790+
/// because the item must also be "maybe const", and the crate where the item is
791+
/// defined must also have the effects feature enabled.
792+
pub fn has_host_param(self, def_id: impl IntoQueryParam<DefId>) -> bool {
793+
self.generics_of(def_id).host_effect_index.is_some()
794+
}
795+
789796
pub fn expected_host_effect_param_for_body(self, def_id: impl Into<DefId>) -> ty::Const<'tcx> {
790797
let def_id = def_id.into();
791798
// FIXME(effects): This is suspicious and should probably not be done,

compiler/rustc_mir_transform/src/coverage/mod.rs

+70-20
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_middle::mir::{
2323
use rustc_middle::ty::TyCtxt;
2424
use rustc_span::def_id::LocalDefId;
2525
use rustc_span::source_map::SourceMap;
26-
use rustc_span::{Span, Symbol};
26+
use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
2727

2828
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
2929
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
@@ -107,6 +107,12 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
107107
);
108108

109109
let mappings = self.create_mappings(&coverage_spans, &coverage_counters);
110+
if mappings.is_empty() {
111+
// No spans could be converted into valid mappings, so skip this function.
112+
debug!("no spans could be converted into valid mappings; skipping");
113+
return;
114+
}
115+
110116
self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters);
111117

112118
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
@@ -148,9 +154,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
148154
// Flatten the spans into individual term/span pairs.
149155
.flat_map(|(term, spans)| spans.iter().map(move |&span| (term, span)))
150156
// Convert each span to a code region, and create the final mapping.
151-
.map(|(term, span)| {
152-
let code_region = make_code_region(source_map, file_name, span, body_span);
153-
Mapping { term, code_region }
157+
.filter_map(|(term, span)| {
158+
let code_region = make_code_region(source_map, file_name, span, body_span)?;
159+
Some(Mapping { term, code_region })
154160
})
155161
.collect::<Vec<_>>()
156162
}
@@ -252,41 +258,85 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
252258
data.statements.insert(0, statement);
253259
}
254260

255-
/// Convert the Span into its file name, start line and column, and end line and column
261+
/// Convert the Span into its file name, start line and column, and end line and column.
262+
///
263+
/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
264+
/// the compiler, these column numbers are denoted in **bytes**, because that's what
265+
/// LLVM's `llvm-cov` tool expects to see in coverage maps.
266+
///
267+
/// Returns `None` if the conversion failed for some reason. This shouldn't happen,
268+
/// but it's hard to rule out entirely (especially in the presence of complex macros
269+
/// or other expansions), and if it does happen then skipping a span or function is
270+
/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
256271
fn make_code_region(
257272
source_map: &SourceMap,
258273
file_name: Symbol,
259274
span: Span,
260275
body_span: Span,
261-
) -> CodeRegion {
276+
) -> Option<CodeRegion> {
262277
debug!(
263278
"Called make_code_region(file_name={}, span={}, body_span={})",
264279
file_name,
265280
source_map.span_to_diagnostic_string(span),
266281
source_map.span_to_diagnostic_string(body_span)
267282
);
268283

269-
let (file, mut start_line, mut start_col, mut end_line, mut end_col) =
270-
source_map.span_to_location_info(span);
271-
if span.hi() == span.lo() {
272-
// Extend an empty span by one character so the region will be counted.
273-
if span.hi() == body_span.hi() {
274-
start_col = start_col.saturating_sub(1);
275-
} else {
276-
end_col = start_col + 1;
277-
}
284+
let lo = span.lo();
285+
let hi = span.hi();
286+
287+
let file = source_map.lookup_source_file(lo);
288+
if !file.contains(hi) {
289+
debug!(?span, ?file, ?lo, ?hi, "span crosses multiple files; skipping");
290+
return None;
291+
}
292+
293+
// Column numbers need to be in bytes, so we can't use the more convenient
294+
// `SourceMap` methods for looking up file coordinates.
295+
let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> {
296+
let rpos = file.relative_position(pos);
297+
let line_index = file.lookup_line(rpos)?;
298+
let line_start = file.lines()[line_index];
299+
// Line numbers and column numbers are 1-based, so add 1 to each.
300+
Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1))
278301
};
279-
if let Some(file) = file {
280-
start_line = source_map.doctest_offset_line(&file.name, start_line);
281-
end_line = source_map.doctest_offset_line(&file.name, end_line);
302+
303+
let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?;
304+
let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?;
305+
306+
// If the span is empty, try to expand it horizontally by one character's
307+
// worth of bytes, so that it is more visible in `llvm-cov` reports.
308+
// We do this after resolving line/column numbers, so that empty spans at the
309+
// end of a line get an extra column instead of wrapping to the next line.
310+
if span.is_empty()
311+
&& body_span.contains(span)
312+
&& let Some(src) = &file.src
313+
{
314+
// Prefer to expand the end position, if it won't go outside the body span.
315+
if hi < body_span.hi() {
316+
let hi_rpos = hi_rpos.to_usize();
317+
let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos;
318+
end_col += nudge_bytes;
319+
} else if lo > body_span.lo() {
320+
let lo_rpos = lo_rpos.to_usize();
321+
let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1);
322+
// Subtract the nudge, but don't go below column 1.
323+
start_col = start_col.saturating_sub(nudge_bytes).max(1);
324+
}
325+
// If neither nudge could be applied, stick with the empty span coordinates.
282326
}
283-
CodeRegion {
327+
328+
// Apply an offset so that code in doctests has correct line numbers.
329+
// FIXME(#79417): Currently we have no way to offset doctest _columns_.
330+
start_line = source_map.doctest_offset_line(&file.name, start_line);
331+
end_line = source_map.doctest_offset_line(&file.name, end_line);
332+
333+
Some(CodeRegion {
284334
file_name,
285335
start_line: start_line as u32,
286336
start_col: start_col as u32,
287337
end_line: end_line as u32,
288338
end_col: end_col as u32,
289-
}
339+
})
290340
}
291341

292342
fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {

compiler/rustc_mir_transform/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#![feature(min_specialization)]
1010
#![feature(never_type)]
1111
#![feature(option_get_or_insert_default)]
12+
#![feature(round_char_boundary)]
1213
#![feature(trusted_step)]
1314
#![feature(try_blocks)]
1415
#![feature(yeet_expr)]

compiler/rustc_span/src/hygiene.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -445,18 +445,46 @@ impl HygieneData {
445445
}
446446

447447
fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
448+
let orig_span = span;
448449
debug!("walk_chain({:?}, {:?})", span, to);
449450
debug!("walk_chain: span ctxt = {:?}", span.ctxt());
450-
while span.from_expansion() && span.ctxt() != to {
451+
while span.ctxt() != to && span.from_expansion() {
451452
let outer_expn = self.outer_expn(span.ctxt());
452453
debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
453454
let expn_data = self.expn_data(outer_expn);
454455
debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
455456
span = expn_data.call_site;
456457
}
458+
debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
457459
span
458460
}
459461

462+
// We need to walk up and update return span if we meet macro instantiation to be collapsed
463+
fn walk_chain_collapsed(
464+
&self,
465+
mut span: Span,
466+
to: Span,
467+
collapse_debuginfo_enabled: bool,
468+
) -> Span {
469+
let orig_span = span;
470+
let mut ret_span = span;
471+
472+
debug!("walk_chain_collapsed({:?}, {:?})", span, to);
473+
debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
474+
while !span.eq_ctxt(to) && span.from_expansion() {
475+
let outer_expn = self.outer_expn(span.ctxt());
476+
debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
477+
let expn_data = self.expn_data(outer_expn);
478+
debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
479+
span = expn_data.call_site;
480+
if !collapse_debuginfo_enabled || expn_data.collapse_debuginfo {
481+
ret_span = span;
482+
}
483+
}
484+
debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span);
485+
ret_span
486+
}
487+
460488
fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
461489
let mut scope = None;
462490
while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
@@ -573,6 +601,10 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
573601
HygieneData::with(|data| data.walk_chain(span, to))
574602
}
575603

604+
pub fn walk_chain_collapsed(span: Span, to: Span, collapse_debuginfo_enabled: bool) -> Span {
605+
HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled))
606+
}
607+
576608
pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
577609
// The new contexts that need updating are at the end of the list and have `$crate` as a name.
578610
let (len, to_update) = HygieneData::with(|data| {

0 commit comments

Comments
 (0)