Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f06caa3
Add regression test for lifetimes preceding types in generics
Tehforsch Sep 21, 2026
ca5f540
Improve suggestions for lifetimes preceding types in generics
Tehforsch Sep 28, 2026
cfa655a
tests: accept noundef in a couple more places
durin42 Sep 30, 2026
e75273b
core: io: clean `unused_variables` lint under `no_io_statics`
ojeda Oct 2, 2026
f3f9adf
tests: add test for warning-free builds of `core` under `no_io_statics`
ojeda Oct 2, 2026
da0baa2
reflection: fix ICE when TypeId::info called on ADT
yara-blue Oct 2, 2026
6065c5a
Make the tracking issue template better suited for experiments
tmandry Oct 2, 2026
89f50a5
ref: Avoid long iterator chain in all_rust_features
panstromek Oct 3, 2026
5d332db
add `ignore-compare-mode-next-solver` and change order to be consistent
lcnr Oct 2, 2026
8111cca
refactor: migrate to LLVM-C's `LLVMGetOrInsertFunction`
AMS21 Oct 3, 2026
4f58d34
Rollup merge of #163645 - lcnr:ui-tests-compare-mode, r=jackh726
JonathanBrouwer Oct 3, 2026
df410a2
Rollup merge of #163663 - yara-blue:reflection-ice-typeid-info, r=oli…
JonathanBrouwer Oct 3, 2026
57373cd
Rollup merge of #163454 - Tehforsch:fix-lifetime-preceding-type-in-ge…
JonathanBrouwer Oct 3, 2026
304792b
Rollup merge of #163561 - durin42:llvm-24-extra-noundefs, r=nikic
JonathanBrouwer Oct 3, 2026
151e58b
Rollup merge of #163633 - ojeda:unused-variable-set_functions, r=John…
JonathanBrouwer Oct 3, 2026
7328c7d
Rollup merge of #163681 - tmandry:issue-template-experiments, r=travi…
JonathanBrouwer Oct 3, 2026
87c25d0
Rollup merge of #163685 - panstromek:all_rust_features_iter, r=RalfJung
JonathanBrouwer Oct 3, 2026
7e68f55
Rollup merge of #163690 - AMS21:refactor_get_or_insert_function, r=ha…
JonathanBrouwer Oct 3, 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
32 changes: 20 additions & 12 deletions .github/ISSUE_TEMPLATE/tracking_issue.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
---
name: Tracking Issue
about: A tracking issue for an accepted feature or RFC in Rust.
about: A tracking issue for an unstable feature in Rust.
title: Tracking Issue for XXX
labels: C-tracking-issue
---
<!--
NOTE: For library features, please use the "Library Tracking Issue" template instead.
Thank you for creating a tracking issue! 📜 Tracking issues are for tracking a
feature from implementation to stabilisation. Make sure to include the relevant
RFC for the feature if it has one. Otherwise provide a short summary of the
feature and link any relevant PRs or issues, and remove any sections that are
not relevant to the feature.
feature from implementation to stabilisation.
Remember to add team labels to the tracking issue.
For a language team feature, this would e.g., be `T-lang`.
For a language team feature, this would e.g., be `T-lang`:
> @rustbot label T-lang
Such a feature should also be labeled with e.g., `F-my_feature`.
This label is used to associate issues (e.g., bugs and design questions) to the feature.
-->

This is a tracking issue for the RFC "XXX" (rust-lang/rfcs#NNN).
The feature gate for the issue is `#![feature(FFF)]`.
This is a tracking issue for `#![feature(FFF)]`.
The RFC for this feature is rust-lang/rfcs#NNN.

<!--
Make sure to include the relevant RFC for the feature if it has one.
Otherwise, provide a short summary and motivation of the
feature and link any relevant PRs or issues.
Remove any sections that are not relevant to the feature.
-->

### About tracking issues

Expand All @@ -38,8 +46,8 @@ implementing a feature, followed by a PR that stabilises the feature. However
for larger features an implementation could be broken up into multiple PRs.
-->

- [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring
instructions?)
- [ ] Create the feature gate
- [ ] Implement the feature
- [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide])
- [ ] Style updates for any new syntax ([nightly-style-procedure])
- [ ] Style team decision on new formatting
Expand All @@ -59,8 +67,8 @@ stabilised. It is useful to link related discussions and conculsions as they
develop.
-->

- [ ] list all the "unresolved questions" found in the RFC to ensure they are
not forgotten.
- [ ] List any unresolved questions, including those listed in the RFC if there is one,
to ensure they are not forgotten.

### Implementation history

Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_codegen_llvm/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ pub(crate) fn declare_simple_fn<'ll>(
ty: &'ll Type,
) -> &'ll Value {
debug!("declare_simple_fn(name={:?}, ty={:?})", name, ty);
let llfn = unsafe {
llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
};
let llfn =
unsafe { llvm::LLVMGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty) };

llvm::SetFunctionCallConv(llfn, callconv);
llvm::set_unnamed_address(llfn, unnamed);
Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,12 @@ unsafe extern "C" {
FunctionTy: &'a Type,
) -> &'a Value;
pub(crate) fn LLVMDeleteFunction(Fn: &Value);
pub(crate) fn LLVMGetOrInsertFunction<'a>(
M: &'a Module,
Name: *const c_char,
NameLen: size_t,
FunctionTy: &'a Type,
) -> &'a Value;

// Operations about llvm intrinsics
pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint;
Expand Down Expand Up @@ -2033,13 +2039,6 @@ unsafe extern "C" {
) -> &Attribute;

// Operations on functions
/// FIXME: After dropping LLVM 21, migrate to LLVM-C's `LLVMGetOrInsertFunction`.
pub(crate) fn LLVMRustGetOrInsertFunction<'a>(
M: &'a Module,
Name: *const c_char,
NameLen: size_t,
FunctionTy: &'a Type,
) -> &'a Value;
pub(crate) fn LLVMRustAddFunctionAttributes<'a>(
Fn: &'a Value,
index: c_uint,
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_const_eval/src/const_eval/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
self.project_downcast_named(&field_dest, sym::Slice)?;
variant
}
ty::Adt(adt_def, generics) => {
self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
}
ty::Adt(adt_def, _) => self.write_adt_type_info(&field_dest, *adt_def)?,
ty::Bool => {
let (variant, _variant_place) =
self.project_downcast_named(&field_dest, sym::Bool)?;
Expand Down
178 changes: 6 additions & 172 deletions compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
Original file line number Diff line number Diff line change
@@ -1,204 +1,38 @@
use rustc_abi::{FieldIdx, VariantIdx};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{
AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, Ty, VariantDef,
AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, Ty,
};
use rustc_span::{bug, span_bug, sym};

use crate::const_eval::CompileTimeMachine;
use crate::interpret::{
CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Projectable, Scalar, Writeable, interp_ok,
CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Projectable, Writeable, interp_ok,
};

impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
// FIXME(type_info): No semver considerations for now
pub(crate) fn write_adt_type_info(
&mut self,
place: &impl Writeable<'tcx, CtfeProvenance>,
adt: (Ty<'tcx>, AdtDef<'tcx>),
generics: &'tcx GenericArgs<'tcx>,
adt_def: AdtDef<'tcx>,
) -> InterpResult<'tcx, VariantIdx> {
let (adt_ty, adt_def) = adt;
let variant_idx = match adt_def.adt_kind() {
AdtKind::Struct => {
let (variant, variant_place) = self.project_downcast_named(place, sym::Struct)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_struct_type_info(
place,
(adt_ty, adt_def.variant(VariantIdx::ZERO)),
generics,
)?;
let (variant, _) = self.project_downcast_named(place, sym::Struct)?;
variant
}
AdtKind::Union => {
let (variant, variant_place) = self.project_downcast_named(place, sym::Union)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_union_type_info(
place,
(adt_ty, adt_def.variant(VariantIdx::ZERO)),
generics,
)?;
let (variant, _) = self.project_downcast_named(place, sym::Union)?;
variant
}
AdtKind::Enum => {
let (variant, variant_place) = self.project_downcast_named(place, sym::Enum)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_enum_type_info(place, adt, generics)?;
let (variant, _) = self.project_downcast_named(place, sym::Enum)?;
variant
}
};
interp_ok(variant_idx)
}

pub(crate) fn write_struct_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
struct_: (Ty<'tcx>, &'tcx VariantDef),
generics: &'tcx GenericArgs<'tcx>,
) -> InterpResult<'tcx> {
let (struct_ty, struct_def) = struct_;
let struct_layout = self.layout_of(struct_ty)?;

for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;

match field.name {
sym::generics => self.write_generics(&field_place, generics)?,
sym::fields => {
self.write_variant_fields(field_place, struct_def, struct_layout, generics)?
}
sym::non_exhaustive => {
let is_non_exhaustive = struct_def.is_field_list_non_exhaustive();
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}

interp_ok(())
}

pub(crate) fn write_union_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
union_: (Ty<'tcx>, &'tcx VariantDef),
generics: &'tcx GenericArgs<'tcx>,
) -> InterpResult<'tcx> {
let (union_ty, union_def) = union_;
let union_layout = self.layout_of(union_ty)?;

for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;

match field.name {
sym::generics => self.write_generics(&field_place, generics)?,
sym::fields => {
self.write_variant_fields(field_place, union_def, union_layout, generics)?
}
sym::non_exhaustive => {
let is_non_exhaustive = union_def.is_field_list_non_exhaustive();
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}

interp_ok(())
}

pub(crate) fn write_enum_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
enum_: (Ty<'tcx>, AdtDef<'tcx>),
generics: &'tcx GenericArgs<'tcx>,
) -> InterpResult<'tcx> {
let (enum_ty, enum_def) = enum_;
let enum_layout = self.layout_of(enum_ty)?;

for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;

match field.name {
sym::generics => self.write_generics(&field_place, generics)?,
sym::type_id_variants => {
self.allocate_fill_and_write_slice_ptr(
&field_place,
enum_def.variants().len() as u64,
|this, i, place| {
let variant_idx = VariantIdx::from_usize(i as usize);
let variant_def = &enum_def.variants()[variant_idx];
let variant_layout = enum_layout.for_variant(this, variant_idx);
this.write_enum_variant(place, (variant_layout, &variant_def), generics)
},
)?;
}
sym::non_exhaustive => {
let is_non_exhaustive = enum_def.is_variant_list_non_exhaustive();
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}

interp_ok(())
}

fn write_enum_variant(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
variant: (TyAndLayout<'tcx>, &'tcx VariantDef),
generics: &'tcx GenericArgs<'tcx>,
) -> InterpResult<'tcx> {
let (variant_layout, variant_def) = variant;

for (field_idx, field_def) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;
match field_def.name {
sym::name => {
let name_place = self.allocate_str_dedup(variant_def.name.as_str())?;
let ptr = self.mplace_to_imm_ptr(&name_place, None)?;
self.write_immediate(*ptr, &field_place)?
}
sym::fields => {
self.write_variant_fields(field_place, &variant_def, variant_layout, generics)?
}
sym::non_exhaustive => {
let is_non_exhaustive = variant_def.is_field_list_non_exhaustive();
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
}
other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
}
}
interp_ok(())
}

// Write fields for struct, enum variants
fn write_variant_fields(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
variant_def: &'tcx VariantDef,
variant_layout: TyAndLayout<'tcx>,
generics: &'tcx GenericArgs<'tcx>,
) -> InterpResult<'tcx> {
self.allocate_fill_and_write_slice_ptr(
&place,
variant_def.fields.len() as u64,
|this, i, place| {
let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)];
let field_ty = field_def.ty(*this.tcx, generics).skip_norm_wip();
this.write_field(field_ty, place, variant_layout, Some(field_def.name), i)
},
)
}

pub(super) fn write_generics(
&mut self,
place: &impl Writeable<'tcx, CtfeProvenance>,
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,6 @@ LLVMRustVerifyFunction(LLVMValueRef Fn, LLVMRustVerifierFailureAction Action) {
return LLVMVerifyFunction(Fn, fromRust(Action));
}

extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
const char *Name,
size_t NameLen,
LLVMTypeRef FunctionTy) {
return wrap(unwrap(M)
->getOrInsertFunction(StringRef(Name, NameLen),
unwrap<FunctionType>(FunctionTy))
.getCallee());
}

// Get the global variable with the given name if it exists or create a new
// external global.
extern "C" LLVMValueRef
Expand Down
38 changes: 38 additions & 0 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2287,6 +2287,44 @@ impl<'a> Parser<'a> {
}
}

/// Handle encountering a lifetime in a generic argument list that is not
/// followed by a `,` or `>`.
/// We emit an error and check if the lifetime is followed by a type
/// in, e.g. `Foo<'a T>`.
/// In this case, it is likely the user meant either `Foo<&'a T>` or `Foo<'a, T>`.
/// We give both suggestions, then emit an error. Note that we do not try to recover,
/// since we cannot know which of the two suggestions is correct and emitting either
/// of the two types could cause confusing errors further on.
pub(super) fn handle_lifetime_arg_preceding_type(&mut self, span: Span) -> PResult<'a, ()> {
let snapshot = self.create_snapshot_for_diagnostic();
let (mutbl, ty) = self.parse_ref_ty_no_leading_ampersand();
self.restore_snapshot(snapshot);
if ty.is_none() {
// The lifetime is not followed by a type, do nothing.
return Ok(());
}
// If we find `'a mut T`, suggesting to add a comma is wrong.
let suggest_comma = mutbl.is_not();
// Add `>` to the list of expected tokens.
self.check(exp!(Gt));
let mut err = self.unexpected().unwrap_err();
err.span_suggestion_verbose(
span.shrink_to_lo(),
"you might have meant to write a reference type here",
"&",
Applicability::MaybeIncorrect,
);
if suggest_comma {
err.span_suggestion_verbose(
span.shrink_to_hi(),
"use a comma to separate type parameters",
",",
Applicability::MaybeIncorrect,
);
}
Err(err.into())
}

/// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this
/// case, we emit an error and try to suggest enclosing a const argument in braces if it looks
/// like the user has forgotten them.
Expand Down
Loading
Loading