Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d9b90b0
Rewrite safety requirements for `Allocator` impls
theemathas Jun 12, 2026
e9929d7
Address feedback comments.
theemathas Jun 15, 2026
84f2896
rustdoc: do not include extra stuff in span
notriddle Jun 7, 2026
2001b88
Fix `unbalanced_ticks` when doc isn't contiguous
notriddle Jun 8, 2026
e66a504
Add test case for split missing punctuation
notriddle Jun 8, 2026
f7302b9
Skip the unhelpful binary search
notriddle Jun 13, 2026
b66a23f
Rename `span` and `line_bytes` to more specific
notriddle Jun 18, 2026
f93f2e4
Use an intermediate variable for readability
notriddle Jun 18, 2026
7975dc7
Add clarifying comment
notriddle Jun 18, 2026
4d83004
Remove unused `Option` return
notriddle Jun 18, 2026
9438aac
Handle span failure in redundant_explicit_links
notriddle Jun 18, 2026
74c203d
Add clarifying comment for shrink_to_hi
notriddle Jun 18, 2026
162a90c
Handle block doc comments better
notriddle Jun 18, 2026
310bfad
Enable Enzyme for x86_64-apple
sgasho Jun 3, 2026
34e0561
bump download-ci-llvm-stamp
sgasho Jun 3, 2026
d847075
Fix conditions of `&` API invalidating memory blocks.
theemathas Jul 1, 2026
a00bdac
diagnostics: suggest type annotation for closure params on HRTB FnOnc…
Rohan-Singla Jul 2, 2026
155ead1
test: bless existing UI tests affected by new closure type annotation…
Rohan-Singla Jul 2, 2026
5817f14
test: bless remaining UI tests affected by new closure type annotatio…
Rohan-Singla Jul 2, 2026
b51d75e
Clarify that LocalKey::try_with may return AccessError
kpeis695 Jul 4, 2026
0e0b98a
diagnostics: improve suggestion message and add rustfix test for clos…
Rohan-Singla Jul 5, 2026
049b3a3
test: bless nll UI tests affected by new closure type annotation sugg…
Rohan-Singla Jul 5, 2026
448e0f8
add regression test for final RPITIT override panic
TaKO8Ki Jul 6, 2026
5a5f78d
avoid final override diagnostics for non-function associated items
TaKO8Ki Jul 6, 2026
042e779
Add diagram to comment
notriddle Jul 7, 2026
8f1fd2c
Fix wrong diagram in comment
notriddle Jul 7, 2026
fd07857
Use better name for lint struct
notriddle Jul 7, 2026
49769af
QNX SDP 8 fixes.
japaric May 8, 2026
76eb33a
Rollup merge of #157385 - sgasho:x86-mac-enzyme, r=ZuseZ4
JonathanBrouwer Jul 7, 2026
ac1ad5d
Rollup merge of #157561 - notriddle:do-not-destroy-function-name, r=l…
JonathanBrouwer Jul 7, 2026
81a2d9c
Rollup merge of #158697 - ferrocene:qnx-sdp-8-fixes, r=aapoalas
JonathanBrouwer Jul 7, 2026
6a550d7
Rollup merge of #158760 - kpeis695:fix/localkey-try-with-may-return, …
JonathanBrouwer Jul 7, 2026
5480a09
Rollup merge of #157801 - theemathas:allocator-safety-rewrite, r=Amanieu
JonathanBrouwer Jul 7, 2026
a403366
Rollup merge of #158701 - Rohan-Singla:fix/#158393, r=mejrs
JonathanBrouwer Jul 7, 2026
f2fdef8
Rollup merge of #158841 - TaKO8Ki:fix-final-rpitit-override-ice, r=mejrs
JonathanBrouwer Jul 7, 2026
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 compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ fn check_overriding_final_trait_item<'tcx>(
trait_item: ty::AssocItem,
impl_item: ty::AssocItem,
) {
if trait_item.defaultness(tcx).is_final() {
if trait_item.is_fn() && trait_item.defaultness(tcx).is_final() {
tcx.dcx().emit_err(diagnostics::OverridingFinalTraitFunction {
impl_span: tcx.def_span(impl_item.def_id),
trait_span: tcx.def_span(trait_item.def_id),
Expand Down
105 changes: 81 additions & 24 deletions compiler/rustc_resolve/src/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,42 +641,99 @@ pub fn source_span_for_markdown_range_inner(
let mut start_bytes = 0;
let mut end_bytes = 0;

let span_of_all_fragments: Span = span_of_fragments(fragments)?;

let mut prev_lines_bytes = 0;
'outer: for (line_no, md_line) in md_lines.enumerate() {
loop {
let source_line = src_lines.next()?;
match source_line.find(md_line) {
Some(offset) => {
if line_no == starting_line {
start_bytes += offset;
let source_line_len = u32::try_from(source_line.len()).unwrap();
let source_line_span =
span_of_all_fragments.split_at(prev_lines_bytes).1.split_at(source_line_len).0;
let fragment = fragments
.iter()
// `source_line_span` might contain indentation that `fragment.span` doesn't contain
.find(|fragment| fragment.span.overlaps(source_line_span));
// Since we're counting bytes, `prev_line_bytes` includes the "\n".
prev_lines_bytes += source_line_len + 1;
if let Some(fragment) = fragment
&& let Some(offset) = source_line.find(md_line)
{
if fragment.span.lo() > source_line_span.lo()
&& source_line
[..usize::try_from(fragment.span.lo().0 - source_line_span.lo().0).unwrap()]
.chars()
.any(|c| !c.is_whitespace())
{
// Make sure anything between the start of this line and the fragment itself is just indentation.
// Because source_line is built by splitting the span that covers all fragments, this only finds
// characters *between* doc comments, not characters before or after doc comments.
//
// 1| /** doc */
// 2| #[inline] /** doc2 */
// ^^^^^^^^^
// | this
//
// 3| fn foo() {}
return None;
}
if fragment.span.hi() < source_line_span.hi()
&& source_line
[usize::try_from(fragment.span.hi().0 - source_line_span.lo().0).unwrap()..]
.chars()
.any(|c| !c.is_whitespace())
{
// Make sure anything between the start of this line and the fragment itself is just indentation.
// Because source_line is built by splitting the span that covers all fragments, this only finds
// characters *between* doc comments, not characters before or after doc comments.
// 1| /** doc */ #[inline]
// ^^^^^^^^^
// | this
//
// 2| /** doc2 */
// 3| fn foo() {}
return None;
}
if line_no == starting_line {
start_bytes += offset;

if starting_line == ending_line {
break 'outer;
}
} else if line_no == ending_line {
end_bytes += offset;
if starting_line == ending_line {
break 'outer;
} else if line_no < starting_line {
start_bytes += source_line.len() - md_line.len();
} else {
end_bytes += source_line.len() - md_line.len();
}
break;
} else if line_no == ending_line {
end_bytes += offset;
break 'outer;
} else if line_no < starting_line {
start_bytes += source_line.len() - md_line.len();
} else {
end_bytes += source_line.len() - md_line.len();
}
None => {
// Since this is a source line that doesn't include a markdown line,
// we have to count the newline that we split from earlier.
if line_no <= starting_line {
start_bytes += source_line.len() + 1;
} else {
end_bytes += source_line.len() + 1;
}
break;
} else {
// Since this is a source line that doesn't include a markdown line,
// we have to count it and its newline as non-markdown bytes.
if line_no <= starting_line {
start_bytes += source_line.len() + 1;
} else if source_line.chars().any(|c| !c.is_whitespace()) {
// We're past the first line, but haven't found the last line,
// but we found a non-empty non-markdown line.
// This could be an attribute, and we don't want a diagnostic
// suggesting to delete that attribute, so we return None to be safe.
// 1| /** doc */
// 2 | #[inline]
// ^^^^^^^^^
// | this
// 3| /** doc2 */
// 4| fn foo() {}
return None;
} else {
end_bytes += source_line.len() + 1;
}
}
}
}

let span = span_of_fragments(fragments)?;
let src_span = span.from_inner(InnerSpan::new(
let src_span = span_of_all_fragments.from_inner(InnerSpan::new(
md_range.start + start_bytes,
md_range.end + start_bytes + end_bytes,
));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::fmt;

use rustc_data_structures::intern::Interned;
use rustc_errors::{Diag, IntoDiagArg};
use rustc_errors::{Applicability, Diag, IntoDiagArg};
use rustc_hir as hir;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
use rustc_middle::bug;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode};
use rustc_middle::ty::{self, GenericArgsRef, RePlaceholder, Region, TyCtxt};
use rustc_middle::ty::{self, GenericArgsRef, IsSuggestable, RePlaceholder, Region, TyCtxt};
use tracing::{debug, instrument};

use crate::diagnostics::{
Expand Down Expand Up @@ -379,6 +380,50 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
}
}

// When the mismatched trait is an Fn-trait and the self type is a closure with
// unannotated parameters, suggest adding explicit type annotations. This turns
// the confusing lifetime-generality error into an actionable hint, e.g.:
// |buf| → |buf: &mut [u8]|
if self.tcx().is_fn_trait(trait_def_id) {
let actual_self_ty = self.cx.resolve_vars_if_possible(
ty::TraitRef::new_from_args(self.cx.tcx, trait_def_id, actual_args).self_ty(),
);
if let ty::Closure(closure_def_id, _) = *actual_self_ty.kind()
&& let Some(local_def_id) = closure_def_id.as_local()
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) =
self.tcx().hir_node_by_def_id(local_def_id)
{
let body = self.tcx().hir_body(closure.body);
// For Fn traits, args[1] is the tupled input types (e.g. `(&mut [u8],)`).
let expected_input_tys = expected_args.type_at(1);
if let ty::Tuple(input_tys) = *expected_input_tys.kind() {
let suggestions: Vec<_> = body
.params
.iter()
.zip(input_tys.iter())
.filter_map(|(param, ty)| {
// ty_span == pat.span means no explicit type annotation was written.
if param.ty_span == param.pat.span
&& ty.is_suggestable(self.tcx(), false)
{
Some((param.pat.span.shrink_to_hi(), format!(": {ty}")))
} else {
None
}
})
.collect();
if !suggestions.is_empty() {
let msg = if suggestions.len() == 1 {
"consider adding an explicit type annotation to the closure's argument"
} else {
"consider adding explicit type annotations to the closure's arguments"
};
err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
}
}
}
}

err
}

Expand Down
Loading
Loading