Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c783871
coverage: Hoist expansion tree creation out of span refinement
Zalathar Nov 9, 2025
075f9c4
coverage: Eagerly ensure that span refinement has an expansion tree node
Zalathar Nov 11, 2025
696690b
coverage: Associate hole spans with expansion tree nodes
Zalathar Nov 11, 2025
06e2e7a
CStr docs: Fix CStr vs &CStr confusion
btj Nov 11, 2025
a56fc9c
Some tweaks
btj Nov 11, 2025
65b5d76
Implement `Read::read_array`
joshtriplett Nov 12, 2025
a0fe930
Refactor `Box::take`
edwloef Nov 12, 2025
8fec082
ignore `build-rust-analyzer` even if it's a symlink
WaffleLapkin Oct 17, 2025
c7e50d0
Remove unused LLVMModuleRef argument
QnnOkabayashi Nov 12, 2025
258a446
Simplify `Resolver::resolve_macro_path`.
nnethercote Nov 11, 2025
8ece939
Remove `trace` argument from `resolve_macro_or_delegation_path`.
nnethercote Nov 11, 2025
b728064
Add a helpful comment to `DeriveResolution::exts`.
nnethercote Nov 12, 2025
199f308
Guard against incorrect `read_buf_exact` implementations
joshtriplett Nov 13, 2025
a40c3e5
Disable rustdoc-test-builder test partially for SGX target.
Nov 13, 2025
776405c
add missing s390x target feature to std detect test
folkertdev Nov 13, 2025
abaccae
waffle: stop watching codegen ssa
WaffleLapkin Nov 13, 2025
78beefe
error when ABI does not support guaranteed tail calls
folkertdev Nov 12, 2025
101ef2b
Correctly link to associated trait items in reexports
GuillaumeGomez Nov 5, 2025
044245c
Add regression test for #148008
GuillaumeGomez Nov 5, 2025
ad1789a
Expose fmt::Arguments::from_str as unstable.
m-ou-se Nov 13, 2025
ddebb62
add assembly test for infinite recursion with `become`
folkertdev Nov 13, 2025
5d33ab1
fix some typos in `!`-related test comments
WaffleLapkin Nov 13, 2025
b13f49e
add explanation comments to `!`-related tests
WaffleLapkin Nov 13, 2025
fd50a37
move `DispatchFromDyn` test out of `never_type/`
WaffleLapkin Nov 13, 2025
89902f4
Rollup merge of #148543 - GuillaumeGomez:fix-import_trait_associated_…
Zalathar Nov 14, 2025
ee40e02
Rollup merge of #148808 - nnethercote:resolve-cleanups, r=chenyukang,…
Zalathar Nov 14, 2025
fead508
Rollup merge of #148812 - Zalathar:expansions, r=JonathanBrouwer
Zalathar Nov 14, 2025
7481e91
Rollup merge of #148826 - btj:cstr-docs, r=joboet
Zalathar Nov 14, 2025
9ff7390
Rollup merge of #148850 - joshtriplett:read-array, r=joboet
Zalathar Nov 14, 2025
ad91711
Rollup merge of #148867 - edwloef:refactor-box-take, r=joboet
Zalathar Nov 14, 2025
9f07b25
Rollup merge of #148870 - QnnOkabayashi:remove-unused-value, r=wesley…
Zalathar Nov 14, 2025
35a82b8
Rollup merge of #148878 - folkertdev:tail-call-unsupported-abi, r=Waf…
Zalathar Nov 14, 2025
79e1013
Rollup merge of #148901 - sardok:disable_rustdoc_test_builder_sgx, r=…
Zalathar Nov 14, 2025
e32379b
Rollup merge of #148902 - folkertdev:detect-s390x-target-feature, r=t…
Zalathar Nov 14, 2025
3ba4d2d
Rollup merge of #148904 - WaffleLapkin:uncodegenssasitself, r=WaffleL…
Zalathar Nov 14, 2025
355e4cf
Rollup merge of #148906 - m-ou-se:fmt-args-from-str, r=dtolnay
Zalathar Nov 14, 2025
6bbc4cb
Rollup merge of #148907 - folkertdev:tail-call-infinite-recursion, r=…
Zalathar Nov 14, 2025
1c32a0b
Rollup merge of #148928 - WaffleLapkin:always-test, r=jieyouxu
Zalathar Nov 14, 2025
f589579
Rollup merge of #148929 - WaffleLapkin:bra-symlink-ignore, r=mati865,…
Zalathar Nov 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ no_llvm_build
/llvm/
/mingw-build/
/build
/build-rust-analyzer/
/build-rust-analyzer
/dist/
/unicode-downloads
/target
Expand Down
45 changes: 45 additions & 0 deletions compiler/rustc_abi/src/extern_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,51 @@ impl ExternAbi {
_ => CVariadicStatus::NotSupported,
}
}

/// Returns whether the ABI supports guaranteed tail calls.
#[cfg(feature = "nightly")]
pub fn supports_guaranteed_tail_call(self) -> bool {
match self {
Self::CmseNonSecureCall | Self::CmseNonSecureEntry => {
// See https://godbolt.org/z/9jhdeqErv. The CMSE calling conventions clear registers
// before returning, and hence cannot guarantee a tail call.
false
}
Self::AvrInterrupt
| Self::AvrNonBlockingInterrupt
| Self::Msp430Interrupt
| Self::RiscvInterruptM
| Self::RiscvInterruptS
| Self::X86Interrupt => {
// See https://godbolt.org/z/Edfjnxxcq. Interrupts cannot be called directly.
false
}
Self::GpuKernel | Self::PtxKernel => {
// See https://godbolt.org/z/jq5TE5jK1.
false
}
Self::Custom => {
// This ABI does not support calls at all (except via assembly).
false
}
Self::C { .. }
| Self::System { .. }
| Self::Rust
| Self::RustCall
| Self::RustCold
| Self::RustInvalid
| Self::Unadjusted
| Self::EfiApi
| Self::Aapcs { .. }
| Self::Cdecl { .. }
| Self::Stdcall { .. }
| Self::Fastcall { .. }
| Self::Thiscall { .. }
| Self::Vectorcall { .. }
| Self::SysV64 { .. }
| Self::Win64 { .. } => true,
}
}
}

pub fn all_names() -> Vec<&'static str> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ pub(crate) unsafe fn llvm_optimize(
// Here we map the old arguments to the new arguments, with an offset of 1 to make sure
// that we don't use the newly added `%dyn_ptr`.
unsafe {
llvm::LLVMRustOffloadMapper(cx.llmod(), old_fn, new_fn);
llvm::LLVMRustOffloadMapper(old_fn, new_fn);
}

llvm::set_linkage(new_fn, llvm::get_linkage(old_fn));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2025,7 +2025,7 @@ unsafe extern "C" {
) -> &Attribute;

// Operations on functions
pub(crate) fn LLVMRustOffloadMapper<'a>(M: &'a Module, Fn: &'a Value, Fn: &'a Value);
pub(crate) fn LLVMRustOffloadMapper<'a>(Fn: &'a Value, Fn: &'a Value);
pub(crate) fn LLVMRustGetOrInsertFunction<'a>(
M: &'a Module,
Name: *const c_char,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,9 @@ pub struct Indeterminate;
pub struct DeriveResolution {
pub path: ast::Path,
pub item: Annotatable,
// FIXME: currently this field is only used in `is_none`/`is_some` conditions. However, the
// `Arc<SyntaxExtension>` will be used if the FIXME in `MacroExpander::fully_expand_fragment`
// is completed.
pub exts: Option<Arc<SyntaxExtension>>,
pub is_const: bool,
}
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,7 @@ extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) {
llvm::PrintStatistics(OS);
}

extern "C" void LLVMRustOffloadMapper(LLVMModuleRef M, LLVMValueRef OldFn,
LLVMValueRef NewFn) {
llvm::Module *module = llvm::unwrap(M);
extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) {
llvm::Function *oldFn = llvm::unwrap<llvm::Function>(OldFn);
llvm::Function *newFn = llvm::unwrap<llvm::Function>(NewFn);

Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_mir_build/src/check_tail_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
self.report_abi_mismatch(expr.span, caller_sig.abi, callee_sig.abi);
}

if !callee_sig.abi.supports_guaranteed_tail_call() {
self.report_unsupported_abi(expr.span, callee_sig.abi);
}

// FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
// e.g.
// ```
Expand Down Expand Up @@ -358,6 +362,16 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
self.found_errors = Err(err);
}

fn report_unsupported_abi(&mut self, sp: Span, callee_abi: ExternAbi) {
let err = self
.tcx
.dcx()
.struct_span_err(sp, "ABI does not support guaranteed tail calls")
.with_note(format!("`become` is not supported for `extern {callee_abi}` functions"))
.emit();
self.found_errors = Err(err);
}

fn report_signature_mismatch(
&mut self,
sp: Span,
Expand Down
33 changes: 30 additions & 3 deletions compiler/rustc_mir_transform/src/coverage/expansion.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
use rustc_middle::mir;
use rustc_middle::mir::coverage::BasicCoverageBlock;
use rustc_span::{ExpnId, ExpnKind, Span};

use crate::coverage::from_mir;
use crate::coverage::graph::CoverageGraph;
use crate::coverage::hir_info::ExtractedHirInfo;

#[derive(Clone, Copy, Debug)]
pub(crate) struct SpanWithBcb {
pub(crate) span: Span,
Expand Down Expand Up @@ -70,6 +75,10 @@ pub(crate) struct ExpnNode {
pub(crate) spans: Vec<SpanWithBcb>,
/// Expansions whose call-site is in this expansion.
pub(crate) child_expn_ids: FxIndexSet<ExpnId>,

/// Hole spans belonging to this expansion, to be carved out from the
/// code spans during span refinement.
pub(crate) hole_spans: Vec<Span>,
}

impl ExpnNode {
Expand All @@ -88,17 +97,27 @@ impl ExpnNode {

spans: vec![],
child_expn_ids: FxIndexSet::default(),

hole_spans: vec![],
}
}
}

/// Given a collection of span/BCB pairs from potentially-different syntax contexts,
/// Extracts raw span/BCB pairs from potentially-different syntax contexts, and
/// arranges them into an "expansion tree" based on their expansion call-sites.
pub(crate) fn build_expn_tree(spans: impl IntoIterator<Item = SpanWithBcb>) -> ExpnTree {
pub(crate) fn build_expn_tree(
mir_body: &mir::Body<'_>,
hir_info: &ExtractedHirInfo,
graph: &CoverageGraph,
) -> ExpnTree {
let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph);

let mut nodes = FxIndexMap::default();
let new_node = |&expn_id: &ExpnId| ExpnNode::new(expn_id);

for span_with_bcb in spans {
for from_mir::RawSpanFromMir { raw_span, bcb } in raw_spans {
let span_with_bcb = SpanWithBcb { span: raw_span, bcb };

// Create a node for this span's enclosing expansion, and add the span to it.
let expn_id = span_with_bcb.span.ctxt().outer_expn();
let node = nodes.entry(expn_id).or_insert_with_key(new_node);
Expand All @@ -123,5 +142,13 @@ pub(crate) fn build_expn_tree(spans: impl IntoIterator<Item = SpanWithBcb>) -> E
}
}

// Associate each hole span (extracted from HIR) with its corresponding
// expansion tree node.
for &hole_span in &hir_info.hole_spans {
let expn_id = hole_span.ctxt().outer_expn();
let Some(node) = nodes.get_mut(&expn_id) else { continue };
node.hole_spans.push(hole_span);
}

ExpnTree { nodes }
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,3 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
| TerminatorKind::InlineAsm { .. } => Some(terminator.source_info.span),
}
}

#[derive(Debug)]
pub(crate) struct Hole {
pub(crate) span: Span,
}

impl Hole {
pub(crate) fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
if !self.span.overlaps_or_adjacent(other.span) {
return false;
}

self.span = self.span.to(other.span);
true
}
}
5 changes: 4 additions & 1 deletion compiler/rustc_mir_transform/src/coverage/mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rustc_middle::mir::coverage::{
use rustc_middle::mir::{self, BasicBlock, StatementKind};
use rustc_middle::ty::TyCtxt;

use crate::coverage::expansion;
use crate::coverage::graph::CoverageGraph;
use crate::coverage::hir_info::ExtractedHirInfo;
use crate::coverage::spans::extract_refined_covspans;
Expand All @@ -23,10 +24,12 @@ pub(crate) fn extract_mappings_from_mir<'tcx>(
hir_info: &ExtractedHirInfo,
graph: &CoverageGraph,
) -> ExtractedMappings {
let expn_tree = expansion::build_expn_tree(mir_body, hir_info, graph);

let mut mappings = vec![];

// Extract ordinary code mappings from MIR statement/terminator spans.
extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut mappings);
extract_refined_covspans(tcx, hir_info, graph, &expn_tree, &mut mappings);

extract_branch_mappings(mir_body, hir_info, graph, &mut mappings);

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::coverage::mappings::ExtractedMappings;

mod counters;
mod expansion;
mod from_mir;
mod graph;
mod hir_info;
mod mappings;
Expand Down
84 changes: 42 additions & 42 deletions compiler/rustc_mir_transform/src/coverage/spans.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
use rustc_middle::mir;
use rustc_middle::mir::coverage::{Mapping, MappingKind, START_BCB};
use rustc_middle::ty::TyCtxt;
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, DesugaringKind, ExpnId, ExpnKind, MacroKind, Span};
use tracing::instrument;

use crate::coverage::expansion::{self, ExpnTree, SpanWithBcb};
use crate::coverage::expansion::{ExpnTree, SpanWithBcb};
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
use crate::coverage::hir_info::ExtractedHirInfo;
use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir};

mod from_mir;

pub(super) fn extract_refined_covspans<'tcx>(
tcx: TyCtxt<'tcx>,
mir_body: &mir::Body<'tcx>,
hir_info: &ExtractedHirInfo,
graph: &CoverageGraph,
expn_tree: &ExpnTree,
mappings: &mut Vec<Mapping>,
) {
if hir_info.is_async_fn {
Expand All @@ -32,22 +28,32 @@ pub(super) fn extract_refined_covspans<'tcx>(

let &ExtractedHirInfo { body_span, .. } = hir_info;

let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph);
// Use the raw spans to build a tree of expansions for this function.
let expn_tree = expansion::build_expn_tree(
raw_spans
.into_iter()
.map(|RawSpanFromMir { raw_span, bcb }| SpanWithBcb { span: raw_span, bcb }),
);
// If there somehow isn't an expansion tree node corresponding to the
// body span, return now and don't create any mappings.
let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) else { return };

let mut covspans = vec![];
let mut push_covspan = |covspan: Covspan| {

for &SpanWithBcb { span, bcb } in &node.spans {
covspans.push(Covspan { span, bcb });
}

// For each expansion with its call-site in the body span, try to
// distill a corresponding covspan.
for &child_expn_id in &node.child_expn_ids {
if let Some(covspan) = single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id)
{
covspans.push(covspan);
}
}

covspans.retain(|covspan: &Covspan| {
let covspan_span = covspan.span;
// Discard any spans not contained within the function body span.
// Also discard any spans that fill the entire body, because they tend
// to represent compiler-inserted code, e.g. implicitly returning `()`.
if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) {
return;
return false;
}

// Each pushed covspan should have the same context as the body span.
Expand All @@ -57,27 +63,11 @@ pub(super) fn extract_refined_covspans<'tcx>(
false,
"span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}"
);
return;
return false;
}

covspans.push(covspan);
};

if let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) {
for &SpanWithBcb { span, bcb } in &node.spans {
push_covspan(Covspan { span, bcb });
}

// For each expansion with its call-site in the body span, try to
// distill a corresponding covspan.
for &child_expn_id in &node.child_expn_ids {
if let Some(covspan) =
single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id)
{
push_covspan(covspan);
}
}
}
true
});

// Only proceed if we found at least one usable span.
if covspans.is_empty() {
Expand Down Expand Up @@ -107,14 +97,8 @@ pub(super) fn extract_refined_covspans<'tcx>(
covspans.dedup_by(|b, a| a.span.source_equal(b.span));

// Sort the holes, and merge overlapping/adjacent holes.
let mut holes = hir_info
.hole_spans
.iter()
.copied()
// Discard any holes that aren't directly visible within the body span.
.filter(|&hole_span| body_span.contains(hole_span) && body_span.eq_ctxt(hole_span))
.map(|span| Hole { span })
.collect::<Vec<_>>();
let mut holes = node.hole_spans.iter().copied().map(|span| Hole { span }).collect::<Vec<_>>();

holes.sort_by(|a, b| compare_spans(a.span, b.span));
holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b));

Expand Down Expand Up @@ -295,3 +279,19 @@ fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
})
.ok()?
}

#[derive(Debug)]
struct Hole {
span: Span,
}

impl Hole {
fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
if !self.span.overlaps_or_adjacent(other.span) {
return false;
}

self.span = self.span.to(other.span);
true
}
}
5 changes: 1 addition & 4 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,14 +458,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let mut result = Err(Determinacy::Determined);
for derive in parent_scope.derives {
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
match this.reborrow().resolve_macro_path(
match this.reborrow().resolve_derive_macro_path(
derive,
MacroKind::Derive,
parent_scope,
true,
force,
ignore_import,
None,
) {
Ok((Some(ext), _)) => {
if ext.helper_attrs.contains(&ident.name) {
Expand Down
Loading
Loading