Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
842c087
Fix requires_lto targets needing lto set in cargo
Flakebi Dec 29, 2025
47bec22
std: sys: process: uefi: Add program searching
Ayush1325 Jan 12, 2026
6f28cd5
Make Rcs and Arcs use pointer comparison for unsized types
Gaming32 Apr 21, 2026
2c79213
field representing types: remove explicit `Send` and `Sync` impls
BennoLossin Apr 21, 2026
59f18c2
field representing types: implement Debug through reflection
BennoLossin Apr 21, 2026
f3719b1
field representing types: implement Default
BennoLossin Apr 21, 2026
104914e
field representing types: implement Hash, Eq & Ord
BennoLossin Apr 21, 2026
ca700ed
field representing types: test all implemented traits
BennoLossin Apr 21, 2026
a041a76
field representing types: add test for unsized types
BennoLossin Apr 21, 2026
4abc28f
`<Take as Read>::read_buf`: Clarify local variable name.
briansmith Apr 22, 2026
71076f2
`<Take as Read>::read_buf`: Eliminate unneeded local variables.
briansmith Apr 22, 2026
c716ce5
`<Take as Read>::read_buf`: Clarify safety comments and naming.
briansmith Apr 22, 2026
3a0a14f
`<Take as Read>::read_buf`: Don't initialize `buf` if it was already …
briansmith Apr 22, 2026
5e00484
Avoid misleading closure return type note
chenyukang Apr 25, 2026
5cd9d92
Avoid Vec allocation in TyCtxt::mk_place_elem
kevinheavey Apr 21, 2026
4fc64f4
Add boxing suggestions for `impl Trait` return type mismatches
Unique-Usman Apr 23, 2026
163aedc
Convert attribute `FinalizeFn` to fn pointer
JonathanBrouwer Apr 26, 2026
a677828
Add boxing suggestions for return expressions in `impl Trait` functions
Unique-Usman Apr 26, 2026
a7330f4
rustc_attr_parsing: use a `try {}` in `or_malformed`
scrabsha Apr 26, 2026
d9e227e
Fix broken logic in `incremental_verify_ich_failed`
jyn514 Apr 26, 2026
7151184
Add some debugging to `rustc_session` filename handling
jyn514 Apr 26, 2026
da545d0
Fix heap overflow in slice::join caused by misbehaving Borrow
Manishearth Apr 26, 2026
f8e3af4
Rollup merge of #149624 - Flakebi:fix-lto, r=bjorn3
jhpratt Apr 27, 2026
12a843a
Rollup merge of #155317 - briansmith:b/take-opt, r=Mark-Simulacrum
jhpratt Apr 27, 2026
72cd5fb
Rollup merge of #155579 - Gaming32:fix-154998, r=Mark-Simulacrum
jhpratt Apr 27, 2026
7695b84
Rollup merge of #155588 - BennoLossin:frt-traits, r=Mark-Simulacrum
jhpratt Apr 27, 2026
f4043f8
Rollup merge of #155708 - Manishearth:borrow-fix, r=Mark-Simulacrum
jhpratt Apr 27, 2026
c20a92e
Rollup merge of #155778 - kevinheavey:perf-mk-place-elem-avoid-vec-al…
jhpratt Apr 27, 2026
e3a6fa5
Rollup merge of #151014 - Ayush1325:uefi-cmd-path, r=jhpratt,nicholas…
jhpratt Apr 27, 2026
9562f3d
Rollup merge of #155682 - Unique-Usman:ua/box-impl, r=mejrs
jhpratt Apr 27, 2026
78569d8
Rollup merge of #155770 - chenyukang:yukang-fix-155670-closure-return…
jhpratt Apr 27, 2026
3502ed3
Rollup merge of #155818 - JonathanBrouwer:finalize-fn-ptr, r=mejrs
jhpratt Apr 27, 2026
c0e4189
Rollup merge of #155829 - scrabsha:push-kwlqypwmnpul, r=mejrs
jhpratt Apr 27, 2026
bd2d1a8
Rollup merge of #155835 - jyn514:jyn/verify-ich-diagnostics, r=wesley…
jhpratt Apr 27, 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
8 changes: 5 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,11 @@ fn parse_directive_items<'p, S: Stage>(
}}

macro or_malformed($($code:tt)*) {{
let Some(ret) = (||{
Some($($code)*)
})() else {
let Some(ret) = (
try {
$($code)*
}
) else {
malformed!()
};
ret
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {

pub(crate) type AcceptFn<S> =
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
pub(crate) type FinalizeFn<S> =
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
pub(crate) type FinalizeFn<S> = fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;

macro_rules! attribute_parsers {
(
Expand Down Expand Up @@ -131,10 +130,10 @@ macro_rules! attribute_parsers {
}),
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
finalizer: Box::new(|cx| {
finalizer: |cx| {
let state = STATE_OBJECT.take();
state.finalize(cx)
})
}
});
}
Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
let mut early_parsed_state = EarlyParsedState::default();

let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
let mut finalizers: Vec<FinalizeFn<S>> = Vec::with_capacity(attrs.len());

for attr in attrs {
// If we're only looking for a single attribute, skip all the ones we don't care about.
Expand Down Expand Up @@ -413,7 +413,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
};

(accept.accept_fn)(&mut cx, &args);
finalizers.push(&accept.finalizer);
finalizers.push(accept.finalizer);

if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
Self::check_target(&accept.allowed_targets, target, &mut cx);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ impl ModuleConfig {
// `#![no_builtins]` is assumed to not participate in LTO and
// instead goes on to generate object code.
EmitObj::Bitcode
} else if need_bitcode_in_object(tcx) {
} else if need_bitcode_in_object(tcx) || sess.target.requires_lto {
EmitObj::ObjectCode(BitcodeSection::Full)
} else {
EmitObj::ObjectCode(BitcodeSection::None)
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,9 @@ impl<'tcx> CoerceMany<'tcx> {
// note in this case, since it would be incorrect.
&& let Some(fn_sig) = fcx.body_fn_sig()
&& fn_sig.output().is_ty_var()
&& fcx.ret_coercion.as_ref().is_some_and(|ret_coercion| {
fcx.resolve_vars_if_possible(ret_coercion.borrow().expected_ty()) == expected
})
{
err.span_note(sp, format!("return type inferred to be `{expected}` here"));
}
Expand Down
38 changes: 37 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence;
use rustc_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan, listify, msg};
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
Expand All @@ -26,13 +27,14 @@ use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::{ExpnKind, Ident, MacroKind, Span, Spanned, Symbol, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use tracing::{debug, instrument};

use super::FnCtxt;
use crate::errors;
use crate::errors::{self, SuggestBoxingForReturnImplTrait};
use crate::fn_ctxt::rustc_span::BytePos;
use crate::method::probe;
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
Expand Down Expand Up @@ -963,6 +965,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}

let trait_def_id = trait_ref.trait_ref.path.res.def_id();
if self.tcx.is_dyn_compatible(trait_def_id) {
err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType {
start_sp: hir_ty.span.with_hi(hir_ty.span.lo() + BytePos(4)),
end_sp: hir_ty.span.shrink_to_hi(),
});

let body = self.tcx.hir_body_owned_by(fn_id);
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);

if !visitor.returns.is_empty() {
let starts: Vec<Span> = visitor
.returns
.iter()
.filter(|expr| expr.span.can_be_used_for_suggestions())
.map(|expr| expr.span.shrink_to_lo())
.collect();
let ends: Vec<Span> = visitor
.returns
.iter()
.filter(|expr| expr.span.can_be_used_for_suggestions())
.map(|expr| expr.span.shrink_to_hi())
.collect();

if !starts.is_empty() {
err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr {
starts,
ends,
});
}
}
}

self.try_suggest_return_impl_trait(err, expected, found, fn_id);
self.try_note_caller_chooses_ty_for_ty_param(err, expected, found);
return true;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ pub(crate) struct Reentrant;
#[note(
"an ideal reproduction consists of the code before and some patch that then triggers the bug when applied and compiled again"
)]
#[note("as a workaround, you can run {$run_cmd} to allow your project to compile")]
#[note("as a workaround, you can {$run_cmd} to allow your project to compile")]
pub(crate) struct IncrementCompilation {
pub run_cmd: String,
pub dep_node: String,
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2416,10 +2416,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// to build a full `Place` it's just a convenient way to grab a projection and modify it in
/// flight.
pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'tcx> {
let mut projection = place.projection.to_vec();
projection.push(elem);

Place { local: place.local, projection: self.mk_place_elems(&projection) }
Place {
local: place.local,
projection: self.mk_place_elems_from_iter(place.projection.iter().chain([elem])),
}
}

pub fn mk_poly_existential_predicates(
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_middle/src/verify_ich.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::cell::Cell;

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_session::utils::was_invoked_from_cargo;
use tracing::instrument;

use crate::dep_graph::{DepGraphData, SerializedDepNodeIndex};
Expand Down Expand Up @@ -66,10 +68,10 @@ fn incremental_verify_ich_failed<'tcx>(
if old_in_panic {
tcx.dcx().emit_err(crate::error::Reentrant);
} else {
let run_cmd = if let Some(crate_name) = &tcx.sess.opts.crate_name {
format!("`cargo clean -p {crate_name}` or `cargo clean`")
let run_cmd = if was_invoked_from_cargo() {
format!("run `cargo clean -p {}` or `cargo clean`", tcx.crate_name(LOCAL_CRATE))
} else {
"`cargo clean`".to_string()
"clean your build cache".to_owned()
};

let dep_node = tcx.dep_graph.data().unwrap().prev_node_of(prev_index);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,7 @@ impl OutputFilenames {
}

pub fn interface_path(&self) -> PathBuf {
debug!("using crate_name={} for interface_path", self.crate_stem);
self.out_directory.join(format!("lib{}.rs", self.crate_stem))
}

Expand All @@ -1214,6 +1215,7 @@ impl OutputFilenames {
let extension = flavor.extension();
match flavor {
OutputType::Metadata => {
debug!("using crate_name={} for {extension}", self.crate_stem);
self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension))
}
_ => self.with_directory_and_extension(&self.out_directory, extension),
Expand Down Expand Up @@ -1288,6 +1290,7 @@ impl OutputFilenames {
}

pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf {
debug!("using filestem={} for {extension}", self.filestem);
let mut path = directory.join(&self.filestem);
path.set_extension(extension);
path
Expand Down
6 changes: 3 additions & 3 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2615,7 +2615,7 @@ impl<T: ?Sized + PartialEq, A: Allocator> RcEqIdent<T, A> for Rc<T, A> {
#[rustc_unsafe_specialization_marker]
pub(crate) trait MarkerEq: PartialEq<Self> {}

impl<T: Eq> MarkerEq for T {}
impl<T: ?Sized + Eq> MarkerEq for T {}

/// We're doing this specialization here, and not as a more general optimization on `&T`, because it
/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to
Expand All @@ -2628,12 +2628,12 @@ impl<T: Eq> MarkerEq for T {}
impl<T: ?Sized + MarkerEq, A: Allocator> RcEqIdent<T, A> for Rc<T, A> {
#[inline]
fn eq(&self, other: &Rc<T, A>) -> bool {
Rc::ptr_eq(self, other) || **self == **other
ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) || **self == **other
}

#[inline]
fn ne(&self, other: &Rc<T, A>) -> bool {
!Rc::ptr_eq(self, other) && **self != **other
!ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) && **self != **other
}
}

Expand Down
32 changes: 27 additions & 5 deletions library/alloc/src/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,26 @@ macro_rules! copy_slice_and_advance {
// the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
// [T] and str both impl AsRef<[T]> for some T
// => s.borrow().as_ref() and we always have slices
//
// # Safety notes
//
// `Borrow` is a safe trait, and implementations are not required
// to be deterministic. An inconsistent `Borrow` implementation could return slices
// of different lengths on consecutive calls (e.g. by using interior mutability).
//
// This implementation calls `borrow()` multiple times:
// 1. To calculate `reserved_len`, all elements are borrowed once.
// 2. The first element is borrowed again when copied via `extend_from_slice`.
// 3. Subsequent elements are borrowed a second time when building the mapped iterator.
//
// Risks and Mitigations:
// - If the first element GROWS on the second borrow, the length subtraction underflows.
// We mitigate this by doing a `checked_sub` to panic rather than allowing an underflow
// that fabricates a huge destination slice.
// - If elements 2..N GROW on their second borrow, the target slice bounds set by `checked_sub`
// means that `split_at_mut` inside `copy_slice_and_advance!` will correctly panic.
// - If elements SHRINK on their second borrow, the spare space is never written, and the final
// length set via `set_len` masks trailing uninitialized bytes.
#[cfg(not(no_global_oom_handling))]
fn join_generic_copy<B, T, S>(slice: &[S], sep: &[T]) -> Vec<T>
where
Expand Down Expand Up @@ -161,19 +181,21 @@ where

unsafe {
let pos = result.len();
let target = result.spare_capacity_mut().get_unchecked_mut(..reserved_len - pos);
let target_len = reserved_len.checked_sub(pos).expect("inconsistent Borrow implementation");
let target = result.spare_capacity_mut().get_unchecked_mut(..target_len);

// Convert the separator and slices to slices of MaybeUninit
// to simplify implementation in specialize_for_lengths
// to simplify implementation in specialize_for_lengths.
let sep_uninit = core::slice::from_raw_parts(sep.as_ptr().cast(), sep.len());
let iter_uninit = iter.map(|it| {
let it = it.borrow().as_ref();
core::slice::from_raw_parts(it.as_ptr().cast(), it.len())
});

// copy separator and slices over without bounds checks
// generate loops with hardcoded offsets for small separators
// massive improvements possible (~ x2)
// copy separator and slices over without bounds checks.
// `specialize_for_lengths!` internally calls `s.borrow()`, but because it uses
// the bounds-checked `split_at_mut` any misbehaving implementation
// will not write out of bounds.
let remain = specialize_for_lengths!(sep_uninit, target, iter_uninit; 0, 1, 2, 3, 4);

// A weird borrow implementation may return different
Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3549,12 +3549,12 @@ impl<T: ?Sized + PartialEq, A: Allocator> ArcEqIdent<T, A> for Arc<T, A> {
impl<T: ?Sized + crate::rc::MarkerEq, A: Allocator> ArcEqIdent<T, A> for Arc<T, A> {
#[inline]
fn eq(&self, other: &Arc<T, A>) -> bool {
Arc::ptr_eq(self, other) || **self == **other
ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) || **self == **other
}

#[inline]
fn ne(&self, other: &Arc<T, A>) -> bool {
!Arc::ptr_eq(self, other) && **self != **other
!ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) && **self != **other
}
}

Expand Down
28 changes: 28 additions & 0 deletions library/alloctests/tests/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,34 @@ fn eq() {
assert_eq!(*x.0.borrow(), 0);
}

#[test]
fn eq_unsized() {
#[derive(Eq)]
struct TestEq<T: ?Sized>(RefCell<usize>, T);
impl<T: ?Sized> PartialEq for TestEq<T> {
fn eq(&self, other: &TestEq<T>) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Arc::<TestEq<[u8; 3]>>::new(TestEq(RefCell::new(0), [0, 1, 2])) as Arc<TestEq<[u8]>>;
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 0);
}

#[test]
fn eq_unsized_slice() {
let a: Arc<[()]> = Arc::new([(); 3]);
let ptr: *const () = Arc::into_raw(a.clone()).cast();
let b: Arc<[()]> = unsafe { Arc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) };
assert!(a == a);
assert!(!(a != a));
assert!(a != b);
assert!(!(a == b));
}

// The test code below is identical to that in `rc.rs`.
// For better maintainability we therefore define this type alias.
type Rc<T, A = std::alloc::Global> = Arc<T, A>;
Expand Down
28 changes: 28 additions & 0 deletions library/alloctests/tests/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,34 @@ fn eq() {
assert_eq!(*x.0.borrow(), 0);
}

#[test]
fn eq_unsized() {
#[derive(Eq)]
struct TestEq<T: ?Sized>(RefCell<usize>, T);
impl<T: ?Sized> PartialEq for TestEq<T> {
fn eq(&self, other: &TestEq<T>) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Rc::<TestEq<[u8; 3]>>::new(TestEq(RefCell::new(0), [0, 1, 2])) as Rc<TestEq<[u8]>>;
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 0);
}

#[test]
fn eq_unsized_slice() {
let a: Rc<[()]> = Rc::new([(); 3]);
let ptr: *const () = Rc::into_raw(a.clone()).cast();
let b: Rc<[()]> = unsafe { Rc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) };
assert!(a == a);
assert!(!(a != a));
assert!(a != b);
assert!(!(a == b));
}

const SHARED_ITER_MAX: u16 = 100;

fn assert_trusted_len<I: TrustedLen>(_: &I) {}
Expand Down
19 changes: 19 additions & 0 deletions library/alloctests/tests/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,25 @@ fn test_join_issue_80335() {
test_join!("0-0-0", arr, "-");
}

#[test]
#[should_panic(expected = "inconsistent Borrow implementation")]
fn test_join_inconsistent_borrow() {
use std::borrow::Borrow;
use std::cell::Cell;

struct E(Cell<u32>);

impl Borrow<str> for E {
fn borrow(&self) -> &str {
let count = self.0.get();
self.0.set(count + 1);
if count == 0 { "" } else { "longer string" }
}
}

let _s = [E(Cell::new(0)), E(Cell::new(0))].join("");
}

#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_unsafe_slice() {
Expand Down
Loading
Loading