Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d715ef4
debuginfo: slices are DW_TAG_array_type's
shua Feb 26, 2026
f398585
adding debuginfo tests for str repr llvm di
shua May 5, 2026
d02b4c8
Improve suggestions for unconstrained parameters in `impl` blocks
TomtheCoder2 Nov 10, 2025
6bd5ab9
Emit error when self type is not specified and accessed
aerooneqq May 14, 2026
0f280d4
Add function to extract the symbol name from the attributes
Urgau Apr 19, 2026
8b67ab3
Add weak-only lang items for core runtime symbols
Urgau Apr 19, 2026
426706d
Add lint against invalid runtime symbol definitions
Urgau Apr 12, 2026
50306e1
Handle static whose type is a function pointer
Urgau Apr 19, 2026
453192d
Fix invalid `memcpy` definition in codegen test and UI tests
Urgau Apr 19, 2026
32aa35c
Fix invalid definition of `strlen` in error codes documentation
Urgau Apr 19, 2026
282ec28
Implement pinned drop sugar
P8L1 May 14, 2026
9faff71
actually run the temp_dir doctest
RalfJung May 12, 2026
8348c93
Fix `compiler-builtins` runtime symbols definitions
Urgau May 14, 2026
5a12d48
Prefer tracing::instrument.
cjgillot May 14, 2026
d76d4cd
Untuple method parameters.
cjgillot May 14, 2026
6e7b089
Use DropCtxt::new_block and new_block_with_statements systematically.
cjgillot May 14, 2026
85dfeda
Correctly handle associated items in rustdoc macro expansion
GuillaumeGomez May 14, 2026
899be9f
Add regression tests for associated items in rustdoc macro expansion
GuillaumeGomez May 14, 2026
8909e79
Require UTF-8 in `Utf8Pattern::StringPattern`
qaijuang May 13, 2026
d24fd77
Make const param default test reproduce original ICE
cijiugechu May 15, 2026
1025e4d
Make the lint doctest pass with stage0
Urgau May 15, 2026
860813d
Require EIIs to be defined when we compile a rust dylib
bjorn3 May 8, 2026
2ab7bfe
Rollup merge of #148788 - TomtheCoder2:unconstrained-parameter-fix, r…
Zalathar May 15, 2026
013b57b
Rollup merge of #153238 - shua:lldb-rcstr, r=davidtwco
Zalathar May 15, 2026
3ae1fda
Rollup merge of #155521 - Urgau:runtime-symbols, r=davidtwco
Zalathar May 15, 2026
4f10c8c
Rollup merge of #156319 - bjorn3:eii_dylib_require_def, r=jdonszelmann
Zalathar May 15, 2026
7bd4ada
Rollup merge of #156452 - P8L1:implement-pin-drop-sugar-upstream, r=p…
Zalathar May 15, 2026
2643c65
Rollup merge of #156600 - cijiugechu:false-negative-test, r=BoxyUwU
Zalathar May 15, 2026
bcaf12d
Rollup merge of #156493 - RalfJung:run-temp-dir, r=ChrisDenton
Zalathar May 15, 2026
5521543
Rollup merge of #156556 - qaijuang:issue-156491-str-replace-utf8-patt…
Zalathar May 15, 2026
7f7d5a4
Rollup merge of #156565 - aerooneqq:delegation-self-type-ice, r=petro…
Zalathar May 15, 2026
38707cb
Rollup merge of #156586 - cjgillot:elaborate-new-block, r=oli-obk
Zalathar May 15, 2026
52569ac
Rollup merge of #156587 - GuillaumeGomez:assoc-items-macro-expansion,…
Zalathar May 15, 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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4267,6 +4267,7 @@ dependencies = [
"rustc_parse_format",
"rustc_session",
"rustc_span",
"rustc_symbol_mangling",
"rustc_target",
"rustc_trait_selection",
"smallvec",
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3867,6 +3867,19 @@ pub struct Fn {
pub eii_impls: ThinVec<EiiImpl>,
}

impl Fn {
pub fn is_pin_drop_sugar(&self) -> bool {
self.ident.name == sym::drop
&& self
.sig
.decl
.inputs
.first()
.and_then(|param| param.to_self())
.is_some_and(|eself| matches!(eself.node, SelfKind::Pinned(None, Mutability::Mut)))
}
}

#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct EiiImpl {
pub node_id: NodeId,
Expand Down
73 changes: 56 additions & 17 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,52 @@ impl<'hir> LoweringContext<'_, 'hir> {
})
}

fn resolve_pin_drop_sugar_impl_item(
&self,
i: &AssocItem,
ident: Ident,
span: Span,
) -> (Ident, Result<DefId, ErrorGuaranteed>) {
let trait_item_def_id = self
.get_partial_res(i.id)
.and_then(|r| r.expect_full_res().opt_def_id())
.ok_or_else(|| {
self.dcx().span_delayed_bug(span, "could not resolve trait item being implemented")
});

let is_pin_drop_sugar = match &i.kind {
AssocItemKind::Fn(fn_kind) => fn_kind.is_pin_drop_sugar(),
_ => false,
};
let def_id = match trait_item_def_id {
Ok(def_id) => def_id,
Err(guar) => return (ident, Err(guar)),
};
if !is_pin_drop_sugar {
return (ident, Ok(def_id));
}

let is_drop_pin_drop = self
.tcx
.lang_items()
.drop_trait()
.is_some_and(|drop_trait| self.tcx.parent(def_id) == drop_trait);
if is_drop_pin_drop {
// Associated item collection still derives the impl item's name from HIR.
return (Ident::new(sym::pin_drop, ident.span), Ok(def_id));
}

let guar = self
.dcx()
.struct_span_err(
i.span,
"method `drop` with `&pin mut self` is only supported for the `Drop` trait",
)
.with_span_label(i.span, "not a `Drop::pin_drop` implementation")
.emit();
(ident, Err(guar))
}

fn lower_impl_item(
&mut self,
i: &AssocItem,
Expand Down Expand Up @@ -1309,26 +1355,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
};

let span = self.lower_span(i.span);
let (effective_ident, impl_kind) = if is_in_trait_impl {
let (effective_ident, trait_item_def_id) =
self.resolve_pin_drop_sugar_impl_item(i, ident, span);
(effective_ident, ImplItemImplKind::Trait { defaultness, trait_item_def_id })
} else {
(ident, ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) })
};

let item = hir::ImplItem {
owner_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
ident: self.lower_ident(effective_ident),
generics,
impl_kind: if is_in_trait_impl {
ImplItemImplKind::Trait {
defaultness,
trait_item_def_id: self
.get_partial_res(i.id)
.and_then(|r| r.expect_full_res().opt_def_id())
.ok_or_else(|| {
self.dcx().span_delayed_bug(
span,
"could not resolve trait item being implemented",
)
}),
}
} else {
ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) }
},
impl_kind,
kind,
span,
has_delayed_lints: !self.delayed_lints.is_empty(),
Expand Down
49 changes: 30 additions & 19 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,20 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
);

let pointee_type_di_node = type_di_node(cx, pointee_type);
let pointee_type_di_node = match pointee_type.kind() {
// `&[T]` will look like `{ data_ptr: *const T, length: usize }`
ty::Slice(element_type) => type_di_node(cx, *element_type),
// `&str` will look like `{ data_ptr: *const u8, length: usize }`
ty::Str => type_di_node(cx, cx.tcx.types.u8),

// `&dyn K` will look like `{ pointer: _, vtable: _}`
// any Adt `Foo` containing an unsized type (eg `&[_]` or `&dyn _`)
// will look like `{ data_ptr: *const Foo, length: usize }`
// and thin pointers `&Foo` will just look like `*const Foo`.
//
// in all those cases, we just use the pointee_type
_ => type_di_node(cx, pointee_type),
};

return_if_di_node_created_in_meantime!(cx, unique_type_id);

Expand Down Expand Up @@ -389,26 +402,11 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
}

/// Create debuginfo for `[T]` and `str`. These are unsized.
///
/// NOTE: We currently emit just emit the debuginfo for the element type here
/// (i.e. `T` for slices and `u8` for `str`), so that we end up with
/// `*const T` for the `data_ptr` field of the corresponding wide-pointer
/// debuginfo of `&[T]`.
///
/// It would be preferable and more accurate if we emitted a DIArray of T
/// without an upper bound instead. That is, LLVM already supports emitting
/// debuginfo of arrays of unknown size. But GDB currently seems to end up
/// in an infinite loop when confronted with such a type.
///
/// As a side effect of the current encoding every instance of a type like
/// `struct Foo { unsized_field: [u8] }` will look like
/// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the
/// slice is zero, then accessing `unsized_field` in the debugger would
/// result in an out-of-bounds access.
fn build_slice_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
slice_type: Ty<'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
span: Span,
) -> DINodeCreationResult<'ll> {
let element_type = match slice_type.kind() {
ty::Slice(element_type) => *element_type,
Expand All @@ -423,7 +421,20 @@ fn build_slice_type_di_node<'ll, 'tcx>(

let element_type_di_node = type_di_node(cx, element_type);
return_if_di_node_created_in_meantime!(cx, unique_type_id);
DINodeCreationResult { di_node: element_type_di_node, already_stored_in_typemap: false }
let (size, align) = cx.spanned_size_and_align_of(slice_type, span);
let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, -1) };
let subscripts = &[subrange];
let di_node = unsafe {
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
size.bits(),
align.bits() as u32,
element_type_di_node,
subscripts.as_ptr(),
subscripts.len() as c_uint,
)
};
DINodeCreationResult { di_node, already_stored_in_typemap: false }
}

/// Get the debuginfo node for the given type.
Expand Down Expand Up @@ -454,7 +465,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
}
ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span),
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id, span),
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0755.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ side effects or infinite loops:

extern "C" {
#[unsafe(ffi_pure)] // ok!
pub fn strlen(s: *const i8) -> isize;
pub fn strlen(s: *const std::ffi::c_char) -> usize;
}
# fn main() {}
```
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0756.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ which have no side effects except for their return value:

extern "C" {
#[unsafe(ffi_const)] // ok!
pub fn strlen(s: *const i8) -> i32;
pub fn strlen(s: *const std::ffi::c_char) -> usize;
}
# fn main() {}
```
Expand Down
87 changes: 87 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,93 @@ impl<'hir> Generics<'hir> {
bound_span.with_lo(bounds[bound_pos - 1].span().hi())
}
}

/// Computes the span representing the removal of a generic parameter at `param_index`.
///
/// This function identifies the correct slice of source code to delete so that the
/// remaining generic list remains syntactically valid (handling commas and brackets).
///
/// ### Examples
///
/// 1. **With a following parameter:** (Includes the trailing comma)
/// - Input: `<T, U>` (index 0)
/// - Produces span for: `T, `
///
/// 2. **With a previous parameter:** (Includes the leading comma and bounds)
/// - Input: `<T: Clone, U>` (index 1)
/// - Produces span for: `, U`
///
/// 3. **The only parameter:** (Includes the angle brackets)
/// - Input: `<T>` (index 0)
/// - Produces span for: `<T>`
///
/// 4. **Parameter with where-clause bounds:**
/// - Input: `fn foo<T, U>() where T: Copy` (index 0)
/// - Produces span for: `T, ` (The where-clause remains for other logic to handle).
pub fn span_for_param_removal(&self, param_index: usize) -> Span {
if param_index >= self.params.len() {
return self.span.shrink_to_hi();
}

let is_param_explicit = |par: &&GenericParam<'_>| match par.kind {
GenericParamKind::Type { .. }
| GenericParamKind::Const { .. }
| GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit } => true,
_ => false,
};

// Find the span of the type parameter.
if let Some(next) = self.params[param_index + 1..].iter().find(is_param_explicit) {
self.params[param_index].span.until(next.span)
} else if let Some(prev) = self.params[..param_index].iter().rfind(is_param_explicit) {
let mut prev_span = prev.span;
// Consider the span of the bounds with the previous generic parameter when there is.
if let Some(prev_bounds_span) = self.span_for_param_bounds(prev) {
prev_span = prev_span.to(prev_bounds_span);
}

// Consider the span of the bounds with the current generic parameter when there is.
prev_span.shrink_to_hi().to(
if let Some(cur_bounds_span) = self.span_for_param_bounds(&self.params[param_index])
{
cur_bounds_span
} else {
self.params[param_index].span
},
)
} else {
// Remove also angle brackets <> when there is just ONE generic parameter.
self.span
}
}

/// Returns the span of the `WherePredicate` associated with the given `GenericParam`, if any.
///
/// This looks specifically for predicates in the `where` clause that were generated
/// from the parameter definition (e.g., `T` in `where T: Bound`).
///
/// ### Example
///
/// - Input: `param` representing `T`
/// - Context: `where T: Clone + Default, U: Copy`
/// - Returns: Span of `T: Clone + Default`
fn span_for_param_bounds(&self, param: &GenericParam<'hir>) -> Option<Span> {
self.predicates
.iter()
.find(|pred| {
if let WherePredicateKind::BoundPredicate(WhereBoundPredicate {
origin: PredicateOrigin::GenericParam,
bounded_ty,
..
}) = pred.kind
{
bounded_ty.span == param.span
} else {
false
}
})
.map(|pred| pred.span)
}
}

/// A single predicate in a where-clause.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@ language_item_table! {

// Used to fallback `{float}` to `f32` when `f32: From<{float}>`
From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1);

// Runtime symbols
MemCpy, sym::memcpy_fn, memcpy_fn, Target::Fn, GenericRequirement::None;
MemMove, sym::memmove_fn, memmove_fn, Target::Fn, GenericRequirement::None;
MemSet, sym::memset_fn, memset_fn, Target::Fn, GenericRequirement::None;
MemCmp, sym::memcmp_fn, memcmp_fn, Target::Fn, GenericRequirement::None;
Bcmp, sym::bcmp_fn, bcmp_fn, Target::Fn, GenericRequirement::None;
StrLen, sym::strlen_fn, strlen_fn, Target::Fn, GenericRequirement::None;
}

/// The requirement imposed on the generics of a lang item
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_hir/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,29 @@ macro_rules! weak_lang_items {
}
}

macro_rules! weak_only_lang_items {
($($item:ident,)*) => {
pub static WEAK_ONLY_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*];

impl LangItem {
pub fn is_weak_only(self) -> bool {
matches!(self, $(LangItem::$item)|*)
}
}
}
}

weak_lang_items! {
PanicImpl, rust_begin_unwind;
EhPersonality, rust_eh_personality;
EhCatchTypeinfo, rust_eh_catch_typeinfo;
}

weak_only_lang_items! {
MemCpy,
MemMove,
MemSet,
MemCmp,
Bcmp,
StrLen,
}
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_middle::ty::{
use rustc_span::{ErrorGuaranteed, Span, kw};

use crate::collect::ItemCtxt;
use crate::errors::DelegationSelfTypeNotSpecified;
use crate::hir_ty_lowering::HirTyLowerer;

type RemapTable = FxHashMap<u32, u32>;
Expand Down Expand Up @@ -284,6 +285,12 @@ fn get_delegation_self_ty_or_err(tcx: TyCtxt<'_>, delegation_id: LocalDefId) ->
ctx.lower_ty(tcx.hir_node(id).expect_ty())
})
.unwrap_or_else(|| {
// It is possible to attempt to get self type when it is used in signature
// (i.e., `fn default() -> Self`), so emit error here in addition to possible
// `mismatched types` error (see #156388).
let err = DelegationSelfTypeNotSpecified { span: tcx.def_span(delegation_id) };
tcx.dcx().emit_err(err);

Ty::new_error_with_message(
tcx,
tcx.def_span(delegation_id),
Expand Down
Loading
Loading