Skip to content

Commit 59bc26c

Browse files
committed
Auto merge of #157044 - matthiaskrgr:rollup-BX6I8YG, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #156932 (relnotes for 1.96) - #156403 (Add `TypeId` methods `variants` `fields` `field` for `type_info`) - #156797 (Suggest adding quotation marks to identifiers in attributes) - #157014 (Allow building the source tarballs while offline) - #157023 (`#[expect]` is an attribute valid for outer style) - #157025 (Show crate root path in misplaced crate-level attribute diagnostic)
2 parents 8f02e85 + 89777ad commit 59bc26c

22 files changed

Lines changed: 635 additions & 14 deletions

File tree

RELEASES.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,96 @@
1+
Version 1.96.0 (2026-05-28)
2+
==========================
3+
4+
<a id="1.96.0-Language"></a>
5+
6+
Language
7+
--------
8+
- [Allow passing `expr` metavariable to `cfg`](https://github.com/rust-lang/rust/pull/146961)
9+
- [Always coerce never types in tuple expressions](https://github.com/rust-lang/rust/pull/147834)
10+
- [Avoid incorrect inference guidance of function arguments in rare cases](https://github.com/rust-lang/rust/pull/150316)
11+
- [Support s390x vector registers in inline assembly](https://github.com/rust-lang/rust/pull/154184)
12+
- [Allow using constants of type `ManuallyDrop` as patterns (fixing a regression introduced in 1.94.0)](https://github.com/rust-lang/rust/pull/154891)
13+
14+
<a id="1.96.0-Compiler"></a>
15+
16+
Compiler
17+
--------
18+
- [Enable link relaxation feature for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/153427)
19+
- [Update `riscv64gc-unknown-fuchsia` baseline to RVA22 + vector](https://github.com/rust-lang/rust/pull/155072)
20+
21+
<a id="1.96.0-Libraries"></a>
22+
23+
Libraries
24+
---------
25+
- [Support iterating over ranges of `NonZero` integers](https://github.com/rust-lang/rust/pull/127534)
26+
- [refactor 'valid for read/write' definition: exclude null; add that as an exception on individual methods instead](https://github.com/rust-lang/rust/pull/152615)
27+
- [Fix SGX delayed host lookup via ToSocketAddr](https://github.com/rust-lang/rust/pull/152851)
28+
29+
<a id="1.96.0-Stabilized-APIs"></a>
30+
31+
Stabilized APIs
32+
---------------
33+
34+
- [`assert_matches!`](https://doc.rust-lang.org/stable/std/macro.assert_matches.html)
35+
- [`debug_assert_matches!`](https://doc.rust-lang.org/stable/std/macro.debug_assert_matches.html)
36+
- [`From<T> for AssertUnwindSafe<T>`](https://doc.rust-lang.org/stable/std/panic/struct.AssertUnwindSafe.html#impl-From%3CT%3E-for-AssertUnwindSafe%3CT%3E)
37+
- [`From<T> for LazyCell<T, F>`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#impl-From%3CT%3E-for-LazyCell%3CT,+F%3E)
38+
- [`From<T> for LazyLock<T, F>`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#impl-From%3CT%3E-for-LazyLock%3CT,+F%3E)
39+
- [`core::range::RangeToInclusive`](https://doc.rust-lang.org/stable/core/range/struct.RangeToInclusive.html)
40+
- [`core::range::RangeToInclusiveIter`](https://doc.rust-lang.org/stable/core/range/struct.RangeToInclusiveIter.html)
41+
- [`core::range::RangeFrom`](https://doc.rust-lang.org/stable/core/ops/struct.RangeFrom.html)
42+
- [`core::range::RangeFromIter`](https://doc.rust-lang.org/stable/core/ops/struct.RangeFromIter.html)
43+
- [`core::range::Range`](https://doc.rust-lang.org/stable/std/range/struct.Range.html)
44+
- [`core::range::RangeIter`](https://doc.rust-lang.org/stable/std/range/struct.RangeIter.html)
45+
46+
<a id="1.96.0-Cargo"></a>
47+
48+
Cargo
49+
-----
50+
- [Allow a dependency to specify both a git repository and an alternate registry.](https://github.com/rust-lang/cargo/pull/16810/) Just like with crates.io, the git repository will be used locally, but the registry version will be used when published.
51+
- [Added `target.'cfg(..)'.rustdocflags` support in configuration.](https://github.com/rust-lang/cargo/pull/16846)
52+
- Fixed [CVE-2026-5222](https://blog.rust-lang.org/2026/05/25/cve-2026-5222/) and [CVE-2026-5223](https://blog.rust-lang.org/2026/05/25/cve-2026-5223/).
53+
54+
<a id="1.96-Rustdoc"></a>
55+
56+
Rustdoc
57+
-----
58+
- [Deprecation notes are now rendered like any other documentation](https://github.com/rust-lang/rust/pull/149931). Previously they used the css `white-space: pre-wrap;` property and stripped any `<p>` elements from the rendered html, however this caused issues and unintuitive behavior. The new behavior should be more predictable, however some multi-line deprecation notes will now be rendered as as single lines. If this is undesirable, you can use the standard markdown method of forcing a linebreak, which is two spaces followed by a newline (`"\n"`).
59+
- [Don't emit rustdoc `missing_doc_code_examples` lint on impl items](https://github.com/rust-lang/rust/pull/154048)
60+
- [Seperate methods and associated functions in sidebar](https://github.com/rust-lang/rust/pull/154644)
61+
62+
<a id="1.96.0-Compatibility-Notes"></a>
63+
64+
Compatibility Notes
65+
-------------------
66+
- [Fix layout of `#[repr(Int)]` enums in some edge cases involving fields of uninhabited zero-sized types](https://github.com/rust-lang/rust/pull/146989)
67+
- [Prevent unsize-coercing into `Pin<Foo>` where `Foo` doesn't implement `Deref`. Some such coercions were previously allowed, but produce a type with no useful public API.](https://github.com/rust-lang/rust/pull/149218)
68+
- [rustc: Stop passing `--allow-undefined` on wasm targets](https://github.com/rust-lang/rust/pull/149868)
69+
- [Gate the accidentally stabilized `#![reexport_test_harness_main]` attribute](https://github.com/rust-lang/rust/pull/152210)
70+
- [Error on return-position-impl-trait-in-traits whose types are too private](https://github.com/rust-lang/rust/pull/152543)
71+
- [Report the `uninhabited_static` lint in dependencies and make it deny-by-default](https://github.com/rust-lang/rust/pull/152853)
72+
- [Distributed builds now contain non-split debuginfo for windows-gnu](https://github.com/rust-lang/rust/pull/152870)
73+
This appears to improve the quality of backtraces. This change has no effect on the defaults for the output of rustc/cargo on these targets.
74+
- [Check const generic arguments are correctly typed in more positions](https://github.com/rust-lang/rust/pull/152931)
75+
- [Remove `-Csoft-float`](https://github.com/rust-lang/rust/pull/152973)
76+
- [Importing structs with `::{self [as name]}`, e.g., `struct S {}; use S::{self as Other};`, is now no longer permitted because `{self}` imports require a module parent.](https://github.com/rust-lang/rust/pull/152996)
77+
- [For `export_name`, `link_name`, and `link_section` attributes, if multiple of the same attribute is present, the first one now takes precedence.](https://github.com/rust-lang/rust/pull/153041)
78+
- [Update the minimum external LLVM to 21](https://github.com/rust-lang/rust/pull/153684)
79+
- On `avr` targets, C's `double` type is 32-bit by default, so [change `c_double` to `f32` on `avr` targets to match](https://github.com/rust-lang/rust/pull/154647). This is a breaking change, but necessary to make `c_double` match C's double.
80+
81+
<a id="1.96.0-Internal-Changes"></a>
82+
83+
Internal Changes
84+
----------------
85+
86+
These changes do not affect any public interfaces of Rust, but they represent
87+
significant improvements to the performance or internals of rustc and related
88+
tools.
89+
90+
- [JSON targets: `aarch64` softfloat targets now have to have `rustc_abi` set to `"softfloat"`](https://github.com/rust-lang/rust/pull/152941)
91+
- [target specs: stricter checks for LLVM ABI values, and correlate that with `cfg(target_abi)`](https://github.com/rust-lang/rust/pull/153769)
92+
93+
194
Version 1.95.0 (2026-04-16)
295
===========================
396

compiler/rustc_ast/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3497,6 +3497,7 @@ impl AttrItem {
34973497
|| self.path == sym::warn
34983498
|| self.path == sym::allow
34993499
|| self.path == sym::deny
3500+
|| self.path == sym::expect
35003501
}
35013502
}
35023503

compiler/rustc_attr_parsing/src/errors.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ pub(crate) struct InvalidAttrStyle {
165165
#[note("this attribute does not have an `!`, which means it is applied to this {$target}")]
166166
pub target_span: Option<Span>,
167167
pub target: &'static str,
168+
pub crate_root_path: String,
169+
#[help("the crate root is at `{$crate_root_path}`")]
170+
pub show_crate_root_help: bool,
168171
}
169172

170173
#[derive(Diagnostic)]

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_ast::{
1212
AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp,
1313
};
1414
use rustc_ast_pretty::pprust;
15-
use rustc_errors::{Diag, PResult};
15+
use rustc_errors::{Applicability, Diag, PResult};
1616
use rustc_hir::{self as hir, AttrPath};
1717
use rustc_parse::exp;
1818
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
@@ -410,7 +410,20 @@ fn expr_to_lit<'sess>(
410410
// - `#[foo = include_str!("nonexistent-file.rs")]`:
411411
// results in `ast::ExprKind::Err`.
412412
let msg = "attribute value must be a literal";
413-
let err = psess.dcx().struct_span_err(span, msg);
413+
let mut err = psess.dcx().struct_span_err(span, msg);
414+
415+
// Suggest adding quotation marks to turn an identifier into a string literal
416+
if let ExprKind::Path(None, ref path) = expr.kind
417+
&& let [segment] = path.segments.as_slice()
418+
{
419+
err.span_suggestion(
420+
expr.span,
421+
"try adding quotation marks",
422+
&format!("\"{}\"", segment.ident),
423+
Applicability::MaybeIncorrect,
424+
);
425+
}
426+
414427
Err(err)
415428
}
416429
}

compiler/rustc_attr_parsing/src/target_checking.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan, StashKey};
55
use rustc_feature::Features;
66
use rustc_hir::attrs::AttributeKind;
77
use rustc_hir::{AttrItem, Attribute, MethodKind, Target};
8-
use rustc_span::{BytePos, Span, Symbol, sym};
8+
use rustc_span::{BytePos, FileName, RemapPathScopeComponents, Span, Symbol, sym};
99

1010
use crate::AttributeParser;
1111
use crate::context::AcceptContext;
@@ -186,13 +186,29 @@ impl<'sess> AttributeParser<'sess> {
186186
let target_span = cx.target_span;
187187
let attr_span = cx.attr_span;
188188

189+
let (show_crate_root_help, crate_root_path) = is_used_as_inner
190+
.then(|| cx.cx.sess.local_crate_source_file())
191+
.flatten()
192+
.filter(|src| {
193+
!matches!(
194+
cx.cx.sess.source_map().span_to_filename(attr_span),
195+
FileName::Real(ref name) if name == src
196+
)
197+
})
198+
.map(|src| {
199+
(true, src.path(RemapPathScopeComponents::DIAGNOSTICS).display().to_string())
200+
})
201+
.unwrap_or_default();
202+
189203
cx.emit_lint(
190204
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
191205
crate::errors::InvalidAttrStyle {
192206
name,
193207
is_used_as_inner,
194208
target_span: (!is_used_as_inner).then_some(target_span),
195209
target: target.name(),
210+
crate_root_path,
211+
show_crate_root_help,
196212
},
197213
attr_span,
198214
);

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow};
22
use std::hash::Hash;
33
use std::{fmt, mem};
44

5-
use rustc_abi::{Align, FIRST_VARIANT, FieldIdx, Size};
5+
use rustc_abi::{Align, FIRST_VARIANT, FieldIdx, Size, VariantIdx};
66
use rustc_ast::Mutability;
77
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
88
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -622,6 +622,75 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
622622
ecx.write_discriminant(variant_index, dest)?;
623623
}
624624

625+
sym::type_id_fields => {
626+
let ty = ecx.read_type_id(&args[0])?;
627+
let variant_idx = ecx.read_target_usize(&args[1])? as usize;
628+
629+
let variants_num =
630+
ty.ty_adt_def().map(|adt_def| adt_def.variants().len()).unwrap_or(1);
631+
if variant_idx >= variants_num {
632+
throw_ub!(BoundsCheckFailed {
633+
len: variants_num as u64,
634+
index: variant_idx as u64
635+
});
636+
}
637+
638+
let fields_num = match ty.kind() {
639+
ty::Adt(adt_def, _) => {
640+
let variant_def = &adt_def.variants()[VariantIdx::from_usize(variant_idx)];
641+
variant_def.fields.len()
642+
}
643+
ty::Tuple(fields) => fields.len(),
644+
_ => 0, // Other types have no fields
645+
};
646+
647+
ecx.write_scalar(Scalar::from_target_usize(fields_num as u64, ecx), dest)?;
648+
}
649+
650+
sym::type_id_field_representing_type => {
651+
let ty = ecx.read_type_id(&args[0])?;
652+
let variant_idx = ecx.read_target_usize(&args[1])? as usize;
653+
let field_idx = ecx.read_target_usize(&args[2])? as usize;
654+
655+
let variants_num =
656+
ty.ty_adt_def().map(|adt_def| adt_def.variants().len()).unwrap_or(1);
657+
if variant_idx >= variants_num {
658+
throw_ub!(BoundsCheckFailed {
659+
len: variants_num as u64,
660+
index: variant_idx as u64
661+
});
662+
}
663+
664+
let fields_num = match ty.kind() {
665+
ty::Adt(adt_def, _) => {
666+
let variant_def = &adt_def.variants()[VariantIdx::from_usize(variant_idx)];
667+
variant_def.fields.len()
668+
}
669+
ty::Tuple(fields) => fields.len(),
670+
_ => 0, // Other types have no fields
671+
};
672+
if field_idx >= fields_num {
673+
throw_ub!(BoundsCheckFailed {
674+
len: fields_num as u64,
675+
index: field_idx as u64
676+
});
677+
}
678+
679+
let frt = Ty::new_field_representing_type(
680+
*ecx.tcx,
681+
ty,
682+
VariantIdx::from_usize(variant_idx),
683+
FieldIdx::from_usize(field_idx),
684+
);
685+
ecx.write_type_id(frt, dest)?;
686+
}
687+
688+
sym::type_id_variants => {
689+
let ty = ecx.read_type_id(&args[0])?;
690+
let variants_num = ty.ty_adt_def().map(|def| def.variants().len()).unwrap_or(1);
691+
ecx.write_scalar(Scalar::from_target_usize(variants_num as u64, ecx), dest)?;
692+
}
693+
625694
sym::field_offset => {
626695
let frt_ty = instance.args.type_at(0);
627696
ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?;
@@ -643,6 +712,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
643712
ecx.write_scalar(Scalar::from_target_usize(offset, ecx), dest)?;
644713
}
645714

715+
sym::field_representing_type_actual_type_id => {
716+
let frt_ty = ecx.read_type_id(&args[0])?;
717+
718+
let field_ty = if let ty::Adt(def, args) = frt_ty.kind()
719+
&& let Some(FieldInfo { ty, .. }) =
720+
def.field_representing_type_info(ecx.tcx.tcx, args)
721+
{
722+
ecx.tcx.erase_and_anonymize_regions(ty)
723+
} else {
724+
span_bug!(ecx.cur_span(), "expected field representing type, got {frt_ty}")
725+
};
726+
ecx.write_type_id(field_ty, dest)?;
727+
}
728+
646729
_ => {
647730
// We haven't handled the intrinsic, let's see if we can use a fallback body.
648731
if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
114114
| sym::fadd_algebraic
115115
| sym::fdiv_algebraic
116116
| sym::field_offset
117+
| sym::field_representing_type_actual_type_id
117118
| sym::floorf16
118119
| sym::floorf32
119120
| sym::floorf64
@@ -213,6 +214,9 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
213214
| sym::truncf128
214215
| sym::type_id
215216
| sym::type_id_eq
217+
| sym::type_id_field_representing_type
218+
| sym::type_id_fields
219+
| sym::type_id_variants
216220
| sym::type_id_vtable
217221
| sym::type_name
218222
| sym::type_of
@@ -319,6 +323,11 @@ pub(crate) fn check_intrinsic_type(
319323
sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
320324
sym::type_id => (1, 0, vec![], type_id_ty()),
321325
sym::type_id_eq => (0, 0, vec![type_id_ty(), type_id_ty()], tcx.types.bool),
326+
sym::type_id_field_representing_type => {
327+
(0, 0, vec![type_id_ty(), tcx.types.usize, tcx.types.usize], type_id_ty())
328+
}
329+
sym::type_id_fields => (0, 0, vec![type_id_ty(), tcx.types.usize], tcx.types.usize),
330+
sym::type_id_variants => (0, 0, vec![type_id_ty()], tcx.types.usize),
322331
sym::type_id_vtable => {
323332
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span);
324333
let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata);
@@ -339,6 +348,7 @@ pub(crate) fn check_intrinsic_type(
339348
vec![type_id_ty()],
340349
tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(),
341350
),
351+
sym::field_representing_type_actual_type_id => (0, 0, vec![type_id_ty()], type_id_ty()),
342352
sym::offload => (
343353
3,
344354
0,

compiler/rustc_span/src/symbol.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ symbols! {
948948
field_offset,
949949
field_projections,
950950
field_representing_type,
951+
field_representing_type_actual_type_id,
951952
field_representing_type_raw,
952953
field_type,
953954
fields,
@@ -2098,6 +2099,9 @@ symbols! {
20982099
type_changing_struct_update,
20992100
type_id,
21002101
type_id_eq,
2102+
type_id_field_representing_type,
2103+
type_id_fields,
2104+
type_id_variants,
21012105
type_id_vtable,
21022106
type_info,
21032107
type_ir,

library/core/src/any.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ impl TypeId {
829829
}
830830
}
831831

832-
fn as_u128(self) -> u128 {
832+
pub(crate) fn as_u128(self) -> u128 {
833833
let mut bytes = [0; 16];
834834

835835
// This is a provenance-stripping memcpy.

0 commit comments

Comments
 (0)