diff --git a/RELEASES.md b/RELEASES.md index 87768b2f74e76..4982b54f0f886 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,96 @@ +Version 1.96.0 (2026-05-28) +========================== + + + +Language +-------- +- [Allow passing `expr` metavariable to `cfg`](https://github.com/rust-lang/rust/pull/146961) +- [Always coerce never types in tuple expressions](https://github.com/rust-lang/rust/pull/147834) +- [Avoid incorrect inference guidance of function arguments in rare cases](https://github.com/rust-lang/rust/pull/150316) +- [Support s390x vector registers in inline assembly](https://github.com/rust-lang/rust/pull/154184) +- [Allow using constants of type `ManuallyDrop` as patterns (fixing a regression introduced in 1.94.0)](https://github.com/rust-lang/rust/pull/154891) + + + +Compiler +-------- +- [Enable link relaxation feature for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/153427) +- [Update `riscv64gc-unknown-fuchsia` baseline to RVA22 + vector](https://github.com/rust-lang/rust/pull/155072) + + + +Libraries +--------- +- [Support iterating over ranges of `NonZero` integers](https://github.com/rust-lang/rust/pull/127534) +- [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) +- [Fix SGX delayed host lookup via ToSocketAddr](https://github.com/rust-lang/rust/pull/152851) + + + +Stabilized APIs +--------------- + +- [`assert_matches!`](https://doc.rust-lang.org/stable/std/macro.assert_matches.html) +- [`debug_assert_matches!`](https://doc.rust-lang.org/stable/std/macro.debug_assert_matches.html) +- [`From for AssertUnwindSafe`](https://doc.rust-lang.org/stable/std/panic/struct.AssertUnwindSafe.html#impl-From%3CT%3E-for-AssertUnwindSafe%3CT%3E) +- [`From for LazyCell`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#impl-From%3CT%3E-for-LazyCell%3CT,+F%3E) +- [`From for LazyLock`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#impl-From%3CT%3E-for-LazyLock%3CT,+F%3E) +- [`core::range::RangeToInclusive`](https://doc.rust-lang.org/stable/core/range/struct.RangeToInclusive.html) +- [`core::range::RangeToInclusiveIter`](https://doc.rust-lang.org/stable/core/range/struct.RangeToInclusiveIter.html) +- [`core::range::RangeFrom`](https://doc.rust-lang.org/stable/core/ops/struct.RangeFrom.html) +- [`core::range::RangeFromIter`](https://doc.rust-lang.org/stable/core/ops/struct.RangeFromIter.html) +- [`core::range::Range`](https://doc.rust-lang.org/stable/std/range/struct.Range.html) +- [`core::range::RangeIter`](https://doc.rust-lang.org/stable/std/range/struct.RangeIter.html) + + + +Cargo +----- +- [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. +- [Added `target.'cfg(..)'.rustdocflags` support in configuration.](https://github.com/rust-lang/cargo/pull/16846) +- 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/). + + + +Rustdoc +----- +- [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 `

` 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"`). +- [Don't emit rustdoc `missing_doc_code_examples` lint on impl items](https://github.com/rust-lang/rust/pull/154048) +- [Seperate methods and associated functions in sidebar](https://github.com/rust-lang/rust/pull/154644) + + + +Compatibility Notes +------------------- +- [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) +- [Prevent unsize-coercing into `Pin` 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) +- [rustc: Stop passing `--allow-undefined` on wasm targets](https://github.com/rust-lang/rust/pull/149868) +- [Gate the accidentally stabilized `#![reexport_test_harness_main]` attribute](https://github.com/rust-lang/rust/pull/152210) +- [Error on return-position-impl-trait-in-traits whose types are too private](https://github.com/rust-lang/rust/pull/152543) +- [Report the `uninhabited_static` lint in dependencies and make it deny-by-default](https://github.com/rust-lang/rust/pull/152853) +- [Distributed builds now contain non-split debuginfo for windows-gnu](https://github.com/rust-lang/rust/pull/152870) + 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. +- [Check const generic arguments are correctly typed in more positions](https://github.com/rust-lang/rust/pull/152931) +- [Remove `-Csoft-float`](https://github.com/rust-lang/rust/pull/152973) +- [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) +- [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) +- [Update the minimum external LLVM to 21](https://github.com/rust-lang/rust/pull/153684) +- 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. + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [JSON targets: `aarch64` softfloat targets now have to have `rustc_abi` set to `"softfloat"`](https://github.com/rust-lang/rust/pull/152941) +- [target specs: stricter checks for LLVM ABI values, and correlate that with `cfg(target_abi)`](https://github.com/rust-lang/rust/pull/153769) + + Version 1.95.0 (2026-04-16) =========================== diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index af8ad425507c4..682ba78cddc5f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3497,6 +3497,7 @@ impl AttrItem { || self.path == sym::warn || self.path == sym::allow || self.path == sym::deny + || self.path == sym::expect } } diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index d2c9c1b1eb807..56f6d29778414 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -165,6 +165,9 @@ pub(crate) struct InvalidAttrStyle { #[note("this attribute does not have an `!`, which means it is applied to this {$target}")] pub target_span: Option, pub target: &'static str, + pub crate_root_path: String, + #[help("the crate root is at `{$crate_root_path}`")] + pub show_crate_root_help: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 48790f273adfc..15a9eb91a143d 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -12,7 +12,7 @@ use rustc_ast::{ AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp, }; use rustc_ast_pretty::pprust; -use rustc_errors::{Diag, PResult}; +use rustc_errors::{Applicability, Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; use rustc_parse::exp; use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr}; @@ -410,7 +410,20 @@ fn expr_to_lit<'sess>( // - `#[foo = include_str!("nonexistent-file.rs")]`: // results in `ast::ExprKind::Err`. let msg = "attribute value must be a literal"; - let err = psess.dcx().struct_span_err(span, msg); + let mut err = psess.dcx().struct_span_err(span, msg); + + // Suggest adding quotation marks to turn an identifier into a string literal + if let ExprKind::Path(None, ref path) = expr.kind + && let [segment] = path.segments.as_slice() + { + err.span_suggestion( + expr.span, + "try adding quotation marks", + &format!("\"{}\"", segment.ident), + Applicability::MaybeIncorrect, + ); + } + Err(err) } } diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index d05f1baf63dad..fe4d72b83282b 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -5,7 +5,7 @@ use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan, StashKey}; use rustc_feature::Features; use rustc_hir::attrs::AttributeKind; use rustc_hir::{AttrItem, Attribute, MethodKind, Target}; -use rustc_span::{BytePos, Span, Symbol, sym}; +use rustc_span::{BytePos, FileName, RemapPathScopeComponents, Span, Symbol, sym}; use crate::AttributeParser; use crate::context::AcceptContext; @@ -186,6 +186,20 @@ impl<'sess> AttributeParser<'sess> { let target_span = cx.target_span; let attr_span = cx.attr_span; + let (show_crate_root_help, crate_root_path) = is_used_as_inner + .then(|| cx.cx.sess.local_crate_source_file()) + .flatten() + .filter(|src| { + !matches!( + cx.cx.sess.source_map().span_to_filename(attr_span), + FileName::Real(ref name) if name == src + ) + }) + .map(|src| { + (true, src.path(RemapPathScopeComponents::DIAGNOSTICS).display().to_string()) + }) + .unwrap_or_default(); + cx.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, crate::errors::InvalidAttrStyle { @@ -193,6 +207,8 @@ impl<'sess> AttributeParser<'sess> { is_used_as_inner, target_span: (!is_used_as_inner).then_some(target_span), target: target.name(), + crate_root_path, + show_crate_root_help, }, attr_span, ); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fb456d80e465f..1dee2f34371e8 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow}; use std::hash::Hash; use std::{fmt, mem}; -use rustc_abi::{Align, FIRST_VARIANT, FieldIdx, Size}; +use rustc_abi::{Align, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -622,6 +622,75 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.write_discriminant(variant_index, dest)?; } + sym::type_id_fields => { + let ty = ecx.read_type_id(&args[0])?; + let variant_idx = ecx.read_target_usize(&args[1])? as usize; + + let variants_num = + ty.ty_adt_def().map(|adt_def| adt_def.variants().len()).unwrap_or(1); + if variant_idx >= variants_num { + throw_ub!(BoundsCheckFailed { + len: variants_num as u64, + index: variant_idx as u64 + }); + } + + let fields_num = match ty.kind() { + ty::Adt(adt_def, _) => { + let variant_def = &adt_def.variants()[VariantIdx::from_usize(variant_idx)]; + variant_def.fields.len() + } + ty::Tuple(fields) => fields.len(), + _ => 0, // Other types have no fields + }; + + ecx.write_scalar(Scalar::from_target_usize(fields_num as u64, ecx), dest)?; + } + + sym::type_id_field_representing_type => { + let ty = ecx.read_type_id(&args[0])?; + let variant_idx = ecx.read_target_usize(&args[1])? as usize; + let field_idx = ecx.read_target_usize(&args[2])? as usize; + + let variants_num = + ty.ty_adt_def().map(|adt_def| adt_def.variants().len()).unwrap_or(1); + if variant_idx >= variants_num { + throw_ub!(BoundsCheckFailed { + len: variants_num as u64, + index: variant_idx as u64 + }); + } + + let fields_num = match ty.kind() { + ty::Adt(adt_def, _) => { + let variant_def = &adt_def.variants()[VariantIdx::from_usize(variant_idx)]; + variant_def.fields.len() + } + ty::Tuple(fields) => fields.len(), + _ => 0, // Other types have no fields + }; + if field_idx >= fields_num { + throw_ub!(BoundsCheckFailed { + len: fields_num as u64, + index: field_idx as u64 + }); + } + + let frt = Ty::new_field_representing_type( + *ecx.tcx, + ty, + VariantIdx::from_usize(variant_idx), + FieldIdx::from_usize(field_idx), + ); + ecx.write_type_id(frt, dest)?; + } + + sym::type_id_variants => { + let ty = ecx.read_type_id(&args[0])?; + let variants_num = ty.ty_adt_def().map(|def| def.variants().len()).unwrap_or(1); + ecx.write_scalar(Scalar::from_target_usize(variants_num as u64, ecx), dest)?; + } + sym::field_offset => { let frt_ty = instance.args.type_at(0); ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?; @@ -643,6 +712,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.write_scalar(Scalar::from_target_usize(offset, ecx), dest)?; } + sym::field_representing_type_actual_type_id => { + let frt_ty = ecx.read_type_id(&args[0])?; + + let field_ty = if let ty::Adt(def, args) = frt_ty.kind() + && let Some(FieldInfo { ty, .. }) = + def.field_representing_type_info(ecx.tcx.tcx, args) + { + ecx.tcx.erase_and_anonymize_regions(ty) + } else { + span_bug!(ecx.cur_span(), "expected field representing type, got {frt_ty}") + }; + ecx.write_type_id(field_ty, dest)?; + } + _ => { // We haven't handled the intrinsic, let's see if we can use a fallback body. if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 9059070157fac..c1edbb4fc520d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -114,6 +114,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::fadd_algebraic | sym::fdiv_algebraic | sym::field_offset + | sym::field_representing_type_actual_type_id | sym::floorf16 | sym::floorf32 | sym::floorf64 @@ -213,6 +214,9 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::truncf128 | sym::type_id | sym::type_id_eq + | sym::type_id_field_representing_type + | sym::type_id_fields + | sym::type_id_variants | sym::type_id_vtable | sym::type_name | sym::type_of @@ -319,6 +323,11 @@ pub(crate) fn check_intrinsic_type( sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), sym::type_id => (1, 0, vec![], type_id_ty()), sym::type_id_eq => (0, 0, vec![type_id_ty(), type_id_ty()], tcx.types.bool), + sym::type_id_field_representing_type => { + (0, 0, vec![type_id_ty(), tcx.types.usize, tcx.types.usize], type_id_ty()) + } + sym::type_id_fields => (0, 0, vec![type_id_ty(), tcx.types.usize], tcx.types.usize), + sym::type_id_variants => (0, 0, vec![type_id_ty()], tcx.types.usize), sym::type_id_vtable => { let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span); let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata); @@ -339,6 +348,7 @@ pub(crate) fn check_intrinsic_type( vec![type_id_ty()], tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(), ), + sym::field_representing_type_actual_type_id => (0, 0, vec![type_id_ty()], type_id_ty()), sym::offload => ( 3, 0, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d220651fc9404..ba8ab39ede8cd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -948,6 +948,7 @@ symbols! { field_offset, field_projections, field_representing_type, + field_representing_type_actual_type_id, field_representing_type_raw, field_type, fields, @@ -2098,6 +2099,9 @@ symbols! { type_changing_struct_update, type_id, type_id_eq, + type_id_field_representing_type, + type_id_fields, + type_id_variants, type_id_vtable, type_info, type_ir, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 54a6408a06321..fc5f60e0d28b5 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -829,7 +829,7 @@ impl TypeId { } } - fn as_u128(self) -> u128 { + pub(crate) fn as_u128(self) -> u128 { let mut bytes = [0; 16]; // This is a provenance-stripping memcpy. diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 9ef9c226f3cda..82a7e3be9228e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2941,11 +2941,57 @@ pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { /// Gets the size of the type represented by this `TypeId`. /// -/// The stabilized version of this intrinsic is [`core::any::TypeId::size`]. +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::size`]. #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] pub const fn size_of_type_id(_id: crate::any::TypeId) -> Option { - panic!("`Type::size` can only be called at compile-time") + panic!("`TypeId::size` can only be called at compile-time") +} + +/// Gets the number of variants of the type represented by this `TypeId`. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::variants`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn type_id_variants(_id: crate::any::TypeId) -> usize { + panic!("`TypeId::variants` can only be called at compile-time") +} + +/// Gets the number of fields at the given `variant_index` represented by this `TypeId`. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::fields`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn type_id_fields(_id: crate::any::TypeId, _variant_index: usize) -> usize { + panic!("`TypeId::fields` can only be called at compile-time") +} + +/// Gets the [`FieldRepresentingType`]'s `TypeId` at the given index of the type represented by this `TypeId`. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::field`]. +/// +/// [`FieldRepresentingType`]: crate::field::FieldRepresentingType +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn type_id_field_representing_type( + _id: crate::any::TypeId, + _variant_index: usize, + _field_index: usize, +) -> crate::any::TypeId { + panic!("`TypeId::field` can only be called at compile-time") +} + +/// Gets the actual field `TypeId` of the [`FieldRepresentingType`]'s `TypeId`. +/// +/// The more user-friendly version of this intrinsic is [`core::mem::type_info::FieldId::type_id`]. +/// +/// [`FieldRepresentingType`]: crate::field::FieldRepresentingType +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn field_representing_type_actual_type_id( + _frt_type_id: crate::any::TypeId, +) -> crate::any::TypeId { + panic!("`FieldId::type_id` can only be called at compile-time") } /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 17c51ccaad858..8e7e51caad1f1 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -2,6 +2,7 @@ //! runtime or const-eval processable way. use crate::any::TypeId; +use crate::fmt; use crate::intrinsics::{self, type_id, type_of}; use crate::marker::PointeeSized; use crate::ptr::DynMetadata; @@ -376,4 +377,201 @@ impl TypeId { pub const fn size(self) -> Option { intrinsics::size_of_type_id(self) } + + /// Returns the number of variants of the type represented by this `TypeId`. + /// + /// For enums, this is the number of variants. For structs and unions, this is always 1. + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert_eq!(const { TypeId::of::>().variants() }, 2); + /// + /// struct Unit; + /// struct Point { + /// x: u32, + /// y: u32, + /// } + /// assert_eq!(const { TypeId::of::().variants() }, 1); + /// assert_eq!(const { TypeId::of::().variants() }, 1); + /// assert_eq!(const { TypeId::of::<(f32, f32)>().variants() }, 1); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn variants(self) -> usize { + intrinsics::type_id_variants(self) + } + + /// Returns the number of fields at the given `variant_index` of the type represented by this `TypeId`. + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert_eq!(const { TypeId::of::().fields(0) }, 0); + /// + /// struct Point { + /// x: u32, + /// y: u32, + /// } + /// assert_eq!(const { TypeId::of::().fields(0) }, 2); + /// + /// enum Enum { + /// Unit, + /// Tuple(u32, u64), + /// Struct { x: u32, y: u32, z: String }, + /// } + /// assert_eq!(const { TypeId::of::().fields(0) }, 0); + /// assert_eq!(const { TypeId::of::().fields(1) }, 2); + /// assert_eq!(const { TypeId::of::().fields(2) }, 3); + /// ``` + /// + /// The variant index refers to the source order index of a variant in a type. + /// + /// For enums, these are always `0..variant_count`, regardless of any custom discriminants that may have been defined. + /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero. + /// + /// ``` + /// enum Number { + /// Seven = 7, // variant index == 0 + /// Six = 6, // variant index == 1 + /// } + /// ``` + /// + /// Out-of-bounds indexing will be treated as a compile-time error. + /// + /// ```compile_fail,E0080 + /// # #![feature(type_info)] + /// # use std::any::TypeId; + /// # + /// # struct Point { + /// # x: u32, + /// # y: u32, + /// # } + /// # enum Enum { + /// # Unit, + /// # Tuple(u32, u64), + /// # Struct { x: u32, y: u32, z: String }, + /// # } + /// const { + /// _ = TypeId::of::().fields(10); // error: indexing out of bounds: the len is 2 but the index is 10 + /// _ = TypeId::of::().fields(10); // error: indexing out of bounds: the len is 3 but the index is 10 + /// } + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn fields(self, variant_index: usize) -> usize { + intrinsics::type_id_fields(self, variant_index) + } + + /// Returns the field representing type at the given index of the type represented by this `TypeId`. + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// struct Point { + /// x: u32, + /// y: u32, + /// } + /// assert_eq!(const { TypeId::of::().field(0, 0).type_id() }, TypeId::of::()); + /// assert_eq!(const { TypeId::of::().field(0, 1).type_id() }, TypeId::of::()); + /// + /// enum Enum { + /// Unit, + /// Tuple(u32, u64), + /// Struct { x: u32, y: u32, z: String }, + /// } + /// assert_eq!(const { TypeId::of::().field(1, 0).type_id() }, TypeId::of::()); + /// assert_eq!(const { TypeId::of::().field(2, 2).type_id() }, TypeId::of::()); + /// ``` + /// + /// The variant index and field index refer to the source order index of a variant in a type and + /// the source order index of a field in a variant, respectively. + /// + /// For enums, variant indexes are always `0..variant_count`, regardless of any custom discriminants that may have been defined. + /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero. + /// + /// As for field indexes, they may not be the same as the layout order for `repr(Rust)` types, but they are for `repr(C)` types. + /// + /// ``` + /// enum Enum { + /// Foo, // variant index == 0 + /// Bar { // variant index == 1 + /// a: (), // field index == 0 in `Bar` + /// b: (), // field index == 1 in `Bar` + /// } + /// } + /// ``` + /// + /// Out-of-bounds indexing will be treated as a compile-time error. + /// + /// ```compile_fail,E0080 + /// # #![feature(type_info)] + /// # use std::any::TypeId; + /// # + /// # struct Point { + /// # x: u32, + /// # y: u32, + /// # } + /// # enum Enum { + /// # Unit, + /// # Tuple(u32, u64), + /// # Struct { x: u32, y: u32, z: String }, + /// # } + /// const { + /// _ = TypeId::of::().field(0, 10); // error: indexing out of bounds: the len is 2 but the index is 10 + /// _ = TypeId::of::().field(2, 10); // error: indexing out of bounds: the len is 3 but the index is 10 + /// } + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn field(self, variant_index: usize, field_index: usize) -> FieldId { + FieldId { + frt_type_id: intrinsics::type_id_field_representing_type( + self, + variant_index, + field_index, + ), + } + } +} + +/// Field representing type ID. Representing a field of a struct, tuple or enum variant. +#[derive(Copy, PartialOrd, Ord, Hash)] +#[derive_const(Clone, PartialEq, Eq)] +#[unstable(feature = "type_info", issue = "146922")] +pub struct FieldId { + frt_type_id: TypeId, +} + +#[unstable(feature = "type_info", issue = "146922")] +impl fmt::Debug for FieldId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "FieldId({:#034x})", self.frt_type_id.as_u128()) + } +} + +impl FieldId { + /// Returns the `TypeId` of the actual field type. + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// struct Point { + /// x: u32, + /// y: u32, + /// } + /// assert_eq!( + /// const { TypeId::of::().field(0, 0).type_id() }, + /// TypeId::of::() + /// ); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn type_id(self) -> TypeId { + intrinsics::field_representing_type_actual_type_id(self.frt_type_id) + } } diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index e02077b96d35a..9a37a2ba0db5f 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -67,6 +67,26 @@ fn test_tuples() { _ => unreachable!(), } } + + const { + let ty_id = TypeId::of::<()>(); + assert!(ty_id.size() == Some(size_of::<()>())); + assert!(ty_id.variants() == 1); + assert!(ty_id.fields(0) == 0); + + let ty_id = TypeId::of::<(u8,)>(); + assert!(ty_id.size() == Some(size_of::<(u8,)>())); + assert!(ty_id.variants() == 1); + assert!(ty_id.fields(0) == 1); + assert!(ty_id.field(0, 0).type_id() == TypeId::of::()); + + let ty_id = TypeId::of::<(u8, u16)>(); + assert!(ty_id.size() == Some(size_of::<(u8, u16)>())); + assert!(ty_id.variants() == 1); + assert!(ty_id.fields(0) == 2); + assert!(ty_id.field(0, 0).type_id() == TypeId::of::()); + assert!(ty_id.field(0, 1).type_id() == TypeId::of::()); + } } #[test] @@ -95,6 +115,11 @@ fn test_structs() { let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); + assert!(ty_id.fields(0) == 3); + assert!(ty_id.field(0, 0).type_id() == TypeId::of::()); + assert!(ty_id.field(0, 1).type_id() == TypeId::of::()); + assert!(ty_id.field(0, 2).type_id() == TypeId::of::<&u16>()); } const { @@ -116,6 +141,13 @@ fn test_structs() { assert!(ty.fields[0].ty == TypeId::of::()); assert!(ty.fields[1].name == "1"); assert!(ty.fields[1].ty == TypeId::of::()); + + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); + assert!(ty_id.fields(0) == 2); + assert!(ty_id.field(0, 0).type_id() == TypeId::of::()); + assert!(ty_id.field(0, 1).type_id() == TypeId::of::()); } const { @@ -156,6 +188,10 @@ fn test_unions() { let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); + assert!(ty_id.fields(0) == 2); + assert!(ty_id.field(0, 0).type_id() == TypeId::of::()); + assert!(ty_id.field(0, 1).type_id() == TypeId::of::()); } const { @@ -212,6 +248,13 @@ fn test_enums() { let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 3); + assert!(ty_id.fields(0) == 1); + assert!(ty_id.fields(1) == 0); + assert!(ty_id.fields(2) == 2); + assert!(ty_id.field(0, 0).type_id() == TypeId::of::()); + assert!(ty_id.field(2, 0).type_id() == TypeId::of::<()>()); + assert!(ty_id.field(2, 1).type_id() == TypeId::of::<&str>()); } const { @@ -223,6 +266,10 @@ fn test_enums() { let ty_id = TypeId::of::>(); assert!(ty_id.size() == Some(size_of::>())); + assert!(ty_id.variants() == 2); + assert!(ty_id.fields(0) == 0); + assert!(ty_id.fields(1) == 1); + assert!(ty_id.field(1, 0).type_id() == TypeId::of::()); } } @@ -234,43 +281,51 @@ fn test_primitives() { let Type { kind: Bool(_ty), .. } = (const { Type::of::() }) else { panic!() }; let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); let Type { kind: Char(_ty), .. } = (const { Type::of::() }) else { panic!() }; let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; assert!(ty.bits == 32); assert!(ty.signed); let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; assert!(ty.bits as usize == size_of::() * 8); assert!(ty.signed); let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; assert!(ty.bits == 32); assert!(!ty.signed); let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; assert!(ty.bits as usize == size_of::() * 8); assert!(!ty.signed); let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); let Type { kind: Float(ty), .. } = (const { Type::of::() }) else { panic!() }; assert!(ty.bits == 32); let ty_id = TypeId::of::(); assert!(ty_id.size() == Some(size_of::())); + assert!(ty_id.variants() == 1); let Type { kind: Str(_ty), .. } = (const { Type::of::() }) else { panic!() }; let ty_id = TypeId::of::(); assert!(ty_id.size() == None); + assert!(ty_id.variants() == 1); } } diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 246598550553a..17bee20a525b6 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -114,6 +114,13 @@ impl Step for Vendor { cmd.arg("--sync").arg(sync_arg); } + // Reuse vendored dependencies when building source tarball for offline support. + if builder.config.vendor { + cmd.arg("--respect-source-config") + .arg("--config") + .arg(builder.src.join(".cargo").join("config.toml")); + } + // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. cmd.env("RUSTC_BOOTSTRAP", "1"); @@ -135,6 +142,13 @@ impl Step for Vendor { cmd.arg("--versioned-dirs"); } + // Reuse vendored dependencies when building source tarball for offline support. + if builder.config.vendor { + cmd.arg("--respect-source-config") + .arg("--config") + .arg(builder.src.join("library").join(".cargo").join("config.toml")); + } + // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. cmd.env("RUSTC_BOOTSTRAP", "1"); diff --git a/tests/ui/attributes/auxiliary/submod.rs b/tests/ui/attributes/auxiliary/submod.rs new file mode 100644 index 0000000000000..8c030e6dc3731 --- /dev/null +++ b/tests/ui/attributes/auxiliary/submod.rs @@ -0,0 +1 @@ +#![crate_name = "bar"] diff --git a/tests/ui/attributes/crate-root-path-in-different-file.rs b/tests/ui/attributes/crate-root-path-in-different-file.rs new file mode 100644 index 0000000000000..66e7b5d7a718b --- /dev/null +++ b/tests/ui/attributes/crate-root-path-in-different-file.rs @@ -0,0 +1,8 @@ +#![deny(unused_attributes)] + +#[path = "auxiliary/submod.rs"] +mod submod; + +fn main() {} + +//~? ERROR the `#![crate_name]` attribute can only be used at the crate root diff --git a/tests/ui/attributes/crate-root-path-in-different-file.stderr b/tests/ui/attributes/crate-root-path-in-different-file.stderr new file mode 100644 index 0000000000000..3ddb5bf455487 --- /dev/null +++ b/tests/ui/attributes/crate-root-path-in-different-file.stderr @@ -0,0 +1,15 @@ +error: the `#![crate_name]` attribute can only be used at the crate root + --> $DIR/auxiliary/submod.rs:1:1 + | +LL | #![crate_name = "bar"] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the crate root is at `$DIR/crate-root-path-in-different-file.rs` +note: the lint level is defined here + --> $DIR/crate-root-path-in-different-file.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/attributes/crate-type-non-crate.stderr b/tests/ui/attributes/crate-type-non-crate.stderr index 3ad51403db518..d27d81f784254 100644 --- a/tests/ui/attributes/crate-type-non-crate.stderr +++ b/tests/ui/attributes/crate-type-non-crate.stderr @@ -40,7 +40,7 @@ error: attribute value must be a literal --> $DIR/crate-type-non-crate.rs:9:16 | LL | #[crate_type = lib] - | ^^^ + | ^^^ help: try adding quotation marks: `"lib"` error[E0539]: malformed `crate_type` attribute input --> $DIR/crate-type-non-crate.rs:12:1 @@ -72,7 +72,7 @@ error: attribute value must be a literal --> $DIR/crate-type-non-crate.rs:14:16 | LL | #[crate_type = foo] - | ^^^ + | ^^^ help: try adding quotation marks: `"foo"` error[E0539]: malformed `crate_type` attribute input --> $DIR/crate-type-non-crate.rs:17:1 diff --git a/tests/ui/attributes/validation-on-associated-items-issue-121537.stderr b/tests/ui/attributes/validation-on-associated-items-issue-121537.stderr index 9c37bb8231790..750ca2e3aaca2 100644 --- a/tests/ui/attributes/validation-on-associated-items-issue-121537.stderr +++ b/tests/ui/attributes/validation-on-associated-items-issue-121537.stderr @@ -2,7 +2,7 @@ error: attribute value must be a literal --> $DIR/validation-on-associated-items-issue-121537.rs:2:13 | LL | #[doc = MyTrait] - | ^^^^^^^ + | ^^^^^^^ help: try adding quotation marks: `"MyTrait"` error: aborting due to 1 previous error diff --git a/tests/ui/darwin-objc/darwin-objc-bad-arg.stderr b/tests/ui/darwin-objc/darwin-objc-bad-arg.stderr index 99eeb27e30c1b..f75f07945a165 100644 --- a/tests/ui/darwin-objc/darwin-objc-bad-arg.stderr +++ b/tests/ui/darwin-objc/darwin-objc-bad-arg.stderr @@ -2,13 +2,13 @@ error: attribute value must be a literal --> $DIR/darwin-objc-bad-arg.rs:12:18 | LL | objc::class!(s); - | ^ + | ^ help: try adding quotation marks: `"s"` error: attribute value must be a literal --> $DIR/darwin-objc-bad-arg.rs:15:18 | LL | objc::class!(NSObject); - | ^^^^^^^^ + | ^^^^^^^^ help: try adding quotation marks: `"NSObject"` error: `objc::class!` expected a string literal --> $DIR/darwin-objc-bad-arg.rs:18:18 @@ -26,13 +26,13 @@ error: attribute value must be a literal --> $DIR/darwin-objc-bad-arg.rs:25:21 | LL | objc::selector!(s); - | ^ + | ^ help: try adding quotation marks: `"s"` error: attribute value must be a literal --> $DIR/darwin-objc-bad-arg.rs:28:21 | LL | objc::selector!(alloc); - | ^^^^^ + | ^^^^^ help: try adding quotation marks: `"alloc"` error: `objc::selector!` expected a string literal --> $DIR/darwin-objc-bad-arg.rs:31:21 diff --git a/tests/ui/parser/const-block-items/inner-attr.stderr b/tests/ui/parser/const-block-items/inner-attr.stderr index e0a70566332cf..8cd5d1487b083 100644 --- a/tests/ui/parser/const-block-items/inner-attr.stderr +++ b/tests/ui/parser/const-block-items/inner-attr.stderr @@ -8,6 +8,11 @@ LL | fn main() {} | ------------ the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the function, change the attribute from inner to outer style + | +LL - #![expect(unused)] +LL + #[expect(unused)] + | error: aborting due to 1 previous error diff --git a/tests/ui/reflection/variant_index_out_of_bounds.rs b/tests/ui/reflection/variant_index_out_of_bounds.rs new file mode 100644 index 0000000000000..2e6ac7f65927c --- /dev/null +++ b/tests/ui/reflection/variant_index_out_of_bounds.rs @@ -0,0 +1,15 @@ +#![feature(type_info)] + +use std::any::TypeId; + +fn main() {} + +const _: () = const { + TypeId::of::>().fields(2); + //~^ ERROR indexing out of bounds: the len is 2 but the index is 2 +}; + +const _: () = const { + TypeId::of::>().field(0, 1); + //~^ ERROR indexing out of bounds: the len is 0 but the index is 1 +}; diff --git a/tests/ui/reflection/variant_index_out_of_bounds.stderr b/tests/ui/reflection/variant_index_out_of_bounds.stderr new file mode 100644 index 0000000000000..177b662d84b7b --- /dev/null +++ b/tests/ui/reflection/variant_index_out_of_bounds.stderr @@ -0,0 +1,41 @@ +error[E0080]: indexing out of bounds: the len is 2 but the index is 2 + --> $DIR/variant_index_out_of_bounds.rs:8:5 + | +LL | TypeId::of::>().fields(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call + | +note: inside `type_info::::fields` + --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL + +note: erroneous constant encountered + --> $DIR/variant_index_out_of_bounds.rs:7:15 + | +LL | const _: () = const { + | _______________^ +LL | | TypeId::of::>().fields(2); +LL | | +LL | | }; + | |_^ + +error[E0080]: indexing out of bounds: the len is 0 but the index is 1 + --> $DIR/variant_index_out_of_bounds.rs:13:5 + | +LL | TypeId::of::>().field(0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call + | +note: inside `type_info::::field` + --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL + +note: erroneous constant encountered + --> $DIR/variant_index_out_of_bounds.rs:12:15 + | +LL | const _: () = const { + | _______________^ +LL | | TypeId::of::>().field(0, 1); +LL | | +LL | | }; + | |_^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`.