From e23f9b37b4b75c7869d9977bde4a5a7fa4f5f84e Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Tue, 30 Sep 2025 03:58:56 -0500 Subject: [PATCH 01/25] add additional lookup path for ref/ptr/array template args --- src/etc/lldb_providers.py | 85 +++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 17 deletions(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 65f18baa937e7..ad7c19264a8a2 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,7 +1,7 @@ from __future__ import annotations import re import sys -from typing import List, TYPE_CHECKING +from typing import List, TYPE_CHECKING, Generator from lldb import ( SBData, @@ -13,7 +13,7 @@ ) if TYPE_CHECKING: - from lldb import SBValue, SBType, SBTypeStaticField + from lldb import SBValue, SBType, SBTypeStaticField, SBTarget # from lldb.formatters import Logger @@ -133,19 +133,18 @@ def has_children(self) -> bool: return False -def get_template_args(type_name: str) -> list[str]: +def get_template_args(type_name: str) -> Generator[str, None, None]: """ Takes a type name `T, D>` and returns a list of its generic args `["A", "tuple$", "D"]`. String-based replacement for LLDB's `SBType.template_args`, as LLDB is currently unable to populate this field for targets with PDB debug info. Also useful for manually altering the type - name of generics (e.g. `Vec` -> `Vec<&str>`). + name of generics (e.g. `Vec >` -> `Vec<&str>`). Each element of the returned list can be looked up for its `SBType` value via `SBTarget.FindFirstType()` """ - params = [] level = 0 start = 0 for i, c in enumerate(type_name): @@ -156,11 +155,55 @@ def get_template_args(type_name: str) -> list[str]: elif c == ">": level -= 1 if level == 0: - params.append(type_name[start:i].strip()) + yield type_name[start:i].strip() elif c == "," and level == 1: - params.append(type_name[start:i].strip()) + yield type_name[start:i].strip() start = i + 1 - return params + + +MSVC_PTR_PREFIX: List[str] = ["ref$<", "ref_mut$<", "ptr_const$<", "ptr_mut$<"] + + +def resolve_msvc_template_arg(arg_name: str, target: SBTarget) -> SBType: + """ + RECURSIVE when arrays or references are nested (e.g. `ref$ >`, `array$ >`) + + Takes the template arg's name (likely from `get_template_args`) and finds/creates its + corresponding SBType. + + For non-reference/pointer/array types this is identical to calling + `target.FindFirstType(arg_name)` + + LLDB internally interprets refs, pointers, and arrays C-style (`&u8` -> `u8 *`, + `*const u8` -> `u8 *`, `[u8; 5]` -> `u8 [5]`). Looking up these names still doesn't work in the + current version of LLDB, so instead the types are generated via `base_type.GetPointerType()` and + `base_type.GetArrayType()`, which bypass the PDB file and ask clang directly for the type node. + """ + result = target.FindFirstType(arg_name) + + if result.IsValid(): + return result + + for prefix in MSVC_PTR_PREFIX: + if arg_name.startswith(prefix): + arg_name = arg_name[len(prefix) : -1].strip() + + result = resolve_msvc_template_arg(arg_name, target) + return result.GetPointerType() + + if arg_name.startswith("array$<"): + arg_name = arg_name[7:-1].strip() + + template_args = get_template_args(arg_name) + + element_name = next(template_args) + length = next(template_args) + + result = resolve_msvc_template_arg(element_name, target) + + return result.GetArrayType(int(length)) + + return result def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: @@ -808,6 +851,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque): # logger = Logger.Logger() # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName()) self.valobj = valobj + self.element_type = None self.update() def num_children(self) -> int: @@ -841,8 +885,9 @@ def update(self): self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) if not self.element_type.IsValid(): - element_name = get_template_args(self.valobj.GetTypeName())[0] - self.element_type = self.valobj.target.FindFirstType(element_name) + arg_name = next(get_template_args(self.valobj.GetTypeName())) + + self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target) self.element_type_size = self.element_type.GetByteSize() @@ -918,6 +963,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque): # logger = Logger.Logger() # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName()) self.valobj = valobj + self.element_type = None self.update() def num_children(self) -> int: @@ -954,6 +1000,12 @@ def update(self): ) self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) + + if not self.element_type.IsValid(): + arg_name = next(get_template_args(self.valobj.GetTypeName())) + + self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target) + self.element_type_size = self.element_type.GetByteSize() def has_children(self) -> bool: @@ -1081,6 +1133,7 @@ def get_child_at_index(self, index: int) -> SBValue: element = self.data_ptr.CreateValueFromAddress( "[%s]" % index, address, self.pair_type ) + if self.show_values: return element else: @@ -1100,14 +1153,12 @@ def update(self): self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned() - template_args = table.type.template_args + self.pair_type = table.GetType().GetTemplateArgumentType(0) - if template_args is None: - type_name = table.GetTypeName() - args = get_template_args(type_name) - self.pair_type = self.valobj.target.FindFirstType(args[0]) - else: - self.pair_type = template_args[0] + if not self.pair_type.IsValid(): + arg_name = next(get_template_args(table.GetTypeName())) + + self.pair_type = resolve_msvc_template_arg(arg_name, self.valobj.target) if self.pair_type.IsTypedefType(): self.pair_type = self.pair_type.GetTypedefedType() From 8760d55de6e5de6428588220589842360365f7bf Mon Sep 17 00:00:00 2001 From: The 8472 Date: Fri, 24 Oct 2025 23:55:52 +0200 Subject: [PATCH 02/25] benchmark path.components() iteration --- library/std/benches/path.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/std/benches/path.rs b/library/std/benches/path.rs index 094c00894a8ee..912c783b31e4c 100644 --- a/library/std/benches/path.rs +++ b/library/std/benches/path.rs @@ -55,6 +55,30 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { }); } +#[bench] +fn bench_path_components_iter(b: &mut test::Bencher) { + let p = Path::new("/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"); + + b.iter(|| { + for c in black_box(p).components() { + black_box(c); + } + }) +} + +#[bench] +fn bench_path_file_name(b: &mut test::Bencher) { + let p1 = Path::new("foo.bar"); + let p2 = Path::new("foo/bar"); + let p3 = Path::new("/bar"); + + b.iter(|| { + black_box(black_box(p1).file_name()); + black_box(black_box(p2).file_name()); + black_box(black_box(p3).file_name()); + }) +} + #[bench] #[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset(b: &mut test::Bencher) { From ea3a4e714e0ab0e8782c544ad51a3ef28706fb92 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 25 Oct 2025 00:39:40 +0200 Subject: [PATCH 03/25] skip some Path prefix-component logic on platforms that don't have prefixes --- library/std/src/path.rs | 66 +++++++++++-------- library/std/src/sys/path/cygwin.rs | 1 + library/std/src/sys/path/sgx.rs | 1 + library/std/src/sys/path/uefi.rs | 1 + library/std/src/sys/path/unix.rs | 1 + .../std/src/sys/path/unsupported_backslash.rs | 1 + library/std/src/sys/path/windows.rs | 1 + 7 files changed, 46 insertions(+), 26 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 6e3b1e6e47d0e..6873942f2a741 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -79,7 +79,7 @@ use crate::ops::{self, Deref}; use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; -use crate::sys::path::{MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; +use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; use crate::{cmp, fmt, fs, io, sys}; //////////////////////////////////////////////////////////////////////////////// @@ -643,17 +643,26 @@ impl<'a> Components<'a> { // how long is the prefix, if any? #[inline] fn prefix_len(&self) -> usize { + if !HAS_PREFIXES { + return 0; + } self.prefix.as_ref().map(Prefix::len).unwrap_or(0) } #[inline] fn prefix_verbatim(&self) -> bool { + if !HAS_PREFIXES { + return false; + } self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false) } /// how much of the prefix is left from the point of view of iteration? #[inline] fn prefix_remaining(&self) -> usize { + if !HAS_PREFIXES { + return 0; + } if self.front == State::Prefix { self.prefix_len() } else { 0 } } @@ -707,7 +716,7 @@ impl<'a> Components<'a> { if self.has_physical_root { return true; } - if let Some(p) = self.prefix { + if HAS_PREFIXES && let Some(p) = self.prefix { if p.has_implicit_root() { return true; } @@ -732,7 +741,7 @@ impl<'a> Components<'a> { // corresponding path component unsafe fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option> { match comp { - b"." if self.prefix_verbatim() => Some(Component::CurDir), + b"." if HAS_PREFIXES && self.prefix_verbatim() => Some(Component::CurDir), b"." => None, // . components are normalized away, except at // the beginning of a path, which is treated // separately via `include_cur_dir` @@ -889,18 +898,16 @@ impl<'a> Iterator for Components<'a> { fn next(&mut self) -> Option> { while !self.finished() { match self.front { - State::Prefix if self.prefix_len() > 0 => { - self.front = State::StartDir; - debug_assert!(self.prefix_len() <= self.path.len()); - let raw = &self.path[..self.prefix_len()]; - self.path = &self.path[self.prefix_len()..]; - return Some(Component::Prefix(PrefixComponent { - raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) }, - parsed: self.prefix.unwrap(), - })); + // most likely case first + State::Body if !self.path.is_empty() => { + let (size, comp) = self.parse_next_component(); + self.path = &self.path[size..]; + if comp.is_some() { + return comp; + } } - State::Prefix => { - self.front = State::StartDir; + State::Body => { + self.front = State::Done; } State::StartDir => { self.front = State::Body; @@ -908,7 +915,7 @@ impl<'a> Iterator for Components<'a> { debug_assert!(!self.path.is_empty()); self.path = &self.path[1..]; return Some(Component::RootDir); - } else if let Some(p) = self.prefix { + } else if HAS_PREFIXES && let Some(p) = self.prefix { if p.has_implicit_root() && !p.is_verbatim() { return Some(Component::RootDir); } @@ -918,15 +925,19 @@ impl<'a> Iterator for Components<'a> { return Some(Component::CurDir); } } - State::Body if !self.path.is_empty() => { - let (size, comp) = self.parse_next_component(); - self.path = &self.path[size..]; - if comp.is_some() { - return comp; - } + _ if const { !HAS_PREFIXES } => unreachable!(), + State::Prefix if self.prefix_len() == 0 => { + self.front = State::StartDir; } - State::Body => { - self.front = State::Done; + State::Prefix => { + self.front = State::StartDir; + debug_assert!(self.prefix_len() <= self.path.len()); + let raw = &self.path[..self.prefix_len()]; + self.path = &self.path[self.prefix_len()..]; + return Some(Component::Prefix(PrefixComponent { + raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) }, + parsed: self.prefix.unwrap(), + })); } State::Done => unreachable!(), } @@ -951,11 +962,11 @@ impl<'a> DoubleEndedIterator for Components<'a> { self.back = State::StartDir; } State::StartDir => { - self.back = State::Prefix; + self.back = if HAS_PREFIXES { State::Prefix } else { State::Done }; if self.has_physical_root { self.path = &self.path[..self.path.len() - 1]; return Some(Component::RootDir); - } else if let Some(p) = self.prefix { + } else if HAS_PREFIXES && let Some(p) = self.prefix { if p.has_implicit_root() && !p.is_verbatim() { return Some(Component::RootDir); } @@ -964,6 +975,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { return Some(Component::CurDir); } } + _ if !HAS_PREFIXES => unreachable!(), State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; return Some(Component::Prefix(PrefixComponent { @@ -3116,7 +3128,9 @@ impl Path { path: self.as_u8_slice(), prefix, has_physical_root: has_physical_root(self.as_u8_slice(), prefix), - front: State::Prefix, + // use a platform-specific initial state to avoid one turn of + // the state-machine when the platform doesn't have a Prefix. + front: const { if HAS_PREFIXES { State::Prefix } else { State::StartDir } }, back: State::Body, } } diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs index da0982384b0e6..416877a7280d2 100644 --- a/library/std/src/sys/path/cygwin.rs +++ b/library/std/src/sys/path/cygwin.rs @@ -21,6 +21,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { pub use super::windows_prefix::parse_prefix; +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "/"; pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/path/sgx.rs b/library/std/src/sys/path/sgx.rs index 32c7752f605d9..dca61f3ea145d 100644 --- a/library/std/src/sys/path/sgx.rs +++ b/library/std/src/sys/path/sgx.rs @@ -17,6 +17,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = false; pub const MAIN_SEP_STR: &str = "/"; pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs index a3f4a3bfe1b67..6b8258685aa0f 100644 --- a/library/std/src/sys/path/uefi.rs +++ b/library/std/src/sys/path/uefi.rs @@ -21,6 +21,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs index 15530323a198d..611d250db4050 100644 --- a/library/std/src/sys/path/unix.rs +++ b/library/std/src/sys/path/unix.rs @@ -17,6 +17,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = false; pub const MAIN_SEP_STR: &str = "/"; pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/path/unsupported_backslash.rs b/library/std/src/sys/path/unsupported_backslash.rs index 30b06c132c98d..8ed1fdc36e23f 100644 --- a/library/std/src/sys/path/unsupported_backslash.rs +++ b/library/std/src/sys/path/unsupported_backslash.rs @@ -18,6 +18,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index f124e1e5a71c7..509b13b6ae812 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -9,6 +9,7 @@ mod tests; pub use super::windows_prefix::parse_prefix; +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; From d263ab36def3283211976b6f64815b22ae781dce Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 25 Oct 2025 13:59:23 +0200 Subject: [PATCH 04/25] replace u8 iterator with slice matching --- library/std/src/path.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 6873942f2a741..8c19f50e787a5 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -729,10 +729,10 @@ impl<'a> Components<'a> { if self.has_root() { return false; } - let mut iter = self.path[self.prefix_remaining()..].iter(); - match (iter.next(), iter.next()) { - (Some(&b'.'), None) => true, - (Some(&b'.'), Some(&b)) => self.is_sep_byte(b), + let slice = &self.path[self.prefix_remaining()..]; + match slice { + [b'.'] => true, + [b'.', b, ..] => self.is_sep_byte(*b), _ => false, } } From b247f67d64db520c206a9ba3b716f69bf237b02f Mon Sep 17 00:00:00 2001 From: Taj Pereira Date: Sat, 25 Oct 2025 06:11:13 +1030 Subject: [PATCH 05/25] Rename downcast_[ref|mut]_unchecked -> downcast_unchecked_[ref|mut] Undo rust-analyzer changes --- library/core/src/any.rs | 36 +++++++++---------- ...us-assoc-type-path-suggest-similar-item.rs | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 3ab95438c3ff3..3935dfe309c10 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -227,7 +227,7 @@ impl dyn Any { // SAFETY: just checked whether we are pointing to the correct type, and we can rely on // that check for memory safety because we have implemented Any for all types; no other // impls can exist as they would conflict with our impl. - unsafe { Some(self.downcast_ref_unchecked()) } + unsafe { Some(self.downcast_unchecked_ref()) } } else { None } @@ -263,7 +263,7 @@ impl dyn Any { // SAFETY: just checked whether we are pointing to the correct type, and we can rely on // that check for memory safety because we have implemented Any for all types; no other // impls can exist as they would conflict with our impl. - unsafe { Some(self.downcast_mut_unchecked()) } + unsafe { Some(self.downcast_unchecked_mut()) } } else { None } @@ -281,7 +281,7 @@ impl dyn Any { /// let x: Box = Box::new(1_usize); /// /// unsafe { - /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// assert_eq!(*x.downcast_unchecked_ref::(), 1); /// } /// ``` /// @@ -291,7 +291,7 @@ impl dyn Any { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> &T { + pub unsafe fn downcast_unchecked_ref(&self) -> &T { debug_assert!(self.is::()); // SAFETY: caller guarantees that T is the correct type unsafe { &*(self as *const dyn Any as *const T) } @@ -309,7 +309,7 @@ impl dyn Any { /// let mut x: Box = Box::new(1_usize); /// /// unsafe { - /// *x.downcast_mut_unchecked::() += 1; + /// *x.downcast_unchecked_mut::() += 1; /// } /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); @@ -321,7 +321,7 @@ impl dyn Any { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + pub unsafe fn downcast_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is::()); // SAFETY: caller guarantees that T is the correct type unsafe { &mut *(self as *mut dyn Any as *mut T) } @@ -417,7 +417,7 @@ impl dyn Any + Send { /// let x: Box = Box::new(1_usize); /// /// unsafe { - /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// assert_eq!(*x.downcast_unchecked_ref::(), 1); /// } /// ``` /// @@ -427,9 +427,9 @@ impl dyn Any + Send { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> &T { + pub unsafe fn downcast_unchecked_ref(&self) -> &T { // SAFETY: guaranteed by caller - unsafe { ::downcast_ref_unchecked::(self) } + unsafe { ::downcast_unchecked_ref::(self) } } /// Forwards to the method defined on the type `dyn Any`. @@ -444,7 +444,7 @@ impl dyn Any + Send { /// let mut x: Box = Box::new(1_usize); /// /// unsafe { - /// *x.downcast_mut_unchecked::() += 1; + /// *x.downcast_unchecked_mut::() += 1; /// } /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); @@ -456,9 +456,9 @@ impl dyn Any + Send { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + pub unsafe fn downcast_unchecked_mut(&mut self) -> &mut T { // SAFETY: guaranteed by caller - unsafe { ::downcast_mut_unchecked::(self) } + unsafe { ::downcast_unchecked_mut::(self) } } } @@ -551,7 +551,7 @@ impl dyn Any + Send + Sync { /// let x: Box = Box::new(1_usize); /// /// unsafe { - /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// assert_eq!(*x.downcast_unchecked_ref::(), 1); /// } /// ``` /// # Safety @@ -560,9 +560,9 @@ impl dyn Any + Send + Sync { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> &T { + pub unsafe fn downcast_unchecked_ref(&self) -> &T { // SAFETY: guaranteed by caller - unsafe { ::downcast_ref_unchecked::(self) } + unsafe { ::downcast_unchecked_ref::(self) } } /// Forwards to the method defined on the type `Any`. @@ -577,7 +577,7 @@ impl dyn Any + Send + Sync { /// let mut x: Box = Box::new(1_usize); /// /// unsafe { - /// *x.downcast_mut_unchecked::() += 1; + /// *x.downcast_unchecked_mut::() += 1; /// } /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); @@ -588,9 +588,9 @@ impl dyn Any + Send + Sync { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + pub unsafe fn downcast_unchecked_mut(&mut self) -> &mut T { // SAFETY: guaranteed by caller - unsafe { ::downcast_mut_unchecked::(self) } + unsafe { ::downcast_unchecked_mut::(self) } } } diff --git a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs index a9c2c20ef374a..45f9f6bc5191d 100644 --- a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs +++ b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs @@ -44,7 +44,7 @@ fn main() { //~^ ERROR ambiguous associated type [E0223] //~| HELP if there were a trait named `Example` with associated type `wrapping` - // this one ideally should suggest `downcast_mut_unchecked` + // this one ideally should suggest `downcast_unchecked_mut` ::downcast::mut_unchecked; //~^ ERROR ambiguous associated type [E0223] //~| HELP if there were a trait named `Example` with associated type `downcast` From 2e5d395f2bfdedfda6bddc4797fbd4c04711efde Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 3 May 2025 22:58:27 -0600 Subject: [PATCH 06/25] refactor ub_checks and contract_checks to share logic --- compiler/rustc_borrowck/src/type_check/mod.rs | 3 +-- compiler/rustc_codegen_cranelift/src/base.rs | 13 ++--------- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 8 ++----- .../src/check_consts/check.rs | 2 +- .../rustc_const_eval/src/interpret/machine.rs | 22 ++++++++----------- .../src/interpret/operator.rs | 3 +-- compiler/rustc_middle/src/mir/mod.rs | 4 +++- compiler/rustc_middle/src/mir/pretty.rs | 6 +++-- compiler/rustc_middle/src/mir/statement.rs | 5 ++--- compiler/rustc_middle/src/mir/syntax.rs | 15 +++++++++++++ compiler/rustc_middle/src/mir/traversal.rs | 4 ++-- .../src/move_paths/builder.rs | 2 +- .../rustc_mir_transform/src/cost_checker.rs | 3 ++- compiler/rustc_mir_transform/src/gvn.rs | 3 +-- .../rustc_mir_transform/src/instsimplify.rs | 5 ++++- .../src/known_panics_lint.rs | 3 +-- .../src/lower_intrinsics.rs | 9 ++++++-- .../rustc_mir_transform/src/promote_consts.rs | 3 +-- compiler/rustc_mir_transform/src/validate.rs | 2 +- compiler/rustc_public/src/mir/body.rs | 9 ++++++-- .../src/unstable/convert/stable/mir.rs | 7 ++++-- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- src/tools/miri/src/machine.rs | 9 ++------ 23 files changed, 75 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d1d0bff8fe06b..46f39ea8f2507 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1046,8 +1046,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(NullOp::ContractChecks, _) => {} - &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} + &Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => {} Rvalue::ShallowInitBox(_operand, ty) => { let trait_ref = diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 7d50548b40262..6a1217a6a49b5 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -841,17 +841,8 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: fields.iter(), ) .bytes(), - NullOp::UbChecks => { - let val = fx.tcx.sess.ub_checks(); - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - return; - } - NullOp::ContractChecks => { - let val = fx.tcx.sess.contract_checks(); + NullOp::RuntimeChecks(kind) => { + let val = kind.value(fx.tcx.sess); let val = CValue::by_val( fx.bcx.ins().iconst(types::I8, i64::from(val)), fx.layout_of(fx.tcx.types.bool), diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 640f7211dc994..9f7eb9bc51bb5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -618,12 +618,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .bytes(); bx.cx().const_usize(val) } - mir::NullOp::UbChecks => { - let val = bx.tcx().sess.ub_checks(); - bx.cx().const_bool(val) - } - mir::NullOp::ContractChecks => { - let val = bx.tcx().sess.contract_checks(); + mir::NullOp::RuntimeChecks(kind) => { + let val = kind.value(bx.tcx().sess); bx.cx().const_bool(val) } }; diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index ca173fe26c2f6..c0a9bd187c147 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -646,7 +646,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} Rvalue::NullaryOp( - NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, + NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _, ) => {} Rvalue::ShallowInitBox(_, _) => {} diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 1725635e0b479..27b1ca01514c4 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -298,11 +298,11 @@ pub trait Machine<'tcx>: Sized { interp_ok(()) } - /// Determines the result of a `NullaryOp::UbChecks` invocation. - fn ub_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>; - - /// Determines the result of a `NullaryOp::ContractChecks` invocation. - fn contract_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>; + /// Determines the result of a `NullaryOp::RuntimeChecks` invocation. + fn runtime_checks( + _ecx: &InterpCx<'tcx, Self>, + r: mir::RuntimeChecks, + ) -> InterpResult<'tcx, bool>; /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction. /// You can use this to detect long or endlessly running programs. @@ -681,14 +681,10 @@ pub macro compile_time_machine(<$tcx: lifetime>) { } #[inline(always)] - fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { - // We can't look at `tcx.sess` here as that can differ across crates, which can lead to - // unsound differences in evaluating the same constant at different instantiation sites. - interp_ok(true) - } - - #[inline(always)] - fn contract_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { + fn runtime_checks( + _ecx: &InterpCx<$tcx, Self>, + _r: mir::RuntimeChecks, + ) -> InterpResult<$tcx, bool> { // We can't look at `tcx.sess` here as that can differ across crates, which can lead to // unsound differences in evaluating the same constant at different instantiation sites. interp_ok(true) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 58b90abf01295..feba237692090 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -522,8 +522,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes(); ImmTy::from_uint(val, usize_layout()) } - UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx), - ContractChecks => ImmTy::from_bool(M::contract_checks(self)?, *self.tcx), + RuntimeChecks(r) => ImmTy::from_bool(M::runtime_checks(self, r)?, *self.tcx), }) } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index fab04df500a5c..802adceb063ea 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -649,7 +649,9 @@ impl<'tcx> Body<'tcx> { } match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)), + Rvalue::NullaryOp(NullOp::RuntimeChecks(kind), _) => { + Some((kind.value(tcx.sess) as u128, targets)) + } Rvalue::Use(Operand::Constant(constant)) => { let bits = eval_mono_const(constant)?; Some((bits, targets)) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 17d8eeee68bfd..a7941290de2e0 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1093,8 +1093,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { let t = with_no_trimmed_paths!(format!("{}", t)); match op { NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"), - NullOp::UbChecks => write!(fmt, "UbChecks()"), - NullOp::ContractChecks => write!(fmt, "ContractChecks()"), + NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"), + NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { + write!(fmt, "ContractChecks()") + } } } ThreadLocalRef(did) => ty::tls::with(|tcx| { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 3cbb4b70b062a..a1f5ffb0b2774 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -795,8 +795,7 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => tcx.types.usize, - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, + Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => tcx.types.bool, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), AggregateKind::Tuple => { @@ -864,7 +863,7 @@ impl<'tcx> NullOp<'tcx> { pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { NullOp::OffsetOf(_) => tcx.types.usize, - NullOp::UbChecks | NullOp::ContractChecks => tcx.types.bool, + NullOp::RuntimeChecks(_) => tcx.types.bool, } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 9d99239546ae2..865b91817b3c5 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1565,6 +1565,12 @@ pub enum AggregateKind<'tcx> { pub enum NullOp<'tcx> { /// Returns the offset of a field OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>), + /// Returns whether we should perform some checking at runtime. + RuntimeChecks(RuntimeChecks), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum RuntimeChecks { /// Returns whether we should perform some UB-checking at runtime. /// See the `ub_checks` intrinsic docs for details. UbChecks, @@ -1573,6 +1579,15 @@ pub enum NullOp<'tcx> { ContractChecks, } +impl RuntimeChecks { + pub fn value(self, sess: &rustc_session::Session) -> bool { + match self { + Self::UbChecks => sess.ub_checks(), + Self::ContractChecks => sess.contract_checks(), + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum UnOp { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 9308570d89d18..7f6c7376501fa 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -293,9 +293,9 @@ pub fn reverse_postorder<'a, 'tcx>( /// reachable. /// /// Such a traversal is mostly useful because it lets us skip lowering the `false` side -/// of `if ::CONST`, as well as [`NullOp::UbChecks`]. +/// of `if ::CONST`, as well as [`NullOp::RuntimeChecks`]. /// -/// [`NullOp::UbChecks`]: rustc_middle::mir::NullOp::UbChecks +/// [`NullOp::RuntimeChecks`]: rustc_middle::mir::NullOp::RuntimeChecks pub fn mono_reachable<'a, 'tcx>( body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index dd65f0699e97e..8801fa8d9fd32 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -452,7 +452,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) | Rvalue::NullaryOp( - NullOp::OffsetOf(..) | NullOp::UbChecks | NullOp::ContractChecks, + NullOp::OffsetOf(..) | NullOp::RuntimeChecks(_), _, ) => {} } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 00a8293966b04..1a9af0e22bbe2 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -75,7 +75,8 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) { match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, ..) + // FIXME: Should we do the same for `OverflowChecks`? + Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), ..) if !self .tcx .sess diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8eae80e235ccd..e19a88d519a45 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -675,8 +675,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { .tcx .offset_of_subfield(self.typing_env(), arg_layout, fields.iter()) .bytes(), - NullOp::UbChecks => return None, - NullOp::ContractChecks => return None, + NullOp::RuntimeChecks(_) => return None, }; ImmTy::from_uint(val, ty).into() } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 932744e4fa25c..51e18516534ad 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -169,7 +169,10 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { - let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue else { return }; + // FIXME: Should we do the same for overflow checks? + let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), _) = *rvalue else { + return; + }; let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 131e3943689b8..dab2267eea690 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -612,8 +612,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { .tcx .offset_of_subfield(self.typing_env, op_layout, fields.iter()) .bytes(), - NullOp::UbChecks => return None, - NullOp::ContractChecks => return None, + NullOp::RuntimeChecks(_) => return None, }; ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index ad7c52064a8ef..e6fa30a72b9b8 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -23,13 +23,18 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::unreachable => { terminator.kind = TerminatorKind::Unreachable; } - sym::ub_checks => { + sym::ub_checks | sym::contract_checks => { + let op = match intrinsic.name { + sym::ub_checks => RuntimeChecks::UbChecks, + sym::contract_checks => RuntimeChecks::ContractChecks, + _ => unreachable!(), + }; let target = target.unwrap(); block.statements.push(Statement::new( terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool), + Rvalue::NullaryOp(NullOp::RuntimeChecks(op), tcx.types.bool), ))), )); terminator.kind = TerminatorKind::Goto { target }; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 9204c221515c9..da5814c6b4cce 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -451,8 +451,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::NullaryOp(op, _) => match op { NullOp::OffsetOf(_) => {} - NullOp::UbChecks => {} - NullOp::ContractChecks => {} + NullOp::RuntimeChecks(_) => {} }, Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 5a9018a62c574..0e71e396c1441 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1478,7 +1478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) - | Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks, _) + | Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) | Rvalue::Discriminant(_) => {} Rvalue::WrapUnsafeBinder(op, ty) => { diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 1a939cbe8dba2..551f666023b0e 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -642,8 +642,7 @@ impl Rvalue { .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) } Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => Ok(Ty::usize_ty()), - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()), + Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => Ok(Ty::bool_ty()), Rvalue::Aggregate(ak, ops) => match *ak { AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), AggregateKind::Tuple => Ok(Ty::new_tuple( @@ -1024,6 +1023,12 @@ pub enum CastKind { pub enum NullOp { /// Returns the offset of a field. OffsetOf(Vec<(VariantIdx, FieldIdx)>), + /// Codegen conditions for runtime checks. + RuntimeChecks(RuntimeChecks), +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub enum RuntimeChecks { /// cfg!(ub_checks), but at codegen time UbChecks, /// cfg!(contract_checks), but at codegen time diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index f850bc5f89b8a..1de5a2b327799 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -322,12 +322,15 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { use rustc_middle::mir::NullOp::*; + use rustc_middle::mir::RuntimeChecks::*; match self { OffsetOf(indices) => crate::mir::NullOp::OffsetOf( indices.iter().map(|idx| idx.stable(tables, cx)).collect(), ), - UbChecks => crate::mir::NullOp::UbChecks, - ContractChecks => crate::mir::NullOp::ContractChecks, + RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op { + UbChecks => crate::mir::RuntimeChecks::UbChecks, + ContractChecks => crate::mir::RuntimeChecks::ContractChecks, + }), } } } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 90ea2616890a4..0cf1ad348953b 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -194,7 +194,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, _) + Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, cx.tcx); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fadbdf5cea999..393895fe1a467 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1329,13 +1329,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } #[inline(always)] - fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { - interp_ok(ecx.tcx.sess.ub_checks()) - } - - #[inline(always)] - fn contract_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { - interp_ok(ecx.tcx.sess.contract_checks()) + fn runtime_checks(ecx: &InterpCx<'tcx, Self>, r: mir::RuntimeChecks) -> InterpResult<'tcx, bool> { + interp_ok(r.value(&ecx.tcx.sess)) } #[inline(always)] From abd9fb44e08443a590ea91d37cff9783011fb323 Mon Sep 17 00:00:00 2001 From: hax0kartik Date: Sun, 26 Oct 2025 12:28:48 +0530 Subject: [PATCH 07/25] O_NOFOLLOW is not supported on VxWorks --- library/std/src/sys/fs/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 74354227d84a6..bc1052b6f8c55 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -122,7 +122,7 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { with_native_path(path, &|path| imp::set_perm(path, perm.clone())) } -#[cfg(unix)] +#[cfg(all(unix, not(target_os = "vxworks")))] pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> { use crate::fs::OpenOptions; @@ -139,7 +139,7 @@ pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io options.open(path)?.set_permissions(perm) } -#[cfg(not(unix))] +#[cfg(any(not(unix), target_os = "vxworks"))] pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> { crate::unimplemented!( "`set_permissions_nofollow` is currently only implemented on Unix platforms" From 5943d07fb34198b7eb7d70e9df060cfbc445270a Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 5 Nov 2025 10:19:49 -0800 Subject: [PATCH 08/25] Add Allocator proxy impls for Box, Rc, and Arc This adds to the existing proxy impl for &T. --- library/alloc/src/boxed.rs | 52 ++++++++++++++++++++++++++++++++++++++ library/alloc/src/rc.rs | 52 ++++++++++++++++++++++++++++++++++++++ library/alloc/src/sync.rs | 52 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 7ad1679b1c822..39b17514a699c 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2241,3 +2241,55 @@ impl Error for Box { Error::provide(&**self, request); } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl Allocator for Box { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a24ea6e526c4b..d25d7044e0001 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -4413,3 +4413,55 @@ impl Drop for UniqueRcUninit { } } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl Allocator for Rc { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 13b5cf23e72d8..6618d3f8ad980 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4780,3 +4780,55 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueArc { unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) }; } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl Allocator for Arc { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} From 12cde3091a5d258c2f3e140e47537818680cb58d Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 7 Nov 2025 08:27:23 +0800 Subject: [PATCH 09/25] Add note for identifier with attempted hygiene violation --- .../rustc_resolve/src/late/diagnostics.rs | 24 +++++++++++++++++++ .../macros/macro-hygiene-help-issue-148580.rs | 15 ++++++++++++ .../macro-hygiene-help-issue-148580.stderr | 19 +++++++++++++++ .../macros/macro-hygiene-scope-15167.stderr | 20 ++++++++++++++++ .../metavar-expressions/concat-hygiene.stderr | 5 ++++ .../proc-macro/gen-macro-rules-hygiene.stderr | 5 ++++ tests/ui/proc-macro/mixed-site-span.stderr | 5 ++++ tests/ui/proc-macro/weird-hygiene.stderr | 10 ++++++++ 8 files changed, 103 insertions(+) create mode 100644 tests/ui/macros/macro-hygiene-help-issue-148580.rs create mode 100644 tests/ui/macros/macro-hygiene-help-issue-148580.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1d00a6b81fabc..ad3493d93e80a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1125,6 +1125,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } } + + self.suggest_ident_hidden_by_hygiene(err, path, span); } else if err_code == E0412 { if let Some(correct) = Self::likely_rust_type(path) { err.span_suggestion( @@ -1138,6 +1140,28 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], span: Span) { + let [segment] = path else { return }; + + let ident = segment.ident; + let callsite_span = span.source_callsite(); + for rib in self.ribs[ValueNS].iter().rev() { + for (binding_ident, _) in &rib.bindings { + if binding_ident.name == ident.name + && !binding_ident.span.eq_ctxt(span) + && !binding_ident.span.from_expansion() + && binding_ident.span.lo() < callsite_span.lo() + { + err.span_help( + binding_ident.span, + "an identifier with the same name exists, but is not accessible due to macro hygiene", + ); + return; + } + } + } + } + /// Emit special messages for unresolved `Self` and `self`. fn suggest_self_ty( &self, diff --git a/tests/ui/macros/macro-hygiene-help-issue-148580.rs b/tests/ui/macros/macro-hygiene-help-issue-148580.rs new file mode 100644 index 0000000000000..8441290b17228 --- /dev/null +++ b/tests/ui/macros/macro-hygiene-help-issue-148580.rs @@ -0,0 +1,15 @@ +macro_rules! print_it { {} => { println!("{:?}", it); } } +//~^ ERROR cannot find value `it` in this scope + +fn main() { + { + let it = "hello"; + } + { + let it = "world"; + { + let it = (); + print_it!(); + } + } +} diff --git a/tests/ui/macros/macro-hygiene-help-issue-148580.stderr b/tests/ui/macros/macro-hygiene-help-issue-148580.stderr new file mode 100644 index 0000000000000..f6a4ae7dd1c66 --- /dev/null +++ b/tests/ui/macros/macro-hygiene-help-issue-148580.stderr @@ -0,0 +1,19 @@ +error[E0425]: cannot find value `it` in this scope + --> $DIR/macro-hygiene-help-issue-148580.rs:1:50 + | +LL | macro_rules! print_it { {} => { println!("{:?}", it); } } + | ^^ not found in this scope +... +LL | print_it!(); + | ----------- in this macro invocation + | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-help-issue-148580.rs:11:17 + | +LL | let it = (); + | ^^ + = note: this error originates in the macro `print_it` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/macros/macro-hygiene-scope-15167.stderr b/tests/ui/macros/macro-hygiene-scope-15167.stderr index 58112c52df159..332a58467cee1 100644 --- a/tests/ui/macros/macro-hygiene-scope-15167.stderr +++ b/tests/ui/macros/macro-hygiene-scope-15167.stderr @@ -7,6 +7,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:12:9 + | +LL | for n in 0..1 { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope @@ -18,6 +23,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:16:17 + | +LL | if let Some(n) = None { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope @@ -29,6 +39,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:21:24 + | +LL | } else if let Some(n) = None { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope @@ -40,6 +55,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:25:20 + | +LL | while let Some(n) = None { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/macros/metavar-expressions/concat-hygiene.stderr b/tests/ui/macros/metavar-expressions/concat-hygiene.stderr index f3150d385ee70..9520f5182f4a7 100644 --- a/tests/ui/macros/metavar-expressions/concat-hygiene.stderr +++ b/tests/ui/macros/metavar-expressions/concat-hygiene.stderr @@ -7,6 +7,11 @@ LL | ${concat($lhs, $rhs)} LL | let _another = join!(abc, def); | --------------- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/concat-hygiene.rs:11:9 + | +LL | let abcdef = 1; + | ^^^^^^ = note: this error originates in the macro `join` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr index e904b43aaae06..17171ad5c5cc5 100644 --- a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr +++ b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr @@ -18,6 +18,11 @@ LL | gen_macro_rules!(); LL | generated!(); | ------------ in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/gen-macro-rules-hygiene.rs:19:13 + | +LL | let local_use = 1; + | ^^^^^^^^^ = note: this error originates in the macro `generated` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `local_def` in this scope diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index 2d2d55fe148d5..4bb2508416aaa 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -594,6 +594,11 @@ error[E0425]: cannot find value `local_use` in this scope LL | proc_macro_rules!(); | ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def` | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/mixed-site-span.rs:21:13 + | +LL | let local_use = 1; + | ^^^^^^^^^ = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `local_def` in this scope diff --git a/tests/ui/proc-macro/weird-hygiene.stderr b/tests/ui/proc-macro/weird-hygiene.stderr index 0cfac3f89a045..aa3ef9556eb16 100644 --- a/tests/ui/proc-macro/weird-hygiene.stderr +++ b/tests/ui/proc-macro/weird-hygiene.stderr @@ -7,6 +7,11 @@ LL | Value = (stringify!($tokens + hidden_ident), 1).1 LL | other!(50); | ---------- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/weird-hygiene.rs:44:9 + | +LL | let hidden_ident = "Hello1"; + | ^^^^^^^^^^^^ = note: this error originates in the macro `inner` which comes from the expansion of the macro `other` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `hidden_ident` in this scope @@ -18,6 +23,11 @@ LL | hidden_ident LL | invoke_it!(25); | -------------- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/weird-hygiene.rs:44:9 + | +LL | let hidden_ident = "Hello1"; + | ^^^^^^^^^^^^ = note: this error originates in the macro `invoke_it` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors From 5ed01e95df9be3accd4d46a9b9c315f602299abd Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 6 Nov 2025 19:40:00 -0600 Subject: [PATCH 10/25] Switch hexagon targets to rust-lld lld is a great choice for a default linker. --- .../src/spec/targets/hexagon_unknown_linux_musl.rs | 1 + .../src/spec/targets/hexagon_unknown_none_elf.rs | 1 + .../src/platform-support/hexagon-unknown-linux-musl.md | 6 ++++++ .../rustc/src/platform-support/hexagon-unknown-none-elf.md | 7 +++++++ 4 files changed, 15 insertions(+) diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs index 17b371f05e530..82811cda00ce9 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.features = "-small-data,+hvx-length128b".into(); base.has_rpath = true; + base.linker = Some("rust-lld".into()); base.linker_flavor = LinkerFlavor::Unix(Cc::Yes); base.c_enum_min_bits = Some(8); diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs index 6379cd30c3559..55ec3697a15e9 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs @@ -27,6 +27,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), emit_debug_gdb_scripts: false, c_enum_min_bits: Some(8), + linker: Some("rust-lld".into()), ..Default::default() }, } diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md index be6e17883f4eb..d74dd843eb259 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md @@ -39,6 +39,12 @@ dynamically linked executables. # /opt/clang+llvm-18.1.0-cross-hexagon-unknown-linux-musl/x86_64-linux-gnu/bin/qemu-hexagon -L /opt/clang+llvm-18.1.0-cross-hexagon-unknown-linux-musl/x86_64-linux-gnu/target/hexagon-unknown-linux-musl/usr/ ./hello ``` +## Linking + +This target selects `rust-lld` by default. Another option to use is +[eld](https://github.com/qualcomm/eld), which is also provided with +the opensource hexagon toolchain and the Hexagon SDK. + ## Building the target Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md index b07b0bb08d60a..a906e895b7743 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md @@ -25,6 +25,13 @@ Functions marked `extern "C"` use the [Hexagon architecture calling convention]( This target generates PIC ELF binaries. +## Linking + +This target selects `rust-lld` by default. Another option to use is +[eld](https://github.com/qualcomm/eld), which is also provided with +[the opensource hexagon toolchain](https://github.com/quic/toolchain_for_hexagon) +and the Hexagon SDK. + ## Building the target You can build Rust with support for the target by adding it to the `target` From b827732898bc52912d2428c9d2d004a3a22378f7 Mon Sep 17 00:00:00 2001 From: Amy Kwan Date: Fri, 7 Nov 2025 04:36:12 +0000 Subject: [PATCH 11/25] Enable std locking functions on AIX This patch enables the std locking functions on AIX by including AIX on the list of supported targets for the locking functions. Excluding AIX from the std locking functions results to compilation errors such as: ("try_lock() not supported"). --- library/std/src/sys/fs/unix.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 129fccdbf4197..cadcfddb0f7f8 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1296,6 +1296,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn lock(&self) -> io::Result<()> { @@ -1321,6 +1322,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn lock(&self) -> io::Result<()> { @@ -1335,6 +1337,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1360,6 +1363,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1374,6 +1378,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1415,6 +1420,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1432,6 +1438,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1473,6 +1480,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1490,6 +1498,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn unlock(&self) -> io::Result<()> { @@ -1515,6 +1524,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn unlock(&self) -> io::Result<()> { From fc20a28776ae6cd9583031c970e1ad2b377ddd9e Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 28 Oct 2025 12:10:18 +0100 Subject: [PATCH 12/25] Modify contributor email entries in .mailmap Updated email addresses for several contributors in the mailmap. --- .mailmap | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.mailmap b/.mailmap index fc8e83d6493cd..de7001b774276 100644 --- a/.mailmap +++ b/.mailmap @@ -9,7 +9,7 @@ Aaron Todd Abhishek Chanda Abhishek Chanda Abhijeet Bhagat Abroskin Alexander -Adolfo Ochagavía +Adolfo Ochagavía Adrian Heine né Lang Adrien Tétar Ahmed Charles @@ -36,6 +36,7 @@ Amanda Stjerna Amanda Stjerna Amanieu d'Antras Amos Onn +Amos Wenger Ana-Maria Mihalache Anatoly Ikorsky Andre Bogus @@ -276,7 +277,8 @@ Irina Popa Ivan Ivaschenko ivan tkachenko J. J. Weber -Jack Huey +Jack Huey +Jack Huey <31162821+jackh726@users.noreply.github.com> Jacob Jacob Hoffman-Andrews Jacob Greenfield @@ -292,6 +294,8 @@ Jakub Adam Wieczorek Jakub Adam Wieczorek Jakub Adam Wieczorek Jakub Adam Wieczorek +Jakub Adam Wieczorek +Jakub Adam Wieczorek Jakub Beránek James [Undefined] James Deng @@ -303,6 +307,7 @@ Jamie Hill-Daniel Jana Dönszelmann Jana Dönszelmann Jana Dönszelmann +Jane Lusby Jan-Erik Rediger Jaro Fietz Jason Fager @@ -313,6 +318,7 @@ Jason Toffaletti Jason Toffaletti Jauhien Piatlicki Jauhien Piatlicki Jay True Jeremy Letang +Jeremy Soller Jeremy Sorensen Jeremy Stucki Jeremy Stucki @@ -336,6 +342,7 @@ John KÃ¥re Alsaker John KÃ¥re Alsaker John Talling John Van Enk +Jon Gjengset Jonas Tepe Jonathan Bailey Jonathan Chan Kwan Yin @@ -424,7 +431,7 @@ Malo Jaffré Manish Goregaokar Mara Bos Marcell Pardavi -Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> +Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Marcus Klaas de Vries Margaret Meyerhofer Marijn Schouten @@ -531,6 +538,7 @@ Oliver Scherer Oliver Scherer Oliver Scherer Oliver Scherer +Onur Özkan Onur Özkan Onur Özkan Ömer Sinan AÄŸacan @@ -591,6 +599,7 @@ Rusty Blitzerr RustyYato Ruud van Asseldonk Ruud van Asseldonk Ryan Leung +Ryan Levick Ryan Scheel Ryan Sullivant Ryan Wiedemann @@ -685,6 +694,8 @@ Weihang Lo Weihang Lo Wesley Wiser whitequark +Will Crichton +Will Crichton William Ting Wim Looman Wim Looman @@ -694,6 +705,8 @@ Xinye Tao Xuefeng Wu Xuefeng Wu Xuefeng Wu XuefengWu York Xiang +Yoshua Wuyts +Yoshua Wuyts <2467194+yoshuawuyts@users.noreply.github.com> Yotam Ofek Youngsoo Son Youngsuk Kim From fdced17e1fb1f1cf00486383d5a90f45987c66b6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Nov 2025 12:35:12 +0100 Subject: [PATCH 13/25] [bootstrap] Make `--open` option work with `doc src/tools/error_index_generator` --- src/bootstrap/src/core/build_steps/doc.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 6622aae069d5c..d6d6fc67ba5ae 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1228,9 +1228,12 @@ impl Step for ErrorIndex { t!(fs::create_dir_all(&out)); tool::ErrorIndex::command(builder, self.compilers) .arg("html") - .arg(out) + .arg(&out) .arg(&builder.version) .run(builder); + + let index = out.join("error-index.html"); + builder.maybe_open_in_browser::(index); } fn metadata(&self) -> Option { From bd23d55f298639de1f108507e6b0a6518fae4a84 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 6 Nov 2025 18:51:01 +0300 Subject: [PATCH 14/25] `invalid_atomic_ordering`: also lint `update` & `try_update` --- compiler/rustc_lint/src/types.rs | 13 +- compiler/rustc_span/src/symbol.rs | 2 + ...nt-invalid-atomic-ordering-fetch-update.rs | 49 ---- ...nvalid-atomic-ordering-fetch-update.stderr | 83 ------ .../lint-invalid-atomic-ordering-update.rs | 144 +++++++++++ ...lint-invalid-atomic-ordering-update.stderr | 243 ++++++++++++++++++ 6 files changed, 399 insertions(+), 135 deletions(-) delete mode 100644 tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs delete mode 100644 tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr create mode 100644 tests/ui/lint/lint-invalid-atomic-ordering-update.rs create mode 100644 tests/ui/lint/lint-invalid-atomic-ordering-update.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 4895e61069e52..f3e6db6f2d8e4 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1022,7 +1022,8 @@ declare_lint! { /// /// - Passing `Ordering::Release` or `Ordering::AcqRel` as the failure /// ordering for any of `AtomicType::compare_exchange`, - /// `AtomicType::compare_exchange_weak`, or `AtomicType::fetch_update`. + /// `AtomicType::compare_exchange_weak`, `AtomicType::update`, or + /// `AtomicType::try_update`. INVALID_ATOMIC_ORDERING, Deny, "usage of invalid atomic ordering in atomic operations and memory fences" @@ -1118,13 +1119,19 @@ impl InvalidAtomicOrdering { let Some((method, args)) = Self::inherent_atomic_method_call( cx, expr, - &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak], + &[ + sym::update, + sym::try_update, + sym::fetch_update, + sym::compare_exchange, + sym::compare_exchange_weak, + ], ) else { return; }; let fail_order_arg = match method { - sym::fetch_update => &args[1], + sym::update | sym::try_update | sym::fetch_update => &args[1], sym::compare_exchange | sym::compare_exchange_weak => &args[3], _ => return, }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 38718bad9e57e..b447239ea85b0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2273,6 +2273,7 @@ symbols! { try_from_fn, try_into, try_trait_v2, + try_update, tt, tuple, tuple_indexing, @@ -2390,6 +2391,7 @@ symbols! { unwrap, unwrap_binder, unwrap_or, + update, use_cloned, use_extern_macros, use_nested_groups, diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs b/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs deleted file mode 100644 index bdeacac4957b6..0000000000000 --- a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ only-x86_64 -use std::sync::atomic::{AtomicIsize, Ordering}; - -fn main() { - // `fetch_update` testing - let x = AtomicIsize::new(0); - - // Allowed ordering combos - let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1)); - - // AcqRel is always forbidden as a failure ordering - let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - - // Release is always forbidden as a failure ordering - let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - -} diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr b/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr deleted file mode 100644 index 33829d68fd5c7..0000000000000 --- a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr +++ /dev/null @@ -1,83 +0,0 @@ -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:26:47 - | -LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - = note: `#[deny(invalid_atomic_ordering)]` on by default - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:28:47 - | -LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:30:47 - | -LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:32:46 - | -LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:34:46 - | -LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:38:47 - | -LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:40:47 - | -LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:42:47 - | -LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:44:46 - | -LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:46:46 - | -LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: aborting due to 10 previous errors - diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-update.rs b/tests/ui/lint/lint-invalid-atomic-ordering-update.rs new file mode 100644 index 0000000000000..ac41e7cee0c25 --- /dev/null +++ b/tests/ui/lint/lint-invalid-atomic-ordering-update.rs @@ -0,0 +1,144 @@ +//@ only-x86_64 +#![feature(atomic_try_update)] + +use std::sync::atomic::{AtomicIsize, Ordering}; + +fn main() { + // `fetch_update` testing + let x = AtomicIsize::new(0); + + // Allowed ordering combos + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::Relaxed, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::Relaxed, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::Relaxed, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::Acquire, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::Acquire, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::Acquire, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::Release, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::Release, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::Release, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::AcqRel, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::AcqRel, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::AcqRel, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::SeqCst, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::SeqCst, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::SeqCst, Ordering::SeqCst, |old| old + 1); + + // AcqRel is always forbidden as a failure ordering + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Relaxed, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Acquire, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Release, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::AcqRel, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::SeqCst, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + // Release is always forbidden as a failure ordering + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Relaxed, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Acquire, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Release, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::AcqRel, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::SeqCst, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` +} diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-update.stderr b/tests/ui/lint/lint-invalid-atomic-ordering-update.stderr new file mode 100644 index 0000000000000..8c266bacf3144 --- /dev/null +++ b/tests/ui/lint/lint-invalid-atomic-ordering-update.stderr @@ -0,0 +1,243 @@ +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:73:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + = note: `#[deny(invalid_atomic_ordering)]` on by default + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:75:45 + | +LL | let _ = x.try_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:77:41 + | +LL | let _ = x.update(Ordering::Relaxed, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:80:47 + | +LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:82:45 + | +LL | let _ = x.try_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:84:41 + | +LL | let _ = x.update(Ordering::Acquire, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:87:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:89:45 + | +LL | let _ = x.try_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:91:41 + | +LL | let _ = x.update(Ordering::Release, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:94:46 + | +LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:96:44 + | +LL | let _ = x.try_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:98:40 + | +LL | let _ = x.update(Ordering::AcqRel, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:101:46 + | +LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:103:44 + | +LL | let _ = x.try_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:105:40 + | +LL | let _ = x.update(Ordering::SeqCst, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:110:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:112:45 + | +LL | let _ = x.try_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:114:41 + | +LL | let _ = x.update(Ordering::Relaxed, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:117:47 + | +LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:119:45 + | +LL | let _ = x.try_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:121:41 + | +LL | let _ = x.update(Ordering::Acquire, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:124:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:126:45 + | +LL | let _ = x.try_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:128:41 + | +LL | let _ = x.update(Ordering::Release, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:131:46 + | +LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:133:44 + | +LL | let _ = x.try_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:135:40 + | +LL | let _ = x.update(Ordering::AcqRel, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:138:46 + | +LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:140:44 + | +LL | let _ = x.try_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:142:40 + | +LL | let _ = x.update(Ordering::SeqCst, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: aborting due to 30 previous errors + From c07f11ac0aa0651dde845fe3b72393867e0527aa Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 7 Nov 2025 14:38:16 +0100 Subject: [PATCH 15/25] don't completely reset `HeadUsages` --- compiler/rustc_type_ir/src/search_graph/mod.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 4f3f140af67d1..8e6376b22ce61 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -23,7 +23,7 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir::data_structures::HashMap; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; mod stack; use stack::{Stack, StackDepth, StackEntry}; @@ -916,6 +916,7 @@ impl, X: Cx> SearchGraph { /// heads from the stack. This may not necessarily mean that we've actually /// reached a fixpoint for that cycle head, which impacts the way we rebase /// provisional cache entries. +#[derive_where(Debug; X: Cx)] enum RebaseReason { NoCycleUsages, Ambiguity(X::AmbiguityInfo), @@ -950,6 +951,7 @@ impl, X: Cx> SearchGraph { /// cache entries to also be ambiguous. This causes some undesirable ambiguity for nested /// goals whose result doesn't actually depend on this cycle head, but that's acceptable /// to me. + #[instrument(level = "trace", skip(self, cx))] fn rebase_provisional_cache_entries( &mut self, cx: X, @@ -969,6 +971,7 @@ impl, X: Cx> SearchGraph { let popped_head = if heads.highest_cycle_head_index() == popped_head_index { heads.remove_highest_cycle_head() } else { + debug_assert!(heads.highest_cycle_head_index() < popped_head_index); return true; }; @@ -1057,6 +1060,8 @@ impl, X: Cx> SearchGraph { new_highest_head_index, )); + trace!(?input, ?entry, "rebased provisional cache entry"); + true }); !entries.is_empty() @@ -1379,7 +1384,8 @@ impl, X: Cx> SearchGraph { } // Clear all provisional cache entries which depend on a previous provisional - // result of this goal and rerun. + // result of this goal and rerun. This does not remove goals which accessed this + // goal without depending on its result. self.clear_dependent_provisional_results_for_rerun(); debug!(?result, "fixpoint changed provisional results"); @@ -1399,7 +1405,12 @@ impl, X: Cx> SearchGraph { // similar to the previous iterations when reevaluating, it's better // for caching if the reevaluation also starts out with `false`. encountered_overflow: false, - usages: None, + // We keep provisional cache entries around if they used this goal + // without depending on its result. + // + // We still need to drop or rebase these cache entries once we've + // finished evaluating this goal. + usages: Some(HeadUsages::default()), candidate_usages: None, }); } From 566a86b02fc81447d922a1bf0a40648466b73dc5 Mon Sep 17 00:00:00 2001 From: 21aslade Date: Mon, 20 Oct 2025 08:42:16 -0600 Subject: [PATCH 16/25] show packed alignment in mir_transform_unaligned_packed_ref --- .../rustc_const_eval/src/util/alignment.rs | 45 +++++++++------- compiler/rustc_const_eval/src/util/mod.rs | 2 +- compiler/rustc_mir_transform/messages.ftl | 7 ++- .../src/add_moves_for_packed_drops.rs | 2 +- .../src/check_packed_ref.rs | 10 +++- .../src/dead_store_elimination.rs | 4 +- compiler/rustc_mir_transform/src/errors.rs | 2 + compiler/rustc_mir_transform/src/validate.rs | 10 ++-- tests/ui/binding/issue-53114-safety-checks.rs | 12 ++--- .../binding/issue-53114-safety-checks.stderr | 24 ++++----- .../diagnostics/repr_packed.rs | 2 +- .../diagnostics/repr_packed.stderr | 4 +- .../lint/unaligned_references.current.stderr | 52 +++++++++---------- .../ui/lint/unaligned_references.next.stderr | 52 +++++++++---------- tests/ui/lint/unaligned_references.rs | 26 +++++----- .../unaligned_references_external_macro.rs | 2 +- ...unaligned_references_external_macro.stderr | 4 +- tests/ui/packed/issue-27060.rs | 8 +-- tests/ui/packed/issue-27060.stderr | 16 +++--- .../packed-struct-borrow-element-64bit.rs | 2 +- .../packed-struct-borrow-element-64bit.stderr | 4 +- .../ui/packed/packed-struct-borrow-element.rs | 4 +- .../packed-struct-borrow-element.stderr | 8 +-- .../ui/packed/packed-union-borrow-element.rs | 26 ++++++++++ .../packed/packed-union-borrow-element.stderr | 23 ++++++++ 25 files changed, 210 insertions(+), 141 deletions(-) create mode 100644 tests/ui/packed/packed-union-borrow-element.rs create mode 100644 tests/ui/packed/packed-union-borrow-element.stderr diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index 9aafc7efd8a6a..0fab4b288d18f 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -1,24 +1,24 @@ use rustc_abi::Align; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, TyCtxt}; use tracing::debug; -/// Returns `true` if this place is allowed to be less aligned -/// than its containing struct (because it is within a packed -/// struct). -pub fn is_disaligned<'tcx, L>( +/// If the place may be less aligned than its type requires +/// (because it is in a packed type), returns the AdtDef +/// and packed alignment of its most-unaligned projection. +pub fn place_unalignment<'tcx, L>( tcx: TyCtxt<'tcx>, local_decls: &L, typing_env: ty::TypingEnv<'tcx>, place: Place<'tcx>, -) -> bool +) -> Option<(AdtDef<'tcx>, Align)> where L: HasLocalDecls<'tcx>, { - debug!("is_disaligned({:?})", place); - let Some(pack) = is_within_packed(tcx, local_decls, place) else { - debug!("is_disaligned({:?}) - not within packed", place); - return false; + debug!("unalignment({:?})", place); + let Some((descr, pack)) = most_packed_projection(tcx, local_decls, place) else { + debug!("unalignment({:?}) - not within packed", place); + return None; }; let ty = place.ty(local_decls, tcx).ty; @@ -30,31 +30,34 @@ where || matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) => { // If the packed alignment is greater or equal to the field alignment, the type won't be - // further disaligned. + // further unaligned. // However we need to ensure the field is sized; for unsized fields, `layout.align` is // just an approximation -- except when the unsized tail is a slice, where the alignment // is fully determined by the type. debug!( - "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", + "unalignment({:?}) - align = {}, packed = {}; not unaligned", place, layout.align.bytes(), pack.bytes() ); - false + None } _ => { - // We cannot figure out the layout. Conservatively assume that this is disaligned. - debug!("is_disaligned({:?}) - true", place); - true + // We cannot figure out the layout. Conservatively assume that this is unaligned. + debug!("unalignment({:?}) - unaligned", place); + Some((descr, pack)) } } } -pub fn is_within_packed<'tcx, L>( +/// If the place includes a projection from a packed struct, +/// returns the AdtDef and packed alignment of the projection +/// with the lowest pack +pub fn most_packed_projection<'tcx, L>( tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>, -) -> Option +) -> Option<(AdtDef<'tcx>, Align)> where L: HasLocalDecls<'tcx>, { @@ -65,9 +68,11 @@ where .take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref)) // Consider the packed alignments at play here... .filter_map(|(base, _elem)| { - base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack) + let adt = base.ty(local_decls, tcx).ty.ty_adt_def()?; + let pack = adt.repr().pack?; + Some((adt, pack)) }) // ... and compute their minimum. // The overall smallest alignment is what matters. - .min() + .min_by_key(|(_, align)| *align) } diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 5be5ee8d1ae97..39992123882a9 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -6,7 +6,7 @@ mod check_validity_requirement; mod compare_types; mod type_name; -pub use self::alignment::{is_disaligned, is_within_packed}; +pub use self::alignment::{most_packed_projection, place_unalignment}; pub use self::check_validity_requirement::check_validity_requirement; pub(crate) use self::check_validity_requirement::validate_scalar_in_layout; pub use self::compare_types::{relate_types, sub_types}; diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 71ec2db1ef00c..cfc9b8edf7a28 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -69,8 +69,11 @@ mir_transform_tail_expr_local = {$is_generated_name -> *[false] `{$name}` calls a custom destructor } -mir_transform_unaligned_packed_ref = reference to packed field is unaligned - .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses +mir_transform_unaligned_packed_ref = reference to field of packed {$ty_descr} is unaligned + .note = this {$ty_descr} is {$align -> + [one] {""} + *[other] {"at most "} + }{$align}-byte aligned, but the type of this field may require higher alignment .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index 7ae2ebaf4ff09..9950a94d722eb 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -51,7 +51,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops { match terminator.kind { TerminatorKind::Drop { place, .. } - if util::is_disaligned(tcx, body, typing_env, place) => + if util::place_unalignment(tcx, body, typing_env, place).is_some() => { add_move_for_packed_drop( tcx, diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 100104e9de03e..9ce244a00fcec 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -37,7 +37,9 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place) + if context.is_borrow() + && let Some((adt, pack)) = + util::place_unalignment(self.tcx, self.body, self.typing_env, *place) { let def_id = self.body.source.instance.def_id(); if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id) @@ -48,7 +50,11 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { // shouldn't do. span_bug!(self.source_info.span, "builtin derive created an unaligned reference"); } else { - self.tcx.dcx().emit_err(errors::UnalignedPackedRef { span: self.source_info.span }); + self.tcx.dcx().emit_err(errors::UnalignedPackedRef { + span: self.source_info.span, + ty_descr: adt.descr(), + align: pack.bytes(), + }); } } } diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 732c3dcd44ab8..63ee69322eef0 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -23,7 +23,7 @@ use rustc_mir_dataflow::impls::{ }; use crate::simplify::UsedInStmtLocals; -use crate::util::is_within_packed; +use crate::util::most_packed_projection; /// Performs the optimization on the body /// @@ -65,7 +65,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { // the move may be codegened as a pointer to that field. // Using that disaligned pointer may trigger UB in the callee, // so do nothing. - && is_within_packed(tcx, body, place).is_none() + && most_packed_projection(tcx, body, place).is_none() { call_operands_to_move.push((bb, index)); } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index a039851681a67..517e4dd692625 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -99,6 +99,8 @@ pub(crate) enum ConstMutate { pub(crate) struct UnalignedPackedRef { #[primary_span] pub span: Span, + pub ty_descr: &'static str, + pub align: u64, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 5a9018a62c574..379af9c442b1d 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -20,7 +20,7 @@ use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::debuginfo::debuginfo_locals; use rustc_trait_selection::traits::ObligationCtxt; -use crate::util::{self, is_within_packed}; +use crate::util::{self, most_packed_projection}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { @@ -409,7 +409,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { // The call destination place and Operand::Move place used as an argument might // be passed by a reference to the callee. Consequently they cannot be packed. - if is_within_packed(self.tcx, &self.body.local_decls, destination).is_some() { + if most_packed_projection(self.tcx, &self.body.local_decls, destination) + .is_some() + { // This is bad! The callee will expect the memory to be aligned. self.fail( location, @@ -423,7 +425,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { for arg in args { if let Operand::Move(place) = &arg.node { - if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() { + if most_packed_projection(self.tcx, &self.body.local_decls, *place) + .is_some() + { // This is bad! The callee will expect the memory to be aligned. self.fail( location, diff --git a/tests/ui/binding/issue-53114-safety-checks.rs b/tests/ui/binding/issue-53114-safety-checks.rs index f4be2b482a7e6..07dfda77622a2 100644 --- a/tests/ui/binding/issue-53114-safety-checks.rs +++ b/tests/ui/binding/issue-53114-safety-checks.rs @@ -20,12 +20,12 @@ fn let_wild_gets_unsafe_field() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - let _ = &p.b; //~ ERROR reference to packed field + let _ = &p.b; //~ ERROR reference to field of packed struct let _ = u1.a; //~ ERROR [E0133] let _ = &u2.a; //~ ERROR [E0133] // variation on above with `_` in substructure - let (_,) = (&p.b,); //~ ERROR reference to packed field + let (_,) = (&p.b,); //~ ERROR reference to field of packed struct let (_,) = (u1.a,); //~ ERROR [E0133] let (_,) = (&u2.a,); //~ ERROR [E0133] } @@ -34,12 +34,12 @@ fn let_ascribe_gets_unsafe_field() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - let _: _ = &p.b; //~ ERROR reference to packed field + let _: _ = &p.b; //~ ERROR reference to field of packed struct let _: _ = u1.a; //~ ERROR [E0133] let _: _ = &u2.a; //~ ERROR [E0133] // variation on above with `_` in substructure - let (_,): _ = (&p.b,); //~ ERROR reference to packed field + let (_,): _ = (&p.b,); //~ ERROR reference to field of packed struct let (_,): _ = (u1.a,); //~ ERROR [E0133] let (_,): _ = (&u2.a,); //~ ERROR [E0133] } @@ -48,12 +48,12 @@ fn match_unsafe_field_to_wild() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - match &p.b { _ => { } } //~ ERROR reference to packed field + match &p.b { _ => { } } //~ ERROR reference to field of packed struct match u1.a { _ => { } } //~ ERROR [E0133] match &u2.a { _ => { } } //~ ERROR [E0133] // variation on above with `_` in substructure - match (&p.b,) { (_,) => { } } //~ ERROR reference to packed field + match (&p.b,) { (_,) => { } } //~ ERROR reference to field of packed struct match (u1.a,) { (_,) => { } } //~ ERROR [E0133] match (&u2.a,) { (_,) => { } } //~ ERROR [E0133] } diff --git a/tests/ui/binding/issue-53114-safety-checks.stderr b/tests/ui/binding/issue-53114-safety-checks.stderr index 9d909e915c21b..3e8389b77c53f 100644 --- a/tests/ui/binding/issue-53114-safety-checks.stderr +++ b/tests/ui/binding/issue-53114-safety-checks.stderr @@ -1,20 +1,20 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:23:13 | LL | let _ = &p.b; | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:28:17 | LL | let (_,) = (&p.b,); | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) @@ -50,23 +50,23 @@ LL | let (_,) = (&u2.a,); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:37:16 | LL | let _: _ = &p.b; | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:42:20 | LL | let (_,): _ = (&p.b,); | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) @@ -102,23 +102,23 @@ LL | let (_,): _ = (&u2.a,); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:51:11 | LL | match &p.b { _ => { } } | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:56:12 | LL | match (&p.b,) { (_,) => { } } | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs index fe5106c57af68..4395b70a922fb 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs @@ -19,7 +19,7 @@ fn test_missing_unsafe_warning_on_repr_packed() { let c = || { println!("{}", foo.x); - //~^ ERROR: reference to packed field is unaligned + //~^ ERROR: reference to field of packed struct is unaligned let _z = foo.x; }; diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr index c9972c8e7e349..0e93e033c022c 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr @@ -1,10 +1,10 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/repr_packed.rs:21:24 | LL | println!("{}", foo.x); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/unaligned_references.current.stderr b/tests/ui/lint/unaligned_references.current.stderr index 0f980c5301f37..39ca072e848cc 100644 --- a/tests/ui/lint/unaligned_references.current.stderr +++ b/tests/ui/lint/unaligned_references.current.stderr @@ -1,130 +1,130 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:32:13 | LL | &self.x; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:44:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:46:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:51:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:81:17 | LL | let _ = &good.ptr; | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:82:17 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:84:17 | LL | let _ = &good.data as *const _; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:85:27 | LL | let _: *const _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:87:17 | LL | let _ = good.data.clone(); | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:89:17 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:98:17 | LL | let _ = &packed2.x; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:137:20 | LL | let _ref = &m1.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:140:20 | LL | let _ref = &m2.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/lint/unaligned_references.next.stderr b/tests/ui/lint/unaligned_references.next.stderr index 0f980c5301f37..39ca072e848cc 100644 --- a/tests/ui/lint/unaligned_references.next.stderr +++ b/tests/ui/lint/unaligned_references.next.stderr @@ -1,130 +1,130 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:32:13 | LL | &self.x; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:44:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:46:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:51:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:81:17 | LL | let _ = &good.ptr; | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:82:17 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:84:17 | LL | let _ = &good.data as *const _; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:85:27 | LL | let _: *const _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:87:17 | LL | let _ = good.data.clone(); | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:89:17 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:98:17 | LL | let _ = &packed2.x; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:137:20 | LL | let _ref = &m1.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:140:20 | LL | let _ref = &m2.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/lint/unaligned_references.rs b/tests/ui/lint/unaligned_references.rs index 321e3ed135c47..af922a1031ab6 100644 --- a/tests/ui/lint/unaligned_references.rs +++ b/tests/ui/lint/unaligned_references.rs @@ -29,7 +29,7 @@ trait Foo { impl Foo for Packed2 { fn evil(&self) { unsafe { - &self.x; //~ ERROR reference to packed field + &self.x; //~ ERROR reference to field of packed struct } } } @@ -41,14 +41,14 @@ fn packed_dyn() { let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u64])); let foo: &Unaligned = &*local; - println!("{:?}", &*foo.0); //~ ERROR reference to packed field + println!("{:?}", &*foo.0); //~ ERROR reference to field of packed struct let foo: &Unaligned<[u64]> = &*local; - println!("{:?}", &*foo.0); //~ ERROR reference to packed field + println!("{:?}", &*foo.0); //~ ERROR reference to field of packed struct // Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.` let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u8])); let foo: &Unaligned = &*local; - println!("{:?}", &*foo.0); //~ ERROR reference to packed field + println!("{:?}", &*foo.0); //~ ERROR reference to field of packed struct // However, we *can* know the alignment when looking at a slice. let foo: &Unaligned<[u8]> = &*local; println!("{:?}", &*foo.0); // no error! @@ -78,15 +78,15 @@ fn main() { unsafe { let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] }; - let _ = &good.ptr; //~ ERROR reference to packed field - let _ = &good.data; //~ ERROR reference to packed field + let _ = &good.ptr; //~ ERROR reference to field of packed struct + let _ = &good.data; //~ ERROR reference to field of packed struct // Error even when turned into raw pointer immediately. - let _ = &good.data as *const _; //~ ERROR reference to packed field - let _: *const _ = &good.data; //~ ERROR reference to packed field + let _ = &good.data as *const _; //~ ERROR reference to field of packed struct + let _: *const _ = &good.data; //~ ERROR reference to field of packed struct // Error on method call. - let _ = good.data.clone(); //~ ERROR reference to packed field + let _ = good.data.clone(); //~ ERROR reference to field of packed struct // Error for nested fields. - let _ = &good.data2[0]; //~ ERROR reference to packed field + let _ = &good.data2[0]; //~ ERROR reference to field of packed struct let _ = &*good.ptr; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 @@ -95,7 +95,7 @@ fn main() { unsafe { let packed2 = Packed2 { x: 0, y: 0, z: 0 }; - let _ = &packed2.x; //~ ERROR reference to packed field + let _ = &packed2.x; //~ ERROR reference to field of packed struct let _ = &packed2.y; // ok, has align 2 in packed(2) struct let _ = &packed2.z; // ok, has align 1 packed2.evil(); @@ -134,9 +134,9 @@ fn main() { struct Misalign(u8, T); let m1 = Misalign(0, Wrapper { a: U16(10), b: HasDrop }); - let _ref = &m1.1.a; //~ ERROR reference to packed field + let _ref = &m1.1.a; //~ ERROR reference to field of packed struct let m2 = Misalign(0, Wrapper2 { a: U16(10), b: HasDrop }); - let _ref = &m2.1.a; //~ ERROR reference to packed field + let _ref = &m2.1.a; //~ ERROR reference to field of packed struct } } diff --git a/tests/ui/lint/unaligned_references_external_macro.rs b/tests/ui/lint/unaligned_references_external_macro.rs index 3a97e2112a144..2d6e493dd542f 100644 --- a/tests/ui/lint/unaligned_references_external_macro.rs +++ b/tests/ui/lint/unaligned_references_external_macro.rs @@ -2,7 +2,7 @@ extern crate unaligned_references_external_crate; -unaligned_references_external_crate::mac! { //~ERROR reference to packed field is unaligned +unaligned_references_external_crate::mac! { //~ERROR reference to field of packed struct is unaligned #[repr(packed)] pub struct X { pub field: u16 diff --git a/tests/ui/lint/unaligned_references_external_macro.stderr b/tests/ui/lint/unaligned_references_external_macro.stderr index 9945c78e8ba66..dd8788aec4b5c 100644 --- a/tests/ui/lint/unaligned_references_external_macro.stderr +++ b/tests/ui/lint/unaligned_references_external_macro.stderr @@ -1,4 +1,4 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references_external_macro.rs:5:1 | LL | / unaligned_references_external_crate::mac! { @@ -9,7 +9,7 @@ LL | | } LL | | } | |_^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) = note: this error originates in the macro `unaligned_references_external_crate::mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/packed/issue-27060.rs b/tests/ui/packed/issue-27060.rs index a0e944caa0b55..7d8be9603b686 100644 --- a/tests/ui/packed/issue-27060.rs +++ b/tests/ui/packed/issue-27060.rs @@ -12,11 +12,11 @@ fn main() { aligned: [0; 32] }; - let _ = &good.data; //~ ERROR reference to packed field - let _ = &good.data2[0]; //~ ERROR reference to packed field + let _ = &good.data; //~ ERROR reference to field of packed struct + let _ = &good.data2[0]; //~ ERROR reference to field of packed struct - let _ = &good.data; //~ ERROR reference to packed field - let _ = &good.data2[0]; //~ ERROR reference to packed field + let _ = &good.data; //~ ERROR reference to field of packed struct + let _ = &good.data2[0]; //~ ERROR reference to field of packed struct let _ = &*good.data; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 let _ = &good.aligned[2]; // ok, has align 1 diff --git a/tests/ui/packed/issue-27060.stderr b/tests/ui/packed/issue-27060.stderr index 4dc31a283865c..3ede68cf93625 100644 --- a/tests/ui/packed/issue-27060.stderr +++ b/tests/ui/packed/issue-27060.stderr @@ -1,40 +1,40 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:15:13 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:16:13 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:18:13 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:19:13 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/packed/packed-struct-borrow-element-64bit.rs b/tests/ui/packed/packed-struct-borrow-element-64bit.rs index 81eac07eaa894..59bd71c80e8c3 100644 --- a/tests/ui/packed/packed-struct-borrow-element-64bit.rs +++ b/tests/ui/packed/packed-struct-borrow-element-64bit.rs @@ -10,6 +10,6 @@ struct Foo4C { pub fn main() { let foo = Foo4C { bar: 1, baz: 2 }; - let brw = &foo.baz; //~ERROR reference to packed field is unaligned + let brw = &foo.baz; //~ERROR reference to field of packed struct is unaligned assert_eq!(*brw, 2); } diff --git a/tests/ui/packed/packed-struct-borrow-element-64bit.stderr b/tests/ui/packed/packed-struct-borrow-element-64bit.stderr index a464b18938784..dcf8e7a51f13d 100644 --- a/tests/ui/packed/packed-struct-borrow-element-64bit.stderr +++ b/tests/ui/packed/packed-struct-borrow-element-64bit.stderr @@ -1,10 +1,10 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/packed-struct-borrow-element-64bit.rs:13:15 | LL | let brw = &foo.baz; | ^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 4-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/packed/packed-struct-borrow-element.rs b/tests/ui/packed/packed-struct-borrow-element.rs index 24dadbcec7ca6..d639746e067bd 100644 --- a/tests/ui/packed/packed-struct-borrow-element.rs +++ b/tests/ui/packed/packed-struct-borrow-element.rs @@ -21,10 +21,10 @@ struct Foo4C { pub fn main() { let foo = Foo1 { bar: 1, baz: 2 }; - let brw = &foo.baz; //~ERROR reference to packed field is unaligned + let brw = &foo.baz; //~ERROR reference to field of packed struct is unaligned assert_eq!(*brw, 2); let foo = Foo2 { bar: 1, baz: 2 }; - let brw = &foo.baz; //~ERROR reference to packed field is unaligned + let brw = &foo.baz; //~ERROR reference to field of packed struct is unaligned assert_eq!(*brw, 2); } diff --git a/tests/ui/packed/packed-struct-borrow-element.stderr b/tests/ui/packed/packed-struct-borrow-element.stderr index c1f749d6fbbbd..ccdbb3aedc715 100644 --- a/tests/ui/packed/packed-struct-borrow-element.stderr +++ b/tests/ui/packed/packed-struct-borrow-element.stderr @@ -1,20 +1,20 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/packed-struct-borrow-element.rs:24:15 | LL | let brw = &foo.baz; | ^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/packed-struct-borrow-element.rs:28:15 | LL | let brw = &foo.baz; | ^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/packed/packed-union-borrow-element.rs b/tests/ui/packed/packed-union-borrow-element.rs new file mode 100644 index 0000000000000..e39d72b4a45c4 --- /dev/null +++ b/tests/ui/packed/packed-union-borrow-element.rs @@ -0,0 +1,26 @@ +#![allow(dead_code)] +//@ ignore-emscripten weird assertion? + +#[repr(packed)] +#[derive(Clone, Copy)] +struct Foo1(usize); + +#[repr(packed(4))] +#[derive(Clone, Copy)] +struct Foo4(usize); + +#[repr(packed(2))] +union Bar2 { + foo1: Foo1, + foo4: Foo4, +} + +pub fn main() { + let bar = Bar2 { foo1: Foo1(2) }; + let brw = unsafe { &bar.foo1.0 }; //~ERROR reference to field of packed struct is unaligned + assert_eq!(*brw, 2); + + let bar = Bar2 { foo4: Foo4(2) }; + let brw = unsafe { &bar.foo4.0 }; //~ERROR reference to field of packed union is unaligned + assert_eq!(*brw, 2); +} diff --git a/tests/ui/packed/packed-union-borrow-element.stderr b/tests/ui/packed/packed-union-borrow-element.stderr new file mode 100644 index 0000000000000..ace7620d97f72 --- /dev/null +++ b/tests/ui/packed/packed-union-borrow-element.stderr @@ -0,0 +1,23 @@ +error[E0793]: reference to field of packed struct is unaligned + --> $DIR/packed-union-borrow-element.rs:20:24 + | +LL | let brw = unsafe { &bar.foo1.0 }; + | ^^^^^^^^^^^ + | + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment + = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error[E0793]: reference to field of packed union is unaligned + --> $DIR/packed-union-borrow-element.rs:24:24 + | +LL | let brw = unsafe { &bar.foo4.0 }; + | ^^^^^^^^^^^ + | + = note: this union is at most 2-byte aligned, but the type of this field may require higher alignment + = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0793`. From eac0c5ac432a50f46a7ae7833a13dde0c962e5eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 7 Nov 2025 23:04:25 +0100 Subject: [PATCH 17/25] Remove eslint-js from npm dependencies --- package-lock.json | 32 ++++++++++++++++++++++---------- package.json | 4 +++- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0297bf70b63f..72129f115845e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,10 @@ "browser-ui-test": "^0.22.2", "es-check": "^6.2.1", "eslint": "^8.57.1", - "eslint-js": "github:eslint/js", "typescript": "^5.8.3" + }, + "devDependencies": { + "@types/node": "^24.10.0" } }, "node_modules/@babel/code-frame": { @@ -57,6 +59,12 @@ "node": ">= 10" } }, + "node_modules/@caporal/core/node_modules/@types/node": { + "version": "13.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.3.tgz", + "integrity": "sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA==", + "license": "MIT" + }, "node_modules/@colors/colors": { "version": "1.6.0", "license": "MIT", @@ -225,8 +233,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "13.9.3", - "license": "MIT" + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } }, "node_modules/@types/table": { "version": "5.0.0", @@ -944,13 +957,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-js": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/eslint/js.git#9e5b4fabf073b915abc56d6c14cc24177036d43e", - "workspaces": [ - "packages/*" - ] - }, "node_modules/eslint-scope": { "version": "7.2.2", "license": "BSD-2-Clause", @@ -2575,6 +2581,12 @@ "through": "^2.3.8" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, "node_modules/untildify": { "version": "3.0.3", "license": "MIT", diff --git a/package.json b/package.json index 04e0f6af19a0c..7420c53fd8cca 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "browser-ui-test": "^0.22.2", "es-check": "^6.2.1", "eslint": "^8.57.1", - "eslint-js": "github:eslint/js", "typescript": "^5.8.3" + }, + "devDependencies": { + "@types/node": "^24.10.0" } } From d1052e476b0106a262d05446f5c70bbdaa584552 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sat, 8 Nov 2025 04:51:33 +0100 Subject: [PATCH 18/25] Recover `[T: N]` as `[T; N]` --- compiler/rustc_parse/src/parser/ty.rs | 11 ++++----- tests/ui/parser/better-expected.stderr | 5 ++-- .../issues/error-pattern-issue-50571.stderr | 1 - tests/ui/parser/recover/array-type-no-semi.rs | 2 ++ .../parser/recover/array-type-no-semi.stderr | 23 ++++++++++++------- .../removed-syntax-fixed-vec.stderr | 3 +-- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 55a279f7ee0cc..ae2e71a78dd5b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -687,7 +687,6 @@ impl<'a> Parser<'a> { let mut err = self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr)); err.span_label(span, "expected `;` or `]`"); - err.note("you might have meant to write a slice or array type"); // If we cannot recover, return the error immediately. if !self.may_recover() { @@ -696,12 +695,10 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); - let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) { - // Consume common erroneous separators. - self.prev_token.span - } else { - self.token.span.shrink_to_lo() - }; + // Consume common erroneous separators. + let hi = self.prev_token.span.hi(); + _ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star)); + let suggestion_span = self.prev_token.span.with_lo(hi); // we first try to parse pattern like `[u8 5]` let length = match self.parse_expr_anon_const() { diff --git a/tests/ui/parser/better-expected.stderr b/tests/ui/parser/better-expected.stderr index 4646ce7eff0e0..6b64ec24da48d 100644 --- a/tests/ui/parser/better-expected.stderr +++ b/tests/ui/parser/better-expected.stderr @@ -4,11 +4,10 @@ error: expected `;` or `]`, found `3` LL | let x: [isize 3]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | -LL | let x: [isize ;3]; - | + +LL | let x: [isize; 3]; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.stderr b/tests/ui/parser/issues/error-pattern-issue-50571.stderr index 47457cff461ce..dac4b5309d23a 100644 --- a/tests/ui/parser/issues/error-pattern-issue-50571.stderr +++ b/tests/ui/parser/issues/error-pattern-issue-50571.stderr @@ -4,7 +4,6 @@ error: expected `;` or `]`, found `,` LL | fn foo([a, b]: [i32; 2]) {} | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - fn foo([a, b]: [i32; 2]) {} diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs index 2cc5d979604c7..499d5719d730a 100644 --- a/tests/ui/parser/recover/array-type-no-semi.rs +++ b/tests/ui/parser/recover/array-type-no-semi.rs @@ -14,4 +14,6 @@ fn main() { //~| ERROR attempt to use a non-constant value in a constant [E0435] let e: [i32 5]; //~^ ERROR expected `;` or `]`, found `5` + let f: [i32: 1 - 1]; + //~^ ERROR expected `;` or `]`, found `:` } diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr index 82330465144c8..45f39fefe5e34 100644 --- a/tests/ui/parser/recover/array-type-no-semi.stderr +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -4,7 +4,6 @@ error: expected `;` or `]`, found `,` LL | let b: [i32, 5]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - let b: [i32, 5]; @@ -19,8 +18,6 @@ LL | let a: [i32, ]; | | | while parsing the type for `a` | help: use `=` if you meant to assign - | - = note: you might have meant to write a slice or array type error: expected `;` or `]`, found `,` --> $DIR/array-type-no-semi.rs:12:16 @@ -28,7 +25,6 @@ error: expected `;` or `]`, found `,` LL | let c: [i32, x]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - let c: [i32, x]; @@ -41,11 +37,22 @@ error: expected `;` or `]`, found `5` LL | let e: [i32 5]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | -LL | let e: [i32 ;5]; - | + +LL | let e: [i32; 5]; + | + + +error: expected `;` or `]`, found `:` + --> $DIR/array-type-no-semi.rs:17:16 + | +LL | let f: [i32: 1 - 1]; + | ^ expected `;` or `]` + | +help: you might have meant to use `;` as the separator + | +LL - let f: [i32: 1 - 1]; +LL + let f: [i32; 1 - 1]; + | error[E0435]: attempt to use a non-constant value in a constant --> $DIR/array-type-no-semi.rs:12:18 @@ -65,7 +72,7 @@ error[E0423]: expected value, found builtin type `i32` LL | let a: [i32, ]; | ^^^ not a value -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0423, E0435. For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr index f584197c98e8d..3a5254d16b30c 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr @@ -4,11 +4,10 @@ error: expected `;` or `]`, found `*` LL | type v = [isize * 3]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - type v = [isize * 3]; -LL + type v = [isize ; 3]; +LL + type v = [isize; 3]; | warning: type `v` should have an upper camel case name From 67802e0494034e1c55205a178b2ee1843e6d39da Mon Sep 17 00:00:00 2001 From: MolecularPilot Date: Thu, 30 Oct 2025 17:36:11 +1100 Subject: [PATCH 19/25] rustc_builtin_macros: rename bench parameter to avoid collisions with user-defined function names --- compiler/rustc_builtin_macros/src/test.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 7a189ee1f4d05..b0155fad139b8 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -207,30 +207,30 @@ pub(crate) fn expand_test_or_bench( }; let test_fn = if is_bench { - // A simple ident for a lambda - let b = Ident::from_str_and_span("b", attr_sp); - + // avoid name collisions by using the function name within the identifier, see bug #148275 + let bencher_param = + Ident::from_str_and_span(&format!("__bench_{}", fn_.ident.name), attr_sp); cx.expr_call( sp, cx.expr_path(test_path("StaticBenchFn")), thin_vec![ // #[coverage(off)] - // |b| self::test::assert_test_result( + // |__bench_fn_name| self::test::assert_test_result( coverage_off(cx.lambda1( sp, cx.expr_call( sp, cx.expr_path(test_path("assert_test_result")), thin_vec![ - // super::$test_fn(b) + // super::$test_fn(__bench_fn_name) cx.expr_call( ret_ty_sp, cx.expr_path(cx.path(sp, vec![fn_.ident])), - thin_vec![cx.expr_ident(sp, b)], + thin_vec![cx.expr_ident(sp, bencher_param)], ), ], ), - b, + bencher_param, )), // ) ], ) From 474501b672a90799be55d268e74941b0d3379c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 7 Nov 2025 22:17:06 +0100 Subject: [PATCH 20/25] Remove a remnant of `dyn*` from the parser --- compiler/rustc_parse/src/parser/ty.rs | 44 ++++++++++++--------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 65347496599d7..f785e1d42f27c 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -82,25 +82,24 @@ enum AllowCVariadic { No, } -/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, -/// `IDENT<::AssocTy>`. +/// Determine if the given token can begin a bound assuming it follows Rust 2015 identifier `dyn`. /// -/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes -/// that `IDENT` is not the ident of a fn trait. -fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { - t == &token::PathSep || t == &token::Lt || t == &token::Shl -} +/// In Rust 2015, `dyn` is a contextual keyword, not a full one. +fn can_begin_dyn_bound_in_edition_2015(t: Token) -> bool { + if t.is_path_start() { + // In `dyn::x`, `dyn` and `dyn<::Y>`, `dyn` should (continue to) denote a regular path + // segment for backward compatibility. We make an exception for `dyn(X)` which used to be + // interpreted as a path with parenthesized generic arguments which can be semantically + // well-formed (consider: `use std::ops::Fn as dyn;`). Instead, we treat it as a trait + // object type whose first bound is parenthesized. + return t != token::PathSep && t != token::Lt && t != token::Shl; + } -fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { - // `!`, `const`, `[`, `async` are deliberately not part of this list to - // contain the number of potential regressions esp. in MBE code. - // `const` and `[` would regress UI test `macro-dyn-const-2015.rs`. - // `!` would regress `dyn!(...)` macro calls in Rust 2015. - t.is_path_start() - || t.is_lifetime() - || t == &TokenKind::Question - || t.is_keyword(kw::For) - || t == &TokenKind::OpenParen + // Contrary to `Parser::can_begin_bound`, `!`, `const`, `[` and `async` are deliberately not + // part of this list to contain the number of potential regressions esp. in MBE code. + // `const` and `[` would regress UI test `macro-dyn-const-2015.rs` and + // `!` would regress `dyn!(...)` macro calls in Rust 2015 for example. + t == token::OpenParen || t == token::Question || t.is_lifetime() || t.is_keyword(kw::For) } impl<'a> Parser<'a> { @@ -930,10 +929,7 @@ impl<'a> Parser<'a> { fn is_explicit_dyn_type(&mut self) -> bool { self.check_keyword(exp!(Dyn)) && (self.token_uninterpolated_span().at_least_rust_2018() - || self.look_ahead(1, |t| { - (can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::Star) - && !can_continue_type_after_non_fn_ident(t) - })) + || self.look_ahead(1, |&t| can_begin_dyn_bound_in_edition_2015(t))) } /// Parses a `dyn B0 + ... + Bn` type. @@ -942,13 +938,11 @@ impl<'a> Parser<'a> { fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { self.bump(); // `dyn` - // We used to parse `*` for `dyn*` here. - let syntax = TraitObjectSyntax::Dyn; - // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; - Ok(TyKind::TraitObject(bounds, syntax)) + + Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) } /// Parses a type starting with a path. From c52b7036c03f05ed62a68ae3a23ef249c129f053 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 8 Nov 2025 10:48:08 +0100 Subject: [PATCH 21/25] Remove unused argument `features` from `eval_config_entry` Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_parsing/src/attributes/cfg.rs | 7 +++---- compiler/rustc_builtin_macros/src/cfg.rs | 1 - compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_expand/src/config.rs | 3 +-- compiler/rustc_metadata/src/native_libs.rs | 2 +- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 47b46cd69d84c..631c2f1be4fd4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -199,14 +199,13 @@ pub fn eval_config_entry( sess: &Session, cfg_entry: &CfgEntry, id: NodeId, - features: Option<&Features>, emit_lints: ShouldEmit, ) -> EvalConfigResult { match cfg_entry { CfgEntry::All(subs, ..) => { let mut all = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features, emit_lints); + let res = eval_config_entry(sess, sub, id, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if !res.as_bool() { all.get_or_insert(res); @@ -217,7 +216,7 @@ pub fn eval_config_entry( CfgEntry::Any(subs, span) => { let mut any = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features, emit_lints); + let res = eval_config_entry(sess, sub, id, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if res.as_bool() { any.get_or_insert(res); @@ -229,7 +228,7 @@ pub fn eval_config_entry( }) } CfgEntry::Not(sub, span) => { - if eval_config_entry(sess, sub, id, features, emit_lints).as_bool() { + if eval_config_entry(sess, sub, id, emit_lints).as_bool() { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } else { EvalConfigResult::True diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 387399668111e..4737e2747e4ca 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -30,7 +30,6 @@ pub(crate) fn expand_cfg( cx.sess, &cfg, cx.current_expansion.lint_node_id, - Some(cx.ecfg.features), ShouldEmit::ErrorsAndLints, ) .as_bool(); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index fa730bae610cd..85788ba5e3b8c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3033,7 +3033,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool() + eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() } None => true, } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8278c29570b75..e93d9702774e1 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -322,7 +322,6 @@ impl<'a> StripUnconfigured<'a> { self.sess, &cfg_predicate, ast::CRATE_NODE_ID, - self.features, ShouldEmit::ErrorsAndLints, ) .as_bool() @@ -443,7 +442,7 @@ impl<'a> StripUnconfigured<'a> { return EvalConfigResult::True; }; - eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features, emit_errors) + eval_config_entry(self.sess, &cfg, self.lint_node_id, emit_errors) } /// If attributes are not allowed on expressions, emit an error for `attr` diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 2d2eedd2ba5a0..291f5c65dfa27 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -189,7 +189,7 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool() + eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() } None => true, } From 7298174cd5905e73b60900110b8cd5e015e45d4f Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sun, 7 Sep 2025 17:07:25 +0000 Subject: [PATCH 22/25] add parser check for multi-reference self --- compiler/rustc_ast/src/ast.rs | 9 ++ .../rustc_parse/src/parser/diagnostics.rs | 39 ++++++++- tests/ui/self/lot-of-references-self.rs | 28 ++++++ tests/ui/self/lot-of-references-self.stderr | 86 +++++++++++++++++++ 4 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 tests/ui/self/lot-of-references-self.rs create mode 100644 tests/ui/self/lot-of-references-self.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 802a6fa324984..422fcabe41b08 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -715,6 +715,15 @@ impl Pat { } } + /// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern. + pub fn peel_refs(&self) -> &Pat { + let mut current = self; + while let PatKind::Ref(inner, _) = ¤t.kind { + current = inner; + } + current + } + /// Is this a `..` pattern? pub fn is_rest(&self) -> bool { matches!(self.kind, PatKind::Rest) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a28af7833c387..300b543381dec 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2,13 +2,12 @@ use std::mem::take; use std::ops::{Deref, DerefMut}; use ast::token::IdentIsRaw; -use rustc_ast as ast; use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ - AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, - BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind, - Path, PathSegment, QSelf, Recovered, Ty, TyKind, + self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, + Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, + PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -2290,6 +2289,38 @@ impl<'a> Parser<'a> { pat.span.shrink_to_hi(), pat.span.shrink_to_lo(), ), + PatKind::Ref(ref inner_pat, _) + // Fix suggestions for multi-reference `self` parameters (e.g. `&&&self`) + // cc: https://github.com/rust-lang/rust/pull/146305 + if let PatKind::Ref(_, _) = &inner_pat.kind + && let PatKind::Path(_, path) = &pat.peel_refs().kind + && let [a, ..] = path.segments.as_slice() + && a.ident.name == kw::SelfLower => + { + let mut inner = inner_pat; + let mut span_vec = vec![pat.span]; + + while let PatKind::Ref(ref inner_type, _) = inner.kind { + inner = inner_type; + span_vec.push(inner.span.shrink_to_lo()); + } + + let span = match span_vec.len() { + // Should be unreachable: match guard ensures at least 2 references + 0 | 1 => unreachable!(), + 2 => span_vec[0].until(inner_pat.span.shrink_to_lo()), + _ => span_vec[0].until(span_vec[span_vec.len() - 2].shrink_to_lo()), + }; + + err.span_suggestion_verbose( + span, + "`self` should be `self`, `&self` or `&mut self`, consider removing extra references", + "".to_string(), + Applicability::MachineApplicable, + ); + + return None; + } // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind => diff --git a/tests/ui/self/lot-of-references-self.rs b/tests/ui/self/lot-of-references-self.rs new file mode 100644 index 0000000000000..8f3e1a30616b0 --- /dev/null +++ b/tests/ui/self/lot-of-references-self.rs @@ -0,0 +1,28 @@ +struct A ; + +impl A { + fn a(&&self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn b(&&&&&&self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn c(&self) {} + fn d(&mut &self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn e(&mut &&&self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn f(&mut &mut &mut self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn g(&mut & &mut self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn h(&mut & & & && & & self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references +} + +fn main() {} diff --git a/tests/ui/self/lot-of-references-self.stderr b/tests/ui/self/lot-of-references-self.stderr new file mode 100644 index 0000000000000..41a401eb13102 --- /dev/null +++ b/tests/ui/self/lot-of-references-self.stderr @@ -0,0 +1,86 @@ +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:4:16 + | +LL | fn a(&&self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn a(&&self) {} +LL + fn a(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:7:20 + | +LL | fn b(&&&&&&self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn b(&&&&&&self) {} +LL + fn b(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:11:20 + | +LL | fn d(&mut &self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn d(&mut &self) {} +LL + fn d(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:14:22 + | +LL | fn e(&mut &&&self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn e(&mut &&&self) {} +LL + fn e(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:17:29 + | +LL | fn f(&mut &mut &mut self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn f(&mut &mut &mut self) {} +LL + fn f(&mut self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:20:26 + | +LL | fn g(&mut & &mut self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn g(&mut & &mut self) {} +LL + fn g(&mut self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:23:39 + | +LL | fn h(&mut & & & && & & self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn h(&mut & & & && & & self) {} +LL + fn h(& self) {} + | + +error: aborting due to 7 previous errors + From cc8b95cc5490552e7080ec4e98c19249b47dac3a Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 3 Aug 2024 22:57:10 -0600 Subject: [PATCH 23/25] add `overflow_checks` intrinsic --- .../src/check_consts/check.rs | 5 +--- .../rustc_hir_analysis/src/check/intrinsic.rs | 3 +- compiler/rustc_middle/src/mir/pretty.rs | 3 ++ compiler/rustc_middle/src/mir/syntax.rs | 4 +++ .../src/move_paths/builder.rs | 5 +--- .../src/lower_intrinsics.rs | 3 +- compiler/rustc_public/src/mir/body.rs | 2 ++ .../src/unstable/convert/stable/mir.rs | 1 + library/core/src/intrinsics/mod.rs | 18 ++++++++++++ .../auxiliary/overflow_checks_add.rs | 10 +++++++ tests/codegen-llvm/overflow-checks.rs | 29 +++++++++++++++++++ tests/ui/consts/const-eval/overflow_checks.rs | 8 +++++ 12 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 tests/codegen-llvm/auxiliary/overflow_checks_add.rs create mode 100644 tests/codegen-llvm/overflow-checks.rs create mode 100644 tests/ui/consts/const-eval/overflow_checks.rs diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index c0a9bd187c147..f515f5d751bc6 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -645,10 +645,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp( - NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), - _, - ) => {} + Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(op, operand) => { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index a6659912e3fb9..39c26f4ea40dc 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -163,6 +163,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::minnumf128 | sym::mul_with_overflow | sym::needs_drop + | sym::overflow_checks | sym::powf16 | sym::powf32 | sym::powf64 @@ -643,7 +644,7 @@ pub(crate) fn check_intrinsic_type( sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), - sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), + sym::ub_checks | sym::overflow_checks => (0, 0, Vec::new(), tcx.types.bool), sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))), diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a7941290de2e0..f881ff1067d96 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1097,6 +1097,9 @@ impl<'tcx> Debug for Rvalue<'tcx> { NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { write!(fmt, "ContractChecks()") } + NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => { + write!(fmt, "OverflowChecks()") + } } } ThreadLocalRef(did) => ty::tls::with(|tcx| { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 865b91817b3c5..3b48a68df1262 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1577,6 +1577,9 @@ pub enum RuntimeChecks { /// Returns whether we should perform contract-checking at runtime. /// See the `contract_checks` intrinsic docs for details. ContractChecks, + /// Returns whether we should perform some overflow-checking at runtime. + /// See the `overflow_checks` intrinsic docs for details. + OverflowChecks, } impl RuntimeChecks { @@ -1584,6 +1587,7 @@ impl RuntimeChecks { match self { Self::UbChecks => sess.ub_checks(), Self::ContractChecks => sess.contract_checks(), + Self::OverflowChecks => sess.overflow_checks(), } } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 8801fa8d9fd32..b4ffeb782b596 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -451,10 +451,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { Rvalue::Ref(..) | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) - | Rvalue::NullaryOp( - NullOp::OffsetOf(..) | NullOp::RuntimeChecks(_), - _, - ) => {} + | Rvalue::NullaryOp(NullOp::OffsetOf(..) | NullOp::RuntimeChecks(_), _) => {} } } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index e6fa30a72b9b8..1e874300e25ea 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -23,10 +23,11 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::unreachable => { terminator.kind = TerminatorKind::Unreachable; } - sym::ub_checks | sym::contract_checks => { + sym::ub_checks | sym::overflow_checks | sym::contract_checks => { let op = match intrinsic.name { sym::ub_checks => RuntimeChecks::UbChecks, sym::contract_checks => RuntimeChecks::ContractChecks, + sym::overflow_checks => RuntimeChecks::OverflowChecks, _ => unreachable!(), }; let target = target.unwrap(); diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 551f666023b0e..5f41b1063280e 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -1033,6 +1033,8 @@ pub enum RuntimeChecks { UbChecks, /// cfg!(contract_checks), but at codegen time ContractChecks, + /// cfg!(overflow_checks), but at codegen time + OverflowChecks, } impl Operand { diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 1de5a2b327799..d5896474d0093 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -330,6 +330,7 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op { UbChecks => crate::mir::RuntimeChecks::UbChecks, ContractChecks => crate::mir::RuntimeChecks::ContractChecks, + OverflowChecks => crate::mir::RuntimeChecks::OverflowChecks, }), } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c397e762d5589..41afb3694b912 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2585,6 +2585,24 @@ pub const fn ub_checks() -> bool { cfg!(ub_checks) } +/// Returns whether we should perform some overflow-checking at runtime. This eventually evaluates to +/// `cfg!(overflow_checks)`, but behaves different from `cfg!` when mixing crates built with different +/// flags: if the crate has overflow checks enabled or carries the `#[rustc_inherit_overflow_checks]` +/// attribute, evaluation is delayed until monomorphization (or until the call gets inlined into +/// a crate that does not delay evaluation further); otherwise it can happen any time. +/// +/// The common case here is a user program built with overflow_checks linked against the distributed +/// sysroot which is built without overflow_checks but with `#[rustc_inherit_overflow_checks]`. +/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with +/// `#[inline]`), gating assertions on `overflow_checks()` rather than `cfg!(overflow_checks)` means that +/// assertions are enabled whenever the *user crate* has overflow checks enabled. However if the +/// user has overflow checks disabled, the checks will still get optimized out. +#[inline(always)] +#[rustc_intrinsic] +pub const fn overflow_checks() -> bool { + cfg!(debug_assertions) +} + /// Allocates a block of memory at compile time. /// At runtime, just returns a null pointer. /// diff --git a/tests/codegen-llvm/auxiliary/overflow_checks_add.rs b/tests/codegen-llvm/auxiliary/overflow_checks_add.rs new file mode 100644 index 0000000000000..ea9db1e9837e1 --- /dev/null +++ b/tests/codegen-llvm/auxiliary/overflow_checks_add.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -Cdebug-assertions=yes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +/// Emulates the default behavior of `+` using `intrinsics::overflow_checks()`. +#[inline] +pub fn add(a: u8, b: u8) -> u8 { + if core::intrinsics::overflow_checks() { a.strict_add(b) } else { a.wrapping_add(b) } +} diff --git a/tests/codegen-llvm/overflow-checks.rs b/tests/codegen-llvm/overflow-checks.rs new file mode 100644 index 0000000000000..c8b10df507b0f --- /dev/null +++ b/tests/codegen-llvm/overflow-checks.rs @@ -0,0 +1,29 @@ +// With -Coverflow-checks=yes (enabled by default by -Cdebug-assertions=yes) we will produce a +// runtime check that panics when an operation would result in integer overflow. +// +// This test ensures that such a runtime check is *not* emitted when debug-assertions are enabled, +// but overflow-checks are explicitly disabled. It also ensures that even if a dependency is +// compiled with overflow checks, `intrinsics::overflow_checks()` will be treated with the +// overflow-checks setting of the current crate (when `#[rustc_inherit_overflow_checks]`) is used. + +//@ aux-build:overflow_checks_add.rs +//@ revisions: DEBUG NOCHECKS +//@ compile-flags: -O -Cdebug-assertions=yes +//@ [NOCHECKS] compile-flags: -Coverflow-checks=no + +#![crate_type = "lib"] + +extern crate overflow_checks_add; + +// CHECK-LABEL: @add( +#[no_mangle] +pub unsafe fn add(a: u8, b: u8) -> u8 { + // CHECK: i8 noundef %a, i8 noundef %b + // CHECK: add i8 %b, %a + // DEBUG: icmp ult i8 [[zero:[^,]+]], %a + // DEBUG: call core::num::overflow_panic::add + // DEBUG: unreachable + // NOCHECKS-NOT: unreachable + // NOCHECKS: ret i8 %0 + overflow_checks_add::add(a, b) +} diff --git a/tests/ui/consts/const-eval/overflow_checks.rs b/tests/ui/consts/const-eval/overflow_checks.rs new file mode 100644 index 0000000000000..7f69157779906 --- /dev/null +++ b/tests/ui/consts/const-eval/overflow_checks.rs @@ -0,0 +1,8 @@ +//@ build-pass +//@ compile-flags: -O -C overflow-checks=no + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// Always returns true during CTFE, even if overflow checks are disabled. +const _: () = assert!(core::intrinsics::overflow_checks()); From 0d64a5f467e54b67d35d1ddc97ba05615ac922fa Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 8 Nov 2025 21:02:21 +0100 Subject: [PATCH 24/25] Use the current lint note id when parsing `cfg!()` Signed-off-by: Jonathan Brouwer --- compiler/rustc_builtin_macros/src/cfg.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 387399668111e..653bf9fe33b2c 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -3,7 +3,7 @@ //! current compilation environment. use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrStyle, CRATE_NODE_ID, token}; +use rustc_ast::{AttrStyle, token}; use rustc_attr_parsing as attr; use rustc_attr_parsing::parser::MetaItemOrLitParser; use rustc_attr_parsing::{ @@ -57,7 +57,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result Date: Fri, 31 Oct 2025 23:00:02 +0700 Subject: [PATCH 25/25] constify result unwrap unchecked --- library/core/src/result.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 6fee7febde38d..9afa71ec0f117 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1646,11 +1646,16 @@ impl Result { #[inline] #[track_caller] #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] - pub unsafe fn unwrap_unchecked(self) -> T { + #[rustc_const_unstable(feature = "const_result_unwrap_unchecked", issue = "148714")] + pub const unsafe fn unwrap_unchecked(self) -> T { match self { Ok(t) => t, - // SAFETY: the safety contract must be upheld by the caller. - Err(_) => unsafe { hint::unreachable_unchecked() }, + Err(e) => { + // FIXME(const-hack): to avoid E: const Destruct bound + super::mem::forget(e); + // SAFETY: the safety contract must be upheld by the caller. + unsafe { hint::unreachable_unchecked() } + } } }